EEPROM library and wear reduction

Hi.

From what I understand, each EEPROM address/byte has 100,000 erase/write cycles before it wears out.
A 'write' constitutes changing bit values from 1 to 0, where as to change a bit value from 0 to 1 the entire byte must be "erased" ie all bits set to 1 (0xFF) and then selected bits are written to 0. For example, to write value 0x01 to 0x00 doesn't require an 'erase' event, where as writing 0x00 to 0x01 first requires that the entire byte is erased to 0xFF and then bits 7 to 1 are written to 0, leaving bit 0 as a 1.

If using a single address/byte to store a counter variable that increments by 1 per write event, you get less wear if you count backwards from 255 rather than forwards from 0. If you count forwards you cause an "erase"event for every write. However if you count backwards only every second write incurs an "erase".

How to take advantage of this with EEPROM.h library? Does the function EEPROM.write() erase the address before writing regardless of what value was stored in it previously? I'm guessing it does, otherwise the function EEPROM.update() wouldn't be necessary. Great that we can avoid unnecessary erasures with EEPROM.update(), but only if the values are the same. However, If the current value at 'address' was 0x01 and I wanted to write it to 0x00, no erase would be necessary, but I have a sneaking suspicion that EEPROM.write() erases it anyway. EEPROM.update() won't help because the values are not the same.

Can anyone confirm if EEPROM.write() conserves wear by not unnecessarily erasing bytes before they are written?

Cheers.

Can anyone confirm if EEPROM.write() conserves wear by not unnecessarily erasing bytes before they are written?

Since EEPROM.write() has no idea what is currently at the address you are writing to, how could it know whether an erase was needed, or not?

EEPROM.write does what is says: it writes EEPROM regardless of current value. EEPROM.update will read the old value/byte from the specified location and if it differs from the new value/byte it will write the new byte.

The best way of reducing EEPROM writes it to make sure (in code) that EEPROM is only written when strictly necessary.

I think that the functionality of EEPROM.update() should be extended so that when only zeros need to be written an erase event does not occur unnecessarily. It's a shame that the Library doesn't facilitate the economical use of EEPROM.

Thanks for your responses.

What application uses 100K writes in EEPROM?
at 1 write per second you can write a whole day.

If you use a (count, value) tuple you could also state that if count = 0xFFFF,
you need to take the next EEPROM location

when you reservate 5 slots for the tuple you can do 5x 0xFFFF = 325K writes
when you reservate 16 slots ==> about 1M writes.

However if you need that much writes you probably should consider another persistant storage like FRAM

boggydew:
I think that the functionality of EEPROM.update() should be extended so that when only zeros need to be written an erase event does not occur unnecessarily. It's a shame that the Library doesn't facilitate the economical use of EEPROM.

Thanks for your responses.

Last I was browsing the source for EEPROM function, I notice your suggestion has already been implemented back when. The documentation may be obsolete as to that fact?

kenneth558:
Last I was browsing the source for EEPROM function, I notice your suggestion has already been implemented back when. The documentation may be obsolete as to that fact?

Thanks, that's what I am trying to clarify. Does the update() function only 'erase' if bit values of 1 need to be written, or does it always call the write() function regardless, (except of course, when the old and new values are the same).

Do I have to take out a ticket to get clarification on this?

but I have a sneaking suspicion that EEPROM.write() erases it anyway. EEPROM.update() won't help because the values are not the same.

Can anyone confirm if EEPROM.write() conserves wear by not unnecessarily erasing bytes before they are written?

EEPROM cells can be seen as little capacitors. Erasing means they are charged (a 1). When we program a number into a memory location, only the bits that need to be zero are discharged. if the cells are all charged, there is no need for an erase and then the write can take the relevant bits to uncharge (zero).

In modern EEPROM and modern AVR, There are two ways to update the EEPROM memory: atomic write and split operation. With atomic write, EEPROM locations are erased and written in one operation. With split operation, erasing and writing are separate operations.

A split write can program selected bits to logic zero. an atomic write first erases to logic one and then writes logic zeros to selected bits.

Unfortunately, From the top of my head, standard arduinos only support erase and write style so you most likely can’t do,what you want

If you are curious about what happens, You could find more by looking in the source codevoid update( int idx, uint8_t val )  { EERef( idx ).update( val ); }

Which calls that codeEERef &update( uint8_t in )          { return  in != *this ? *this = in : *this; }
which will asign (operator =) the byte in memory only if it has changed

Operator = has been overloaded withEERef &operator=( uint8_t in )      { return eeprom_write_byte( (uint8_t*) index, in ), *this;  }

So it all boils down to what the function [

eeprom_write_byte()

](toolchain-avr/avr-libc-patches/eeprom.h at a46e93f109927cd9aa15296ec7a20b2f95c4b57e · arduino/toolchain-avr · GitHub) does - which you can see here

