Organized EEPROM storage

Introduction

EEPROM is a permanent memory. It will remain even after the Arduino is restarted. It can be reprogrammed around 100,000 times, so it is substantially less resilient than the flash storage or a hard drive. It is also kind of slow (3ms per byte). The Ardiono Uno has 1KB of EEPROM. 

The compiled program is uploaded to flash storage (not EEPROM), which is faster and larger. So, if you can, it is better to write keep as much as possible in the C++ file.

Sometimes it can be convenient or more reliable to use the EEPROM. You could log sensor readings to EEPROM so that the data will still be there even if it loses power. Alternatively, you could use an SD shield and get more, more reliable, and more portable storage.

If you have multiple Arduinos for a project that do the same tasks, but want a way to differentiate them despite having identical programming, you could flash an ID number to the EEPROM.

Simple Usage

Reader

This reader is used after the writer to get the value from the EEPROM:

#include <EEPROM.h>

int address = 0;

void setup() {
  Serial.begin(9600);

int value = EEPROM.read(address);
Serial.print("Read: ");
Serial.println( value );
}

void loop() {
}

Writer

Here is a simple writer that just writes an int of 123 to the first byte in the EEPROM:

#include <EEPROM.h>

int address = 0;

void setup() {
  Serial.begin(9600);

int value = 123;
EEPROM.write(address, value);

Serial.println("Done writing");
}

void loop() {
}

Structured and Organized Storage

A cool trick in C++ is to sort of overlay a structure onto an area of memory - taking advantage of data structure alignment. This organization method is used heavily in file manipulation, for example: reading a bitmap.

The cool thing about this is that you can mix datatypes and not have to worry about reading things in the right order. As long as the struct remains the same when you read it after you write it.

You might see this struct example and want to use it as a seperate class in a seperate header, but I didn't do that primarily because it depends so heavily on the struct you make. It is actually possible to make an encapsulated version of this by using templates. A template is a way to pick a data type for some elements in a class. Some good examples of ways they are useful are vectors and linked lists.

This class should only be used once in a project without any modification. By simply adding a fixed offset to the EEPROM.read and EEPROM.write methods, multiples could be used.

#include <EEPROM.h>

typedef struct                    /**** EEPROM STORAGE STRUCTURE ****/
{
//stuff in here gets stored to the EEPROM unsigned short count; /* A count of values stored */ long sum; /* A running total of values */ char str[10]; /* A string label */ int values[100]; /* Array of values collected */ boolean complete; /* a flag for whether gathering is finished */ } EEPROMSTORAGE; // a class to manage the struct class Permanent { private: // the actual eeprom gets stored here // the struct is overlayed onto this storage byte buffer[ sizeof(EEPROMSTORAGE) ]; public: Permanent(); //constructor - reads the eeprom void write(); //a function to write to the eeprom
//this pointer makes the buffer's contents easily accessed EEPROMSTORAGE * store; }; //read the eeprom into the buffer Permanent::Permanent() { for( int i = 0; i < sizeof(EEPROMSTORAGE); ++i ) { buffer[i] = EEPROM.read(i); } //overlay the pointer to the storage onto the buffer store = (EEPROMSTORAGE *) buffer; } //write the buffer into the eeprom //be careful writting too often to the eeprom. It only has 100,000 writes void Permanent::write() { for( int i = 0; i < sizeof(EEPROMSTORAGE); ++i ) { EEPROM.write(i, buffer[i]); } } //make an instance of the managing class called eeprom (in lower case!) Permanent eeprom; //this is just a demo of how you would access and write the data void setup() { Serial.begin(9600);
//check to see what was already in the eeprom. serial print it. Serial.println( eeprom.store->str );
//fill the buffer's store with some data eeprom.store->count = 0; strcpy( eeprom.store->str, "Hello!"); for(int i = 0; i < 50; ++i ) { int sensorVal = i*3+2; eeprom.store->values[i] = sensorVal; eeprom.store->sum += sensorVal; eeprom.store->count++; } eeprom.store->complete = true;
//write the buffered data to the eeprom eeprom.write(); } void loop() {}