AT24C32 EEPROM Write Cycle Time

Hello there,

Anyone know the single byte write time for this EEPROM or similar?
This is at 5v, and the data sheet says 10ms max but i'm seeing more like 0.5ms but not sure if that is right or not yet. That includes the time to call the Wire library for I2c.

MrAl:
Hello there,

Anyone know the single byte write time for this EEPROM or similar?
This is at 5v, and the data sheet says 10ms max but i'm seeing more like 0.5ms but not sure if that is right or not yet. That includes the time to call the Wire library for I2c.

It is spec'd to happen within 10ms, The actual time is device, data dependent. Are you asking for a guaranteed exact write time? If so, there is no answer. The EEPROM is erased by injected electrons into a floating 'well'. The electron tunneling is not deterministic. It depends on the thickness of the insulating layer, the number of electrons currently inhabiting the 'well', the voltage generated by the chip's high voltage charge pump.

Each memory cell of the chip may be different. So, they only spec the worst case duration.

You do understand that this device has a 32 byte write page size? This means that any time you write to the device, 32 bytes are actually erased, written. And you have to take care when writing multiple bytes that all of the bytes you send fit on one 32 byte page?

This means that the chip is organized in multiple 32 byte pages:

page    address Range
0           0..31
1          32..63
2          64..95

If you use code like this to write a multibyte buffer to the EEPROM:

void writeBlock(uint8_t i2cAddress, uint16_t addr, char *ch, uint8_t len){
Wire.beginTransmission(i2cAddress);
Wire.write(highByte(addr));
Wire.write(lowByte(addr));
Wire.write(ch,len);
Wire.endTransmission();
}

It will not correctly store the data if (((addr+len)/32) != (addr/32)). This is because of the 32 byte write buffer.

The way I2C EEPROMS store data is something like this.

The Chip receives the Write command, it decodes the address, finding which of the 32Byte pages you will be changing.
Then it fills the page write buffer with the current contents of it's EEPROM page.
Then it starts overwriting the page write buffer with the data coming in the I2C buss. It has a 5bit index register (0..31) that indicates where in the buffer the next byte is to be stored. After each byte is received from the I2C buss, this index pointer is incremented. If it is incremented past 31, it starts over at 0. So, this mean that if your multibyte buffer is 10bytes long and you want it stored starting at address 25, your first 7 bytes are stored at addresses[25..31], and the remaining 3 bytes are stored at addresses [0..2].
After the I2C write instruction has completed, the Chip Erases the current page, then writes the data from the page write buffer into the newly erased memory cells.

So, if you are going to write multiple bytes in one I2C transaction, you must consider the page size of the EEPROM you are using. The write page size is device dependent. Some of the little 2k EEPROMs have as small as a 4byte page size, some of the larger ones have 256 byte buffers.

Chuck.

chucktodd:
It is spec'd to happen within 10ms, The actual time is device, data dependent. Are you asking for a guaranteed exact write time? If so, there is no answer. The EEPROM is erased by injected electrons into a floating 'well'. The electron tunneling is not deterministic. It depends on the thickness of the insulating layer, the number of electrons currently inhabiting the 'well', the voltage generated by the chip's high voltage charge pump.

Each memory cell of the chip may be different. So, they only spec the worst case duration.

You do understand that this device has a 32 byte write page size? This means that any time you write to the device, 32 bytes are actually erased, written. And you have to take care when writing multiple bytes that all of the bytes you send fit on one 32 byte page?

This means that the chip is organized in multiple 32 byte pages:

page    address Range

0          0..31
1          32..63
2          64..95




If you use code like this to write a multibyte buffer to the EEPROM:


void writeBlock(uint8_t i2cAddress, uint16_t addr, char *ch, uint8_t len){
Wire.beginTransmission(i2cAddress);
Wire.write(highByte(addr));
Wire.write(lowByte(addr));
Wire.write(ch,len);
Wire.endTransmission();
}




It will not correctly store the data if (((addr+len)/32) != (addr/32)). This is because of the 32 byte write buffer.

The way I2C EEPROMS store data is something like this.

