I'm working on an Arduino library that will maximize the life of the AVR's EEPROM. It takes the number of variables you want to store and does the rest. This is my attempt, which does not work in all cases.
Background information
Atmel says each memory cell is rated for 100,000 write/erase cycles. They also provide an application note, which describes how to perform wear levelling. Here is a summary of the application note.
By alternating writes across two memory addresses, we can increase the erase/write to 200,000 cycles. Three memory addresses gives you 300,000 erase/write cycles and so on. To automate this process, a status buffer is used to keep track of where the next write should be. The status buffer must also be the same length as the parameter buffer because wear leveling must be performed on it as well. Since we can't store the index of the next write we increment the corresponding index in the status buffer.
Here is an example.
<------------------- EEPROM -------------------->
0 N
-------------------------------------------------
Parameter Buffer | Status Buffer |
-------------------------------------------------
Initial state.
[ 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 ]
First write is a 7. The corresponding position
in the status buffer is changed to previous value + 1.
Both buffers are circular.
[ 7 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 ]
A second value, 4, is written to the parameter buffer
and the second element in the status buffer becomes
the previous element, 1 in this case, plus 1.
[ 7 | 4 | 0 | 0 | 0 | 0 | 1 | 2 | 0 | 0 | 0 | 0 ]
And so on
[ 7 | 4 | 9 | 0 | 0 | 0 | 1 | 2 | 3 | 0 | 0 | 0 ]
To determine where the next write should occur, we look at the difference between elements. If the previous element + 1 does NOT equal the next element then that is where the next write should occur. For example:
Compute the differences by starting at the first
element in the status buffer and wrapping around.
General algo: previous element + 1 = current element
1st element: 0 + 1 = 1 = 1st element (move on)
2nd element: 1 + 1 = 2 = 2nd element (move on)
3rd element: 2 + 1 = 3 = 3rd element (move on)
4th element: 3 + 1 = 4 != 4th element (next write occurs here)
[ 7 | 4 | 9 | 0 | 0 | 0 | 1 | 2 | 3 | 0 | 0 | 0 ]
^ ^
| |
Another edge case to consider is when the incrementing values
wrap around at 256 because we are writing bytes. With the
following buffer we know the next write is at the 3rd element
because 255 + 1 = 0 != 250 assuming we are using byte arithmetic.
[ x | x | x | x | x | x | 254 | 255 | 250 | 251 | 252 | 253 ]
^
|
After we write at element 3 the status buffer is incremented
to the next value using byte arithmetic and looks like this.
255 + 1 = 0 (wrap around)
0 + 1 != 251 (next write is here)
[ x | x | x | x | x | x | 254 | 255 | 0 | 251 | 252 | 253 ]
^
|
These examples above show how to extend the life of the EEPROM for one variable. For multiple variables imagine segmenting the EEPROM into multiple segments with the same data structure, but smaller buffers.
Problem
I have working code for what I described above. My problem is the algorithm does not work when the buffer length >= 256. Here is what happens
Buffer length of 256. The last zero is from
the initial state of the buffer. At every index
previous element + 1 == next element. No way to
know where the next write should be.
<-------------- Status Buffer ------------>
[ 1 | 2 | ... | 253 | 254 | 255 | 0 ]
A similar problem occurs when the buffer length
is greater than 256. A lookup for a read will think
the next element is at the first 0 when it should be at
255.
<-------------------- Status Buffer ------------------>
[ 1 | 2 | ... | 253 | 254 | 255 | 0 | 0 | 0 ]
Question
How can I solve the above problem? Is there a better way to track where the next element should be written?