EEPROM_writeAnything - slightly improved

Hi,

just like to share a slightly improvement to EEPROM_writeAnything. Lets assume you're using a struct to store your data to the EEPROM, for instance:

struct config_t
{
  unsigned int param1;
  unsigned int param2;
  unsigned int param3;
  int sockets[63];
} cfg;

The obvious drawback of the original EEPROM_writeAnything lies in always writing out the whole data to the EEPROM, regardless of the actual changed data. So here's my simple (but effective) solution:

template <class T> int EEPROM_writeAnything(int ee, const T& value)
{
  const byte* p = (const byte*)(const void*)&value;
  byte c;  // Comparison byte
  int i;
  for (i = 0; i < sizeof(value); i++) {
    c = EEPROM.read(ee);
    if(c != *p) {
      EEPROM.write(ee, *p);
    }
    *p++;
    ee++;
  }
  return i;
}

template <class T> int EEPROM_readAnything(int ee, T& value)
{
  byte* p = (byte*)(void*)&value;
  int i;
  for (i = 0; i < sizeof(value); i++)
    *p++ = EEPROM.read(ee++);
  return i;
}

The function reads and compares each byte, writing only different data to the EEPROM. This will drasticially improve write performance with bigger data structures, and increases the overall lifetime of the EEPROM. :wink:

Cheers,
-- Bastian

That is a nice idea, though have you noticed any increase in size of code or RAM usage because of the template usage? Would it not be simpler (trying to avoid templates here) to just pass a "const void *" to EEPROM_writeAnything?

--
The Ruggeduino: compatible with Arduino UNO, 24V operation, all I/O's fused and protected

Interesting point, I'll check that. Just copied the code from the playground: Arduino Playground - EEPROMWriteAnything. Using templates seems a bit overkill to me as well.

Made a quick test, first using templates:

template <class T> int EEPROM_writeAnything(int ee, const T& value)
{
    (...)
}

Binary sketch size: 15528 bytes
Available RAM: 438 bytes

...next without:

int EEPROM_writeAnything(int ee, const config_t& value)
{
    (...)
}

Binary sketch size: 15682 bytes
Available RAM: 438 bytes

Surprisingly, using templates saves me 154 bytes, the RAM doesn't seem to be affected at all...

Cool! Yay for GCC.

Personally I would still prefer a "const void *" version ensuring that only 1 instance of the code is ever instantiated. I'd be worried with the template version that if you try to use the functions with more than one type it will insert the code twice.

--
The Flexible MIDI Shield: MIDI IN/OUT, stacking headers, your choice of I/O pins

Besides a memory test, do you have some figures about the speed differences?

I think of a testcase with a 20 bytes struct or array ... ( don't have an Arduino free at the moment :frowning:

same, # time without read, time with read

0, t1, t2
1,
...
20,

TIA,
Rob

The theoretical value : http://www.arduino.cc/en/Reference/EEPROMWrite => An EEPROM write takes 3.3 ms to complete
Can't find the value for EEPROMRead() ??


the char c is not needed?

template <class T> int EEPROM_writeAnything(int ee, const T& value)
{
  const byte* p = (const byte*)(const void*)&value;
  int i;
  for (i = 0; i < sizeof(value); i++) {
    if (EEPROM.read(ee) != *p) EEPROM.write(ee, *p);
    }
    *p++;
    ee++;
  }
  return i;
}

Maybe it is better to change it one level lower in the EEPROM class in EEPROM.cpp, Then other EEPROM applications would benefit from it too!

from EEPROM.cpp

uint8_t EEPROMClass::read(int address)
{
	return eeprom_read_byte((unsigned char *) address);
}

void EEPROMClass::write(int address, uint8_t value)
{
	eeprom_write_byte((unsigned char *) address, value);
}

to

uint8_t EEPROMClass::read(int address)
{
	return eeprom_read_byte((unsigned char *) address);
}

void EEPROMClass::write(int address, uint8_t value)
{
         if (eeprom_read_byte((unsigned char *) address) != value) eeprom_write_byte((unsigned char *) address, value);
}