Reading and writing · 06 of 10

The first byte

Four wires and a sketch that counts how many times your board has started. It reads one byte at address 0, adds one, writes it back, and prints it. Unplug the board, plug it in again, and the count carries on: the byte survived the power going off.

Four wires

Four wires
Your board
VCC to
3V3
SDA, SCL to
GPIO 21, GPIO 22
Address
0x50
GND to GND, VCC to 3V3, SDA to GPIO 21, SCL to GPIO 22: the ESP32's default I2C pins, so Wire.begin() needs nothing in its brackets. Not 5V: the pull-ups would then hold two of the ESP32's pins at 5 V.

GND to GND. VCC to your board's logic supply: 5V on an Uno, 3V3 on the others. SDA and SCL to your board's I2C pins: A4 and A5 on an Uno, GPIO 21 and 22 on an ESP32, GPIO 8 and 9 on an ESP32-S3, GP4 and GP5 on a Pico.

Those are each board's default I2C pins, so Wire.begin() needs nothing in its brackets. They are the same pins the SHT31 book uses, so two I2C blocks share the same four wires.

The sketch

readByte sends 0x50, the two address bytes and a repeated start, then asks for one byte. writeByte sends 0x50, the two address bytes and the value, then waits 5 ms. Those are the two transactions from two wires and an address, in about ten lines each.

setup() reads byte 0, adds one and writes it back. A chip that has never been written usually reads 255, so the sketch treats 255 as zero.

What you should see

At 115200 the serial monitor prints:

Started 1 times. Unplug it, plug it back in.

Unplug the board, plug it back in, and it says 2, then 3. The number was on the TK31 while the power was off. If it says no answer at 0x50, the chip did not acknowledge: check the four wires, counting from the square pad.

The code

No library to install: Wire comes with every board. readByte and writeByte are the two transactions from the last chapter, written out. Change nothing but the wiring.

eeprom_boot_counter.ino
/*
  EEPROM Memory - boot counter                          TK31 / /p/tk31

  Wiring. Count from the square pad on the TinkerBlock board, parts
  up, header at the bottom:

    GND -> GND
    VCC -> your board's logic supply: 5V on an Uno, 3V3 on an
           ESP32 or ESP32-S3, 3V3(OUT) on a Pico. Never 5V beside
           a 3.3 V board: the pull-ups would put 5 V on its pins.
    SDA -> A4 on an Uno, GPIO 21 on an ESP32, GPIO 8 on an
           ESP32-S3, GP4 on a Raspberry Pi Pico
    SCL -> A5 on an Uno, GPIO 22 on an ESP32, GPIO 9 on an
           ESP32-S3, GP5 on a Raspberry Pi Pico

  Arduino IDE
    Tools > Board                 your board, e.g. Arduino Uno
    Tools > Port                  the one that appears when you plug in
    Tools > USB CDC On Boot       Enabled   (ESP32-S3 only)
    No library to install: Wire comes with every board.
*/

#include <Wire.h>

const int EEPROM_ADDR = 0x50;  // fixed: A0 to A2 are tied to GND
const uint16_t COUNT_AT = 0;   // the byte that holds the count

// Returns true if the chip acknowledged every byte.
bool writeByte(uint16_t at, uint8_t value) {
  Wire.beginTransmission(EEPROM_ADDR);
  Wire.write((uint8_t)(at >> 8));     // memory address, high byte
  Wire.write((uint8_t)(at & 0xFF));   // then the low byte
  Wire.write(value);
  bool ok = Wire.endTransmission() == 0;  // the stop starts the write
  delay(5);                           // up to 5 ms, answering nobody
  return ok;
}

int readByte(uint16_t at) {
  Wire.beginTransmission(EEPROM_ADDR);
  Wire.write((uint8_t)(at >> 8));
  Wire.write((uint8_t)(at & 0xFF));
  if (Wire.endTransmission(false) != 0) return -1;  // no answer
  Wire.requestFrom(EEPROM_ADDR, 1);   // repeated start, then read
  return Wire.available() ? Wire.read() : -1;
}

void setup() {
  Serial.begin(115200);
  delay(1000);                        // time for the monitor to open
  Wire.begin();                       // the board's default I2C pins

  int count = readByte(COUNT_AT);
  if (count < 0) {
    Serial.println("no answer at 0x50: check the four wires");
    return;
  }
  if (count == 255) count = 0;        // a byte never written
  count++;
  writeByte(COUNT_AT, count);

  Serial.print("Started ");
  Serial.print(count);
  Serial.println(" times. Unplug it, plug it back in.");
}

void loop() {
}

writeByte waits 5 ms after every write, because the chip answers nobody while it writes. This is not the Arduino EEPROM library: EEPROM.h would read the memory inside your microcontroller, not this chip.

When it does not work

The first run says 1, not 0.

That is right. An unwritten chip usually reads 255 at every address, and the sketch treats 255 as never started, so the first start counts as 1. After 255 starts the one byte is full and the count goes back to 1.

On an Uno the count goes up when I open the serial monitor.

Opening the serial monitor resets an Uno, and a reset is a start. The count is doing its job. Unplug the USB cable and plug it back in to see the power-off case.

It prints 'no answer at 0x50'.

The chip did not acknowledge. Count from the square pad: GND, VCC, SDA, SCL, and check SDA and SCL are not swapped. Then check VCC is on your board's logic supply and actually connected.

The serial monitor stays empty on my ESP32-S3.

Set Tools > USB CDC On Boot to Enabled and upload again. Without it the S3's USB port does not bring up a serial port at boot, so the sketch runs with nowhere to print.

Where this goes next

What the delay(5) is for, and a faster way to wait.

Five milliseconds a write

Edit this page — content/books/eeprom-memory/the-first-byte.mdx

Community

Questions about this product

See what other owners have asked, and read their solutions.

Ask a question ↗

EEPROM Memory

Loading discussions…

Discuss this article

Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.

Browse Modules and blocks on the forum