The Chip receives the Write command, it decodes the address, finding which of the 32Byte pages you will be changing.
Then it fills the page write buffer with the current contents of it's EEPROM page.
Then it starts overwriting the page write buffer with the data coming in the I2C buss. It has a 5bit index register (0..31) that indicates where in the buffer the next byte is to be stored. After each byte is received from the I2C buss, this index pointer is incremented. If it is incremented past 31, it starts over at 0. So, this mean that if your multibyte buffer is 10bytes long and you want it stored starting at address 25, your first 7 bytes are stored at addresses[25..31], and the remaining 3 bytes are stored at addresses [0..2]. 
After the I2C write instruction has completed, the Chip Erases the current page, then writes the data from the page write buffer into the newly erased memory cells.

So, if you are going to write multiple bytes in one I2C transaction, you must consider the page size of the EEPROM you are using. The write page size is device dependent. Some of the little 2k EEPROMs have as small as a 4byte page size, some of the larger ones have 256 byte buffers. 

Chuck.

Hello there Chuck,

Thanks for the informative reply.

I suspected that the paging worked that way, but didnt know for sure.

I am actually using the Wire library as you noted, and only sending one byte at a time.
The question of timing came up because i was getting 432 microseconds for the write instruction to return after writing a single byte, and this seemed too fast.

So are you saying that some bytes may write as fast as 432us ?
Do you think it matters if the cycle age is much longer? That is, a EEPROM that had been written to many times over would take longer?

I am using "micros()" to time it, as in:

a=micros();
WriteByte(addr,value);
b=micros();
Serial.println(b-a);
it prints 432 every time.

MrAl:
Hello there Chuck,

Thanks for the informative reply.

I suspected that the paging worked that way, but didnt know for sure.

I am actually using the Wire library as you noted, and only sending one byte at a time.
The question of timing came up because i was getting 432 microseconds for the write instruction to return after writing a single byte, and this seemed too fast.

So are you saying that some bytes may write as fast as 432us ?
Do you think it matters if the cycle age is much longer? That is, a EEPROM that had been written to many times over would take longer?

I am using "micros()" to time it, as in:

a=micros();
WriteByte(addr,value);
b=micros();
Serial.println(b-a);
it prints 432 every time.

The simple Answer is Yes. as the part ages, both erasing and Writing take longer.

Lets assume that currently the EEPROM page is completely erased, 0xFF in each cell. And you want to write 0xA5 (B10100101) into one cell. The erase sequence could/may be skipped because the cells are already erased, and the write cycle only has to update one byte, and only 4 bits have to be changed(maximum optimization).

Now, say the EEPROM page has 0xA5(B10100101) in each cell and you are writing 0x5A(B01011010) into all 32 bytes. The erase sequence has to erase all 32 bytes and then reprogram all 32 bytes (no optimization possible).

None of the device manufactures actually describe the actual erase, write sequence. So, my conjecture on conditional erase, write optimization has no basis in fact. But, I choose to interpret their 'max time' as meaning that there are some optimizations(conditional) operations in the sequence.

Don't use your measured duration as a fixed constant.

If you have a time critical operation that is writing single bytes, try creating a buffered write instead.

But, understand the standard Wire.h library only uses a 32byte internal buffer. Don't try to send a bigger buffer. The Wire.endTransmission() will return a 'buffer too big' error.

Now, this will create a longer write sequence, but the 'erase,write' cycle would be less noticeable.

If you are worried about knowing if the last 'erase,write' cycle has completed use this code to see if your EEPROM has finished the prior command:

bool i2cReady(uint8_t i2cAddr){
Wire.beginTransaction(i2cAddr);
return !Wire.endTransaction();
}

It will return TRUE if the EEPROM has completed the prior command (write).

Chuck.

chucktodd:
The simple Answer is Yes. as the part ages, both erasing and Writing take longer.

