7

I want to store a few (8 as of now) IR codes into my Board's EEPROM. It would be great if someone could suggest a few tips to maximize the lifetime.

The IR codes in my sketch are saved in array of unsigned longs.

I know that the count of times that I will be writing to EEPROM will << 100,000 times, but still would like to optimize my sketch. + would help in future projects

4
  • 4
    Just out of interest, I tried to "wear out" my EEPROM a while back. It took something like 1.5 million writes before it started to fail.
    – Nick Gammon
    Commented Feb 3, 2017 at 0:50
  • @NickGammon, what were the failures like? Random data? Commented Feb 3, 2017 at 7:04
  • 1
    One bit failures, from memory.
    – Nick Gammon
    Commented Feb 3, 2017 at 8:30
  • It's possible that if you exceed the specifications the memory might become less reliable. I didn't test that. Conceivably you might find that, after a month, a bit would change. My own findings were that you could exceed the recommended ratings by a substantial amount, and still read back the byte you wrote, a moment later.
    – Nick Gammon
    Commented Feb 3, 2017 at 8:32

4 Answers 4

5

I can think of a few:

  1. don't power it on unless you have to;
  2. don't write to it unless you have to;
  3. write as little data to you as you can - compress the data; only write to it during brown out or power down, ...;
  4. level the writes to as many cells as possible - increment the write address with subsequent writes;
  5. use a big eeprom;
  6. use fram;
  7. use sram + battery back-up;

...

3 - 7 are really examples of implementating #2.

0
7

The other answer mentioned some general ideas; here are a couple of more-specific notes.

• You can direct your writes of single bytes through a routine that reads the EEPROM cell before writing to it, and if its value isn't changing, doesn't write.

• For load-leveling, you can divide the EEPROM address space into k buckets, where k =⌊E/(n+1)⌋, with n = data array size and E = EEPROM size. Initialize a directory, an array of m bytes all set to k, with m = E-n·k. When your device starts up, it reads through the directory until it finds current entry, a byte not equal to k. [If all directory entries equal k, initialize the first to 0, and go on from there.] If the current directory entry contains j, then bucket j contains current data. When you need to write new data, you store j+1 into the current directory entry; if that makes it equal to k, initialize the next directory entry to 0, and go on from there. Note that directory bytes get about the same amount of wear as bucket bytes because 2·k > m ≥ k.

1
  • Thanks, I will try and implement load-leveling to my sketch also. Great explanation. I do check if the values are same before writing, so that part is taken care of.
    – karx
    Commented Feb 3, 2017 at 18:46
3

If your data occupies only a small fraction of your EEPROM, you could use one of the wear leveling algorithms. The essence of these algorithms is to write to a different location each time, so writes are spread across several locations while each location stays below the 100,000 writes limit.

There are several such algorithms discussed here, which you could implement yourself. Alternatively, you could just use a library like this one.

1
  • 1
    These are great links Dmitry! Thanks. Anyways, now I am using ~the entire EEPROM for data. Write operations are rare in my code and only happen during the start of the lifecycle (configuration period of my device). The lifecycle mostly consists of only read operations. As the size of my config-files is increasing I am now looking for memory-optimization techniques to fit all that in the EEPROM and no go for any additional storage.
    – karx
    Commented May 10, 2017 at 22:57
0

I believe there's a simple way to use only n cells and a single dedicated bit pattern to achieve n/2 increase in durability.

The dedicated bit pattern (e.g. 0xffff) is a marker which indicates an unused cell, and in normal operation at most one cell at a time has this value:

uint16_t readWord (const uint16_t *address);
void writeWord (uint16_t *address, uint16_t value);

#define CELL_COUNT   42
#define BASE_ADDRESS 12
#define MARKER       0xffff  // Best to use EEPROM default for this

static uint8_t curCell = 0;

static void wlInit (void)
{
  for ( uint8_t ii = 0 ; ii < CELL_COUNT ; ii++ ) {
    if ( readWord (BASE_ADDRESS + ii) != MARKER ) {
      curCell = ii;
      // No early return/break here to keep init() execution time 
      // constant.  Could also check for corruption here by checking for
      // > 1 cells with MARKER (see below).
    }
  }
  // If we didn't find a non-marker cell we'll end up with curCell = 0 
  // per the initial value of curCell
}

static uint16_t wlRead (void)
{
  return readWord (BASE_ADDRESS + curCell);
}

static void wlWrite (uint16_t value)
{
  assert (value != MARKER);   // Storing marker value is big no-no

  uint8_t nextCell = (curCell + 1) % CELL_COUNT;
  writeWord (BASE_ADDRESS + nextCell, value);
  writeWord (BASE_ADDRESS + curCell, MARKER);
  curCell = nextCell;
}

The same approach can be used with structured data provided a bit pattern can be reserved (either in a dedicated byte or from some other field that has a spare pattern).

This approach also has a useful property with respect to interrupted (e.g. power drop) writes: if there are ever two cells without the MARKER value an incomplete (i.e. corrupted) write has occurred. This seems useful, because e.g. the ATmega328P datasheet contains the following unclear and not-particularly-reassuring paragraph about using brown-out detection to avoid corruption:

Keep the AVR RESET active (low) during periods of insufficient power supply voltage. This can be done by enabling the internal Brown-out Detector (BOD). If the detection level of the internal BOD does not match the needed detection level, an external low V CC reset Protection circuit can be used. If a reset occurs while a write operation is in progress, the write operation will be com- pleted provided that the power supply voltage is sufficient.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.