Arduino EEPROM Access
On an Arduino, access to the EEPROM can present difficulties if you want to store different types of data. In this blog post, I’ll show you a simple method to use when you have lots of structured data to store in EEPROM.
Firstly the Arduino EEPROM access routines only reads/writes single bytes but there are two templated functions that let you read/write anything. However, you need to know the offset of whatever you are accessing. Also, I find C++ templates a bit icky for this use case.
- One level deeper, avr-libc has a more complex API for other kinds of integers, and buffers. However, you still need to remember offsets & sizes.
- The EEMEM keyword works like PROGMEM to let you flag things as stored in the EEPROM. Which is nice, but you still need to pass size and offset whenever you read a value.
This technique uses a single ‘struct’ to represent the entire contents of your EEPROM, so you can then use macros to read and write fields.
You define a struct, in this example its called “__eeprom_data” that describes your EEPROM:
Then use macros eeprom_read & eeprom_write to read and write each field:
(Keep in mind, this is Arduino code, obviously if you’re using avr-libc directly then you can rewrite it for that.)
The downsides of this technique would appear to be the use of macro’s and for a single data type it would appear to be a bit of an overkill.
When you start up, you need to know if the data in EEPROM is data that your program saved, or something else. There are a few different ways to deal with this.
EEMEM provides a way for you to set default values easily in your code:
Via avr-objcopy & avrdude you can generate a .eep file and flash it to the AVR. This is nice, but it won’t work if you’re using the Arduino IDE because (as of version 0018) it doesn’t generate .eep files properly, and it also doesn’t support flashing them.
It’s a good option if you’re using your own Makefile, though.
The other way is to check for and expect a “magic” value somewhere in the EEPROM data. Something like:
// Change this any time the EEPROM content changes
magic_number = 0x5432;
// should be set to magic_number
(magic != magic_number)