EEPROM.put an array - one element or entire array?

For my project, I have an array, int32_t Xyz[7][5] that I save to EEPROM (EEPROM.put(0, Xyz)) during an INIT routine. On subsequent power-ups, I read in the entire array during setup (EEPROM.get(0, Xyz)). All this is fine. When the program is running, I need to occasionally update one or more elements within that array. These changes are human interactions (settings, and switch changes from time to time), so we are not talking about a lot of changes (maybe 20 EEPROM puts in a day?).

Every 60 seconds, I check if one or more of the elements have been changed, and if so, I do an EEPROM.put command. So it's probably not critical, but for reference and future projects, which of these methods would be preferred?

A) Perform an EEPROM.put(0, Xyz[a][b]) for each element of the array that has changed (likely just one, but could be up to 4 elements).

or

B) Or just write the whole array if anything changed? That is, perform a EEPROM.put(0, Xyz).

I'm not sure how EEPROM works - does a block get updated when anything gets updated? Would two individual puts actually be more write cycles than just writing the entire array?

Hopefully I was clear. I'm doing individual puts now, and so either should work.

This is for a Sparkfun ProMicro board (ATMega32U4 5V 16MHz) if it matters.

Hi,

To make your EEPROM work you must be careful. EEPROM has limited write cycles. To use less write cycles I recommend having a line in your code, so it only writes to the EEPROM if the value has changed.

Hope this helps!

1 Like

Also if this was critical, you should probably invest in external memory, such as an SD, to make it last.

1 Like

Thank you - yes, the function where I do the writing is only called if something has changed. And only called once every 60 seconds, and there will probably only be a dozen or changes in the course of a day, on average, often less. So I doubt I’d ever hit any limits, but I still like to understand best practices, for future projects where this may be more important.

The internal EEPROM on Arduino boards, typically found in the ATmega microcontrollers, has a specified life of 100,000 write/erase cycles. This means each individual memory location within the EEPROM can reliably be written to and erased approximately 100,000 times before degradation may occur.

Yeah, you will probably never hit the limit.

1 Like
    template< typename T > const T &put( int idx, const T &t ){
        EEPtr e = idx;
        const uint8_t *ptr = (const uint8_t*) &t; 
        for( int count = sizeof(T) ; count ; --count, ++e )  (*e).update( *ptr++ );
        return t;
    }  

The put() function in the EEPROM library uses update() instead of write(), so it does a read first, then only writes to EEPROM if the value has changed.

4 Likes

As usual, YMMV applies.
If you do a put of the entire array, then even though the update method is used, each address in the array must be read, compared, and written if different; if only one element has changed, that whole process still happens, with the exception of all-but-one write. So, for a small array, no big deal; the delay for this to happen for an array with hundreds of elements might be noticeable. Or not. That's the YMMV.

1 Like

Interesting. I started with EEPROM.update, and even though it compiled, and ran, I learned (after it didn’t do what I expected!) that update only accepts a single byte, my int32 was not compatible.

I take it (not sure though), that when I EEPROM.put an array, it is just doing a byte-by-byte EEPROM.write, with the read before to avoid redundant writes?

In that case, my method of only EEPROM.put the elements that I know have changed is probably most efficient, as the library would just be reading through all the others.

And it appears this is a true byte-by-byte operation? I know some types of memory have to write an entire block to change one byte.

You'll have to look at the underlying documentation for that processor, to verify that it isn't emulating EEPROM with flash memory(a useful exercise for you to undertake, or I'd do it for you), or using other tricks to maintain compatibility with EEPROM, which seems to be more "legacy" with every passing year.

1 Like

I took a look at the Atmel datasheet (438 pages of light reading!) :slight_smile: .

They do refer to 1K of EEPROM, distinct from Flash for program mem.

16/32KB of In-System Self-Programmable Flash;
512Bytes/1KB Internal EEPROM
Write/Erase Cycles: 10,000 Flash/100,000 EEPROM

A little confusing, section 28.6.5 mentions pages of EEPROM and filling a buffer, but p369 says:

The EEPROM array is programmed one byte at a time by supplying the address and
data together with the appropriate Write instruction.

Maybe page writes are an option for speed in bulk programming, and byte-by-byte for small updates?

Have a look at section 5.3 starting on page 20, section 28.6 is in reference to external programming.

1 Like

Efficiency of the code might depend a lot on how you are checking to see if any of the elements have changed, and how you would determine which element to write to EEPROM. If you are going to go through and individually check if each element has changed, it might be faster to just put() the entire array, in which case anything that has changed will be updated in EEPROM.

Probably the most efficient way would be to do an update to EEPROM at the point where an element changed, and do away with checking every 60 seconds. That way you already know which specific element to update, and don't have to worry about periodically checking for any changes.

1 Like

OK, thanks. That section seems pretty clear:

5.3 EEPROM Data Memory
The ATmega16U4/ATmega32U4 contains 512Bytes/1K bytes of data EEPROM memory. It is organized as a separate data space, in which single bytes can be read and written.

Yes, I see what you are saying. But for this project, there are only 4 elements that change semi-regularly. The other elements are config-style data that is fairly static. When a user changes those, I just update the data when they press a switch to ‘accept’ the change.

The 4 elements are a bit ‘tricky’ - these are to monitor how long a beer tap is open, and with a pre-programmed flow rate for that tap (part of the config data), I can determine how much beer was drawn from a keg, to alert the user when the keg is approaching empty. So while the tap is open, the data changes rapidly (20x/second). But I just update the variable. Every 60 seconds I check that it has changed by more than one ‘serving size’ before updating EEPROM. Even that is overkill for protecting against losing data if power was lost or the system crashed somehow. At most, I’d be off by one serving (of about 50 per keg). As long as the user (my Son-in-Law), knows the keg is near empty, w/o having to go in and lift it out to weigh it, he’s happy.

Unless an accidental programming error results in runaway writes.

1 Like

Yes, I always worry about that. I usually put in a delay when I can, and some display to make it obvious. If not, some sort of counter and timer. Of course, that has to be tested to make sure it works! I’ll double check my code.

As the code in Post #6 shows, that's exactly what EEPROM.put() does. It loops through the data structure byte by byte and writes them individually to consecutive EEPROM addresses using update().

But questions of EEPROM wear and efficiency aside, your alternate plan is flawed and won't work. Again, the function call EEPROM.put(0, Xyz) writes the entire array (byte by byte) to EEPROM starting at EEPROM address 0. That means element Xyz[0][0] of your int32_t array will occupy EEPROM addresses 0 - 3. Element Xyz[0][1] will occupy EEPROM addresses 4 - 7. Etc.

But, if you call EEPROM.put(0, Xyz[a][b]), it will put element Xyz[a][b] in EEPROM addresses 0 - 3. So, unless a and b are both zero, you will have corrupted your data.

Array element Xyz[a][b] belongs in EEPROM addresses (a * 5 + b) * 4 to (a * 5+ b) * 4 + 3.

1 Like

Correct, and that is what I have done. I only used ‘a’ and ‘b’ as placeholders for those calculations. But other readers may be confused by that, so your details may help them. In simple terms, since the int32 takes 4 bytes, the address needs to be incremented by 4 for each element, and since it is two dimensional, the math you show is what is needed.

Use the update method, it is the least 'wearing'.

As noted, EPROM.put() uses the updated() method, and it does the looping over multi-byte structures for you.

So, the only issue (if @NTL2009 wants do update array elements individually for efficiency) is to do the math on the array indices to get the correct EEPROM address.

1 Like