I believe NO is the right answer. I don't have my computer here but I was doing similar thing some time ago. The OP's code measures time to SEND the command to the EEPROM, but not the time it takes to execute it. If you send second WriteByte command just after the first one you will get some unexpected behavior. (No byte will be written or the second command will take much longer waiting for the first write to finish or some corruption of the TWI protocol - I don't know, it depends on implementation.)

As a side note: are you sure the EEPROM does not support single byte write? Since it is described in the datasheet I would expect it is supported but it is not staded explicitely.

Smajdalf:
I believe NO is the right answer. I don't have my computer here but I was doing similar thing some time ago. The OP's code measures time to SEND the command to the EEPROM, but not the time it takes to execute it. If you send second WriteByte command just after the first one you will get some unexpected behavior. (No byte will be written or the second command will take much longer waiting for the first write to finish or some corruption of the TWI protocol - I don't know, it depends on implementation.)

As a side note: are you sure the EEPROM does not support single byte write? Since it is described in the datasheet I would expect it is supported but it is not staded explicitely.

Smajdalf,
You are correct in the write function return time, I was considering when the next write was possible. Yes, the 10ms write time starts after the Wire.endTransmission(); has completed, the uS measurement was the I2C transmission time! Not the EEPROM write time! I was so stupid!

I guess is comes back to "Read what the Question was!" not what I thought it IS! >:(

Chuck.

Here is my own code to that wait for ACK (finishing of the write of the EEPROM) as decribed in datasheet. It part of larger sketch and it may corrupt the TWI protocol because it generates START condition and send slave address without continuing the transmission but it should work at least once:

void pollACK(byte address) { //address of the EEPROM
  byte isNACK=1;
  while (isNACK){
    TWCR = B11100100; //send start condition; interrupt disabled
    TWWait(); //wait for start
    //we will trust it was send
    sendRawByte(address);
    isNACK=(TWSR&B11111100)^0x18;
    }
}

void TWWait() {
  while (!(TWCR&(1<<TWINT))){
    
  }
}

Hello again,

Chuck:
Nice little piece of code. I'll add a timeout and use that most likely. Seems to be the simplest way to add to the code i already have.
I found that reading the byte back after the write works too, but the problem is that the wire lib returns 0xFF when there is a failure, so if i write the byte 0xFF it will look like it has been written when really it didnt get written yet, so the old data might still be there. I'd have to wait for 10ms in that case i guess, but i like your test better so next i'll add that and do some testing. Looks good so thanks. I dont know the Wire lib that well yet.
LATER:
Oh yeah BTW i think you meant "beginTransmission()". etc., and also BTW i tried it and it works.

Smajdalf:
I'll have to study your code as i dont know the Wire library that well yet, or whatever that is. I guess that's a more direct way to send codes to the I2C device? I'll look into that as i knew there was a way to poll the EEPROM but wasnt sure how to do it in the Arduino world.

If you are worried about knowing if the last 'erase,write' cycle has completed use this code to see if your EEPROM has finished the prior command:
Code: [Select]

bool i2cReady(uint8_t i2cAddr){
Wire.beginTransaction(i2cAddr);
return !Wire.endTransaction();
}

Here's how jack Christensen does it in his externalEEPROM which is pretty solid. GitHub - JChristensen/extEEPROM: Arduino library to support external I2C EEPROMs.

//wait up to 50ms for the write to complete
        for (uint8_t i=100; i; --i) {
            delayMicroseconds(500);                     //no point in waiting too fast
            Wire.beginTransmission(ctrlByte);
            if (_nAddrBytes == 2) Wire.write((byte)0);        //high addr byte
            Wire.write((byte)0);                              //low addr byte
            txStatus = Wire.endTransmission();
            if (txStatus == 0) break;
        }

For single bytes, and even page writes, I have always used delay(5) and the data winds up in the EEPROM.

cattledog:
Here's how jack Christensen does it in his externalEEPROM which is pretty solid. GitHub - JChristensen/extEEPROM: Arduino library to support external I2C EEPROMs.

//wait up to 50ms for the write to complete

for (uint8_t i=100; i; --i) {
            delayMicroseconds(500);                    //no point in waiting too fast
            Wire.beginTransmission(ctrlByte);
            if (_nAddrBytes == 2) Wire.write((byte)0);        //high addr byte
            Wire.write((byte)0);                              //low addr byte
            txStatus = Wire.endTransmission();
            if (txStatus == 0) break;
        }




For single bytes, and even page writes, I have always used delay(5) and the data winds up in the EEPROM.

Hi,

I had included the timeout function in my code too just in case something goes wrong with the EEPROM i dont want to wait all day for a return :slight_smile:
I used 100us increments and a max of 500 tries which covers about a 50ms span, which should be enough for any write. I'm using Chuck's routine, inline, with the timeout code added. It's working so good i dont think i want to change anything now :slight_smile: