Go Down

Topic: Slightly modify EEPROM_writeAnything to minimise write cycles (Read 2020 times) previous topic - next topic

zylantha

My sketch uses EEPROM_writeAnything to save state data on a regular basis, however being concerned about EEPROM failure I have made a slight change to the code to check if what is being written is different from what is already stored in the EEPROM, and only writing it if it is different from what is already there.

While there has been some discussion that EEPROM.write() should have this check already built in, having it in this function at least saves a lot of worry that you may be irrecoverably wearing out the EEPROM through too-frequent write cycles. 

While there is an extra step involved in reading-before-write, it takes a lot less time to read from the EEPROM than it does to write to it - therefore the net effect of this change will usually be an increase in speed of execution unless all data being written is different from what is already stored. 

The revised EEPROM_writeAnything function is as follows:

Code: [Select]
template <class T> int EEPROM_writeAnything(int ee, const T& value)
{
    const byte* p = (const byte*)(const void*)&value;
    unsigned int i;
    for (i = 0; i < sizeof(value); i++)
         EEPROM.read(ee)==*p ? e++, p++; EEPROM.write(ee++, *p++);  // Only write the data if it is different to what's there
    return i;
}

pYro_65


Code: [Select]
template <class T> int EEPROM_writeAnything(int ee, const T& value)
{
   const byte* p = (const byte*)(const void*)&value;
   unsigned int i;
   for (i = 0; i < sizeof(value); i++)
        EEPROM.read(ee)==*p ? e++, p++; EEPROM.write(ee++, *p++);  // Only write the data if it is different to what's there
   return i;
}



There is a problem with your code. Did you compile it?

Your conditional operator should look more like this:
Code: [Select]
( EEPROM.read(ee)==*p ) ? ee++, p++ : ({EEPROM.write(ee++, *p++), (const byte*)( 0x00 );});

There is also no saving over using an if statement.
Code: [Select]
for (i = 0; i < sizeof(value); i++){
 if( EEPROM.read(ee)==*p ){
   ee++;
   p++;
 }else{
   EEPROM.write(ee++, *p++);  // Only write the data if it is different to what's there
 }
}

pYro_65

#2
May 12, 2014, 12:55 pm Last Edit: May 13, 2014, 01:37 am by pYro_65 Reason: 1
Also for a size optimisation you should use the eeprom functions directly. When not using the EEPROM library this code is 74 bytes smaller on an Uno, probably faster too as the library functions probably aren't inlined.

Code: [Select]
for (i = 0; i < sizeof(value); i++){
 const byte b = *p;
 if( eeprom_read_byte( ( uint8_t* ) ee ) != b )
   eeprom_write_byte( ( uint8_t* ) ee++, b ), ++p;
 else
   ee++, p++;
}


EDITED '==' to '!=' in code. Explained in post below.

zylantha

Thanks, you are right - the missing curly brackets is showing up my rusty C++.  My original code compiles fine but doesn't work as intended without them.

However I'm pretty sure your final code also has an error in it (the if statement should be !=).

Code: [Select]
for (i = 0; i < sizeof(value); i++){
  const byte b = *p;
  if( eeprom_read_byte( ( uint8_t* ) ee ) != b )
    eeprom_write_byte( ( uint8_t* ) ee++, b ), ++p;
  else
    ee++, p++;
}

robtillaart

Thanks for these ideas,

Added link on - http://playground.arduino.cc/Code/EEPROMWriteAnything - to this thread
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

pYro_65


Thanks, you are right - the missing curly brackets is showing up my rusty C++.  My original code compiles fine but doesn't work as intended without them.

However I'm pretty sure your final code also has an error in it (the if statement should be !=).

Code: [Select]
for (i = 0; i < sizeof(value); i++){
  const byte b = *p;
  if( eeprom_read_byte( ( uint8_t* ) ee ) != b )
    eeprom_write_byte( ( uint8_t* ) ee++, b ), ++p;
  else
    ee++, p++;
}




Yes, alas its a  product of trying to write too fast.

There was more than the curly brackets, notice the 0x00 converted to a pointer, its needed as EEPROM.write returns nothing.

mrburnette

Oldie, but goodie:
Quote
Having a system that regularly writes parameters to the EEPROM can wear out the
EEPROM, since it is only guaranteed to endure 100 k erase/write cycles. Writing the
parameters to a circular buffer in EEPROM where each of the elements in the buffer
can endure 100 k erase/write cycles can circumvent this. However, if the system is
exposed to RESET conditions, such as power failures, the system needs to be able to
identify the correct position in the circular buffer again. This document describes how
to make safe high endurance parameter storage in EEPROM


AVR101: High Endurance EEPROM Storage
www.atmel.com/images/doc2526.pdf

Also, gahelton, over at AVR Freaks writes:
Quote
There are several techniques for extending the life of EEPROM (called wear leveling). The 100K cycle limit refers to a programming and erase cycle. Programming a cell, then erasing it, counts as 1 cycle. One method of extending the life is to "program many, erase once". For example, if you had one byte that had to be changed on a regular basis, you could write this value into an EEPROM array. Each time that you had to write the value, you could find the next erased address in the array and write the value there. When the predefined array was filled, it would be erased, and the process would start over. This would count as 1 program/erase operation for the entire array. So, if you had a 16 byte EEPROM array, you could store this single byte 16 x 100K or 1.6 million times.

You can also extend life of an EEPROM address "horizontally" as well. By programming individual bits (without erasure), you can also extend life. Example:

Code: [Select]
76543210
11111111 beginning state (erased)
11111110 program
11111100 program
11111000 program
11110000 program
11100000 program
11000000 program
10000000 program
00000000 program
11111111 erase


This would also count as 1 program/erase cycle.

Programming an already programmed bit does not count towards the programming cycle count, nor does erasing an already erased cell. The majority of damage to the cell comes from current flow into or out of the cell (changing the cell state) during a program or erase cycle.


Personally, I'm just too darn lazy to worry about 100K eeprom cycle issues... If the uC in the project lives 2x or 3x the warranty period, I'm good with that.

Ray

Go Up