EEPROM memory/Reading and writing/07. Five milliseconds a write
Reading and writing · 07 of 10

Five milliseconds a write

After the stop, the chip spends up to 5 ms writing and answers nobody, not even its own address. A read in that time fails. delay(5) always works; asking the chip 'are you there?' until it says yes, called acknowledge polling, works too and never waits longer than it has to. This sketch shows both, and times the chip.

Three ways to wait

Five milliseconds a write
After the write, the sketch
Time
0.00 ms
Read goes out
4.00 ms
Read
waiting
The write goes out: address, two bytes of memory address, the value. About 0.38 ms at 100 kHz.

Press play for each. The write goes out on the wire in well under half a millisecond. Then the stop, and the chip goes quiet while it writes.

Reading straight away reaches a chip that is busy. It does not acknowledge its own address, so the read fails. The value was written; the sketch asked too soon, and the byte it prints is 255 or the old value.

delay(5) waits the datasheet's worst case every time. It always works, and for a setting saved now and then it is all you need. The last sketch used it.

Acknowledge polling asks "are you there?", an address with nothing after it, until the chip says yes. It is the datasheet's own method, and it never waits longer than the chip needs.

How long this chip takes

The datasheet gives only a maximum, 5 ms. The sketch measures yours. The serial monitor prints the failed read first:

asked straight away: endTransmission() = 2

then five lines of write 0 was done after … us, each a number of microseconds. It should be under 5000; how far under is the chip's own business and is not in the datasheet. The code on the first line depends on your board: an Uno says 2, which means "the address was not acknowledged". Whatever you see, write every sketch for 5 ms.

Why it matters most in a loop

Writing one setting, the 5 ms is invisible. Writing 16,384 bytes one at a time, it is 16,384 waits: about a minute and a half. Sixty-four-byte pages cuts that to under ten seconds by writing many bytes per wait.

The code

Writes five bytes and times each one by polling for the chip's acknowledge. Before that, it asks once straight after a write, to show what a sketch without a wait sees.

eeprom_write_timing.ino
/*
  EEPROM Memory - how long a write takes                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;

// Send a write, and return as soon as the stop has gone.
void sendByte(uint16_t at, uint8_t value) {
  Wire.beginTransmission(EEPROM_ADDR);
  Wire.write((uint8_t)(at >> 8));
  Wire.write((uint8_t)(at & 0xFF));
  Wire.write(value);
  Wire.endTransmission();
}

// Is the chip there? 0 from endTransmission means it acknowledged.
bool answers() {
  Wire.beginTransmission(EEPROM_ADDR);
  return Wire.endTransmission() == 0;
}

// Acknowledge polling: ask until it answers, at most 20 ms.
unsigned long waitReady() {
  unsigned long t0 = micros();
  while (!answers() && micros() - t0 < 20000) {
  }
  return micros() - t0;
}

void setup() {
  Serial.begin(115200);
  delay(1000);
  Wire.begin();

  sendByte(100, 42);
  Wire.beginTransmission(EEPROM_ADDR);
  Serial.print("asked straight away: endTransmission() = ");
  Serial.println(Wire.endTransmission());   // not 0: nobody answered
  waitReady();

  for (int i = 0; i < 5; i++) {
    sendByte(100 + i, i);
    unsigned long us = waitReady();
    Serial.print("write ");
    Serial.print(i);
    Serial.print(" was done after ");
    Serial.print(us);
    Serial.println(" us");
  }
}

void loop() {
}

waitReady() gives up after 20 ms, so a missing chip cannot hang the sketch. It is the wait every later sketch in this book uses in place of delay(5).

When it does not work

A value reads back as the old one, or as 255.

The read went out while the chip was still writing, so the address was not acknowledged. Wait after every write: delay(5), or the waitReady() loop in this sketch.

The first line says 0, not an error.

Some boards' Wire library waits or retries on its own before it gives up, and the chip had finished by then. The timing lines below it are still right; the point is that the sketch cannot count on that.

Why is my write faster than 5 ms?

5 ms is the datasheet's maximum, not its typical. The chip is allowed to finish sooner, and the datasheet does not say by how much, so one chip's time says nothing about the next. Never hard-code the time you measured.

Does the scan interfere with a write?

No, but a scan run straight after a write can miss the chip, because it does not answer while writing. Scan again a moment later and 0x50 is back.

Where this goes next

Writing more than one byte at a time, and the edge a write must never cross.

Sixty-four-byte pages

Edit this page — content/books/eeprom-memory/five-milliseconds-a-write.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