EEMEM Wear Leveling

Does EEMEM always store data in the same EEPROM address? I want to write to EEPROM every few seconds and I'm worried about exceeding the max write cycle (100,000) for any one particular address. I don't need to know the specific address where data is stored, I'm just looking for some easy wear leveling.

Example 1:

EEMEM uint16_t myDataAddress = 1;
uint16_t myData = eeprom_read_word(&myDataAddress);

-Does this mean that "myData" will always be written to address 1?

Example 2:

EEMEM uint16_t myDataAddress;
uint16_t myData = eeprom_read_word(&myDataAddress);

-Where is the data stored?

  • Is the data always stored in the same address or does the address change when powered off/on?
EEMEM uint16_t myDataAddress = 1;
uint16_t myData = eeprom_read_word(&myDataAddress);

-Does this mean that "myData" will always be written to address 1?

You would always read from address 1.

EEMEM uint16_t myDataAddress;
uint16_t myData = eeprom_read_word(&myDataAddress);

Where is the data stored?

  • Is the data always stored in the same address or does the address change when powered off/on?

You only read the data, from an unspecified address (it may be 0, if the compiler initializes the variable, but that's not guaranteed).

You only read the data, from an unspecified address (it may be 0, if the compiler initializes the variable, but that's not guaranteed).

Ok, that makes sense but will this address ever change on it's own? Do I still need to force the address to change every so often to avoid excessive wear?

Thanks!

will this address ever change on it's own

It doesn't change on its own. Your code needs to change it.

Do I still need to force the address to change every so often to avoid excessive wear

I would change it after each write, if I was concerned about the eeprom wearing out.
But then you will also need to store the last address somewhere as well. And that gets written (to the same address) a lot more often than the byte of data ("myData") itself.

What type of data do you want to store every few seconds? Is it the state of a button or some small number, big number, or what?

Mr_Laggy:
Does EEMEM always store data in the same EEPROM address? I want to write to EEPROM every few seconds and I'm worried about exceeding the max write cycle (100,000) for any one particular address. I don't need to know the specific address where data is stored, I'm just looking for some easy wear leveling.

The EEPROM low level code that supports EEPROM reading and writing via the "EEPROM" library does not do any wear leveling. It doesn't even do intelligent "selectively program more bits". If you write an address, it's always the same address. There is an "update" function that will avoid the erase/write cycle if the data you want to store is the same as what's already there, but the chances of the data being the same are usually remote and "update" won't save you much at all.

Now, I can't imagine why any program would need to save something to EEPROM every few seconds. There should be a way to do whatever you're trying to do without writing to the EEPROM over and over (and ruining it really quickly).

Even if you need to have a backup of some variables when the code restarts (either normally or via the watchdog timer), you can instead use a small battery backup or a supercap (plus a hardware interrupt) and detect a power failure, but still have a few seconds of run time left to store away your important variables.

What exactly are you trying to do that needs to destroy.... um I mean write to your EEPROM every few seconds?

Mr_Laggy:
Does EEMEM always store data in the same EEPROM address? I want to write to EEPROM every few seconds

Why? This sounds like an X-Y problem. Does the data change that much? Why store it? You have something, you haven't said what, and you want to store it, into one memory location, every second, for some reason. What reason would that be? That one location will last just over a day at that rate.

-Where is the data stored?

  • Is the data always stored in the same address or does the address change when powered off/on?

It is stored where you tell it to be stored.

If you only stored changes that would be different. And if you deferred storing a change until, say, 5 seconds elapsed that would be more sensible again.

I had a similar sort of thing where I needed to store a simple number, which kept incrementing. So what I did was dedicate the first page of EEPROM (a page is 4 bytes) to remembering where the active numbers was (eg. address 4, address 8, etc.).

Then I kept a count of how many writes had been done in a page (this was part of the page). Once it approached the limit (100,000) I moved onto the next page. This resulted in a write to the first page (the one that remembers which page is active) once every 100,000 writes. That then increments so that we know we are using another page in EEPROM.

Thus each page contained:

  • The number we are interested in
  • How many times we updated it

Of course, you won't store 100,000 into 2 bytes, so a "page" is probably going to be around 8 bytes at this rate.

Now the total number of writes you can do is something like:

1024 / 8 * 100000 = 12800000

That's 148 days, if you really have to write once a second. Which I doubt.

Mr_Laggy:
Does EEMEM always store data in the same EEPROM address?

Short answer: No!

Longer answer:

If you're lucky, same code, compiler, linker then no worries. But EEMEM can be looked at as a way to allow a layout that has no conflicting addresses (overlap). So adding in a library that uses EEMEM variables is going to affect your local layout using EEMEM.

More complete answer:

IDE's before 1.5.7 usually put things in the EEPROM in the order they are declared. The newer IDE using GCC 4.8.1 usually does the exact opposite. People that used hard coded addresses to EEMEM variables suddenly had broken code. The compiler reverses a few things like the order of evaluation in a statement without a sequence point, or function call inputs. There is no guarantee for either ordering (GCC has a -flag to force certain aspects of this).

EEMEM should be used to remove the dependence on fixed locations. Its not really logical to use a fixed pointer address. Just like RAM, you can use any address you like, however the stack/heap is free to run over your pointer if there is no logical allocation. This is why you should always have a pointer (if nothing gave you the address, then you are using a fixed location), and is why a pointer to int conversion is illegal without a specific C-style cast. The exception is things like memory mapped registers.

Many years ago I wanted to see exactly what a "worn out" EEPROM behaved like. So I took one of my Motorola "EVBU" (68HC11 evaluation) boards and wrote a tiny assembler program that ran a sequence like this (pseudo-code):

LOOP:   WRITE  EEPROM 0x00  ; 0b00000000
        WRITE  EEPROM 0x55  ; 0b01010101
        WRITE  EEPROM 0xAA  ; 0b10101010
        JUMP   back to LOOP
        
....
WRITE:  INC    64 BIT counter  ; count this cycle
        ERASE  EEPROM, ADDR    ; pre-erase last byte
        PROG   VALUE, ADDR     ; write data
        COMP   EEPROM, ADDR to VALUE ; compare EE to data
        JUMP IF MATCH WRITE    ; same, so go again
....
        PRINT to LCD "EE FAIL AT " ; failed, show result on LCD
        PRINT to LCD 64 BIT counter
HANG    JUMP    HANG

The EEPROM writing code allowed up to 20 msec for an EE location to write, otherwise it timed out (Motorola specs say 10 ms max, but I used 20).

I connected the board to a wall wart and walked away. A few days later, I looked at the LCD. Nothing.

After 2 weeks, still nothing.

If you assume that the EEPROM programmed well before 20 msec was up (which it did) and then take 1/20ms = 50 writes per second multiplied by 86400 seconds in a day you get 4320000 writes per day times 2 weeks is 60480000 writes!

So now I begin to think that the EEPROM is working, but maybe it's simply degrading which may show up as an increase in required write time.

I stopped the test and re-wrote the code to compare "this programming time" to "previous programming time" and do an LCD display if it was different.

When I started the program, of course it immediately displayed a write time (because "previous" was zero). As it ran, the LCD occasionally updated, but instead of increasing it just vacillated between 4 and 5 ms.

After a few more weeks I thought "well maybe it writes but it won't retain the data. So I wrote 0x00 to the location (all bits programmed) and then ran a loop that looked for "value at location is not zero".

I left it running and eventually forgot about it. Several months later, I saw the dusty board in the corner and checked the LCD. Still running, but no readback error.

That left me completely confused.

(edit to add): Motorola specs say 10K erase/write cycles is the EEPROM lifetime.

pYro_65:
IDE's before 1.5.7 usually put things in the EEPROM in the order they are declared.

I think you are thinking of PROGMEM here, not EEPROM.

One approach that I have used where I needed to constantly update a few values in non volatile storage wss to use an FRAM chip - those have nigh unlimited write cycles. The cost per bit is exorbitant, but if you're not storing much, that's not a problem. 2kbyte (16kbit) ones are only like 2 bucks and change, ave the interface is the same as eeprom chips.

Nope. What I wrote is applicable to both.

pYro_65:
Nope. What I wrote is applicable to both.

What you wrote doesn't make any sense.

jremington:
What you wrote doesn't make any sense.

What have you failed to understand?

Have you not used the EEMEM attribute before? Most likely not.

pYro_65, would you mind, please show us how to properly do this with EEMEM? Perhaps a short tutorial to enlighten us about "EEMEM should be used to remove the dependence on fixed locations. Its not really logical to use a fixed pointer address." for a newbie on this subject like me. I would like to understand this.

What have you failed to understand?

What your comment has to do with wear leveling.

jremington:
What your comment has to do with wear leveling.

Even when I quoted at the top (from the OP):

Mr_Laggy:
Does EEMEM always store data in the same EEPROM address?

You are still having trouble understanding?
I'm sorry... I can't help you with a lack of attention to detail.

I however, can clearly see that if you can't rely on the locations of data attributed with EEMEM, then a wear leveling lib might require a more robust approach.

dmjlambert:
pYro_65, would you mind, please show us how to properly do this with EEMEM? Perhaps a short tutorial to enlighten us about "EEMEM should be used to remove the dependence on fixed locations. Its not really logical to use a fixed pointer address." for a newbie on this subject like me. I would like to understand this.

Sure here is a basic example to do with EEMEM, I can add to it later if needed.

However doing wear leveling 'properly' with EEMEM does not really make much sense. EEMEM manages discrete allocations, not data that moves around. You could use EEMEM to allocate a large block of memory, then constrain your wear leveling to this..

This code shows one way fixed locations can be used.

#include <EEPROM.h>

//Locations for data.
#define EE_PARAM_A   0
#define EE_PARAM_B   EE_PARAM_A + sizeof(int)
#define EE_PARAM_C   EE_PARAM_B + sizeof(int)

void setup(){

  //Runtime variables.
  int param_A, param_B, param_C;  

  //Access each object.
  EEPROM.get( EE_PARAM_A, param_A );
  EEPROM.get( EE_PARAM_B, param_B );
  EEPROM.get( EE_PARAM_C, param_C );
}

void loop() {
}

Using EEMEM, the same result can be achieved without worrying about addresses. The compilation process will automatically space out all EEMEM data over the EEPROM.

The benefit of this is, any code you do not know uses EEMEM will not interfere with your EEMEM data. If a lib uses EEMEM and you use fixed addresses, you'll have overlapped memory.

#include <EEPROM.h>

//Locations for data.
int eeParamA EEMEM;
int eeParamB EEMEM;  
int eeParamC EEMEM;  

void setup(){

  //Runtime variables.
  int paramA, paramB, paramC;  

  //Access each object.
  EEPROM.get( &eeParamA, paramA );
  EEPROM.get( &eeParamB, paramB );
  EEPROM.get( &eeParamC, paramC );
}

void loop() {
}

A huge benefit of EEMEM (which is not available in the IDE out of the box), is that you can assign an initial value just like PROGMEM data.

pYro_65:
Nope. What I wrote is applicable to both.

Can you post some example code please? The only reference I can find to EEMEM is here in ./hardware/tools/avr/avr/include/avr/eeprom.h:

#define EEMEM __attribute__((section(".eeprom")))

Ach, never mind. I found some hints by a bit of searching. This for example does not work:

int foo EEMEM;
char bar [10] EEMEM;

void setup ()
  {
  foo = 22;
  strcpy (bar, "Nick");
  }  // end of setup

void loop ()
  {
  }  // end of loop

All that EEMEM does is allocate the variables in a different address space. You still have to use the EEPROM accessing functions. I can't say this is at all obvious from any of the examples I saw.

pYro_65:
EEMEM (which is not available in the IDE out of the box)

Is this for people who are not interested in the IDE, or is there an appropriate way to add it to the IDE?

Since it is not available in the IDE out of the box, does this mean common libs for Arduino don't use EEMEM (for example EEPROM.h and EEPROMex.h)?

Can you please show us how to do wear leveling with EEMEM allocations for a variable we plan to update into EEPROM extremely often?