static __inline__ void eeprom_write_byte (uint8_t *__p, uint8_t __value)
{
    do {} while (!eeprom_is_ready ());

#if	defined(EEPM0) && defined(EEPM1)
    EECR = 0;		/* Set programming mode: erase and write.	*/
#elif	defined(EEPM0) || defined(EEPM1)
# warning "Unknown EECR register, eeprom_write_byte() has become outdated."
#endif

#if	E2END <= 0xFF
    EEARL = (unsigned)__p;
#else
    EEAR = (unsigned)__p;
#endif
    EEDR = __value;

    __asm__ __volatile__ (
        "/* START EEPROM WRITE CRITICAL SECTION */\n\t"
        "in	r0, %[__sreg]		\n\t"
        "cli				\n\t"
        "sbi	%[__eecr], %[__eemwe]	\n\t"
        "sbi	%[__eecr], %[__eewe]	\n\t"
        "out	%[__sreg], r0		\n\t"
        "/* END EEPROM WRITE CRITICAL SECTION */"
        :
        : [__eecr]  "i" (_SFR_IO_ADDR(EECR)),
          [__sreg]  "i" (_SFR_IO_ADDR(SREG)),
          [__eemwe] "i" (EEMWE),
          [__eewe]  "i" (EEWE)
        : "r0"
    );
}

The address of the byte you want to write is specified in the EEPROM Address Register (EEAR). If the AVR you are using has more than 256 bytes, the EEAR register is divided in the EEARH and EEARL registers. this is handled with

#if	E2END <= 0xFF
    EEARL = (unsigned)__p;
#else
    EEAR = (unsigned)__p;
#endif

The EEPROM Data Register (EEDR) contains the data you want to store.It is initialized with the value passed as a parameter EEDR = __value;

The EEPROM Control Register (EECR) is used to control the operation of the EEPROM. It has three bits : EEMWE, EEWE and EERE. The EERE (EEPROM Read Enable) bit is used to read the EEPROM and not used here.

In order to issue an EEPROM write, you must first set the EEMWE (EEPROM Master Write Enable) bit, and then set the EEWE (EEPROM write enable) bit. The EEWE bit is also used to know if the EEPROM is ready to write a new byte. While the EEPROM is busy, EEWE is set to one, and is cleared by hardware when the EEPROM is ready. So, the program polls this bit and wait until is cleared before writing the next byte. This is what this does do {} while (!eeprom_is_ready()); and you can see here how eeprom_is_ready() is defined # define eeprom_is_ready() bit_is_clear(EECR, EEWE)

EECR is the EEPROM control register in AVR
SBI is an assembly language command to Set a Bit in I/O Register

Two bits are set in assembly in the control register which has been initially set to zero

        "sbi	%[__eecr], %[__eemwe]	\n\t"
        "sbi	%[__eecr], %[__eewe]	\n\t"

• Bit 2 – EEMWE: EEPROM Master Write Enable
You must write one to EEMWE to enable EEPROM write operation.

• Bit 1 – EEWE: EEPROM Write Enable
EEWE is the write strobe to the EEPROM. To write the value into the EEPROM this bit must be written to one after you set up address and data correctly . Before that the EEMWE bit must be set to one, otherwise no EEPROM write takes place.

So what do we know? The write of the byte is done in one go, push the byte to the right Hardare register... what happens at physical level is this AVR dependent and as there is no way to play with split mode or atomic, one need to believe it’s always erase and write....

My 2cts on how I would think about that

1 Like

boggydew:
Thanks, that's what I am trying to clarify. Does the update() function only 'erase' if bit values of 1 need to be written, or does it always call the write() function regardless, (except of course, when the old and new values are the same).

Do I have to take out a ticket to get clarification on this?

I looked a bit for the ditty that I remembered seeing, but can't find it now. I don't know any reason to ever use the .write except for wear-testing. I only use the .update.

If you use EEPROM.put() it automatically uses the update mechanism.

UKHeliBob:
If you use EEPROM.put() it automatically uses the update mechanism.

indeed, but I don't think this is the point of the OP.

I think OP’s question is one level down: the ability to support split mode rather than atomic - that is - to make erasing and writing separate operations.

indeed, but I don't think this is the point of the OP.

It would have been better if I had quoted some/all of his post but I was replying to kenneth558 not to the OP

UKHeliBob:
If you use EEPROM.put() it automatically uses the update mechanism.

And I searched source again and found the .put() code is what I must have remembered b/c the .write() source still contains the comment: - All write functions force erase_and_write programming mode.

Reference: https://github.com/arduino/toolchain-avr/blob/master/avr-libc-patches/eeprom.h

Would a split write that changed only 1 bit in a byte count as a write to the EEPROM ?

UKHeliBob:
Would a split write that changed only 1 bit in a byte count as a write to the EEPROM ?

Misunderstanding possible of "split". I'll assume you intend to limit it to a single byte per the remainder of that sentence: all references I have found thus far of EEPROM.update() compare the entire byte as follows:

/***
The function EEPROM.update(address, val) is equivalent to the following:

if( EEPROM.read(address) != val ){
EEPROM.write(address, val);
}
***/

Example reference: https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/libraries/EEPROM/examples/eeprom_update/eeprom_update.ino

So a single bit difference results in a .write() of the entire byte.

From reply #7

A split write can program selected bits to logic zero

It was that phrase that prompted my question, not the way in which update() works, which I know is different. If a split write counts as a write (why wouldn't it ?) then the memory address would be subject to the same 100,000 write limit as writing a whole byte.

Charging a bit or discharging means applying a high voltage from the charge pump - either positively or negatively

If you play with one byte, this energy from the charge pump is concentrated on that one byte which accelerated the wear. If a page write is used, that energy is dissipated over more bytes, so cell wear is decreased.

So Setting bits to zero does create a wear but if you save setting to 1 beforehand then you have somewhat protected you’re cell - that is moving from 1100.1100 to 1100.0000 could be technically done without setting all the bits to 1 in the first place... but probably the negative voltage would still be applied to bring the zero to zero as split write still assumes the erase was done sometimes before hand