The Arduino EEPROM (Electrically Erasable Programmable Read
Only Memory) is a high endurance Flash memory block. It is dedicated to
saving data between sessions (power down and power up of the
microcontroller).
The EEPROM memory on a microcontroller can serve two very useful calibration purposes.
First, it allows storing calibration parameters so they don't need to
be re-done each time the microcontroller restarts. For example, you
could save the calibrated offset value for an MCP4922 DAC that is being used with an opamp. Then on restart, it would load the stored value and maintain the calibration.
Second, the EEPROM can hold user-entered data so it doesn't get lost
on restart. For example, if your program prompts the user to input
various configuration settings, you could store those entries in the
EEPROM. Then when the program launches again later, it can load the
saved data from EEPROM rather than making the user re-enter all the
configuration each time. This provides a nicer user experience by
preserving their previous inputs.
Flash Types
There are two rewritable memory types on a microcontroller that are useful to compare: Flash memory and EEPROM.
Flash memory is where the microcontroller program code is stored. It
can be re-written, such as when downloading a new program to the
Arduino. However, Flash memory has a lower rewrite capability compared
to EEPROM. Over time, repeated rewriting of Flash will cause wear and
eventual failure.
In contrast, EEPROM (electrically erasable programmable read-only
memory) has a much higher maximum rewrite cycle count. It is well-suited
for saving calibration constants or other data that needs to persist
between runs of a program without wearing out over many rewrite cycles.
On this page your can find out how to preserve the life of EEPROM as
well as sketches showing how to save and restore multiple data elements.
There are two rewritable memories and it is useful to compare their
capabilities. The Flash memory area of the microcontroller (that stores
your program) is capable of being
re-written (when you download a new program to the Arduino!). This
memory, however, has a lower rewrite capability:
Device
Memory Type
Size
Rewrites
AtMega328P (Arduino Uno)
Flash
32kB
>10,000
AtMega328P (Arduino Uno)
EEPROM
1kB
>100,000
Flash lifetime
A useful thing to do, is to see how long
normal Flash memory will last if you write to it 10 times per day. It turns out that it will last at least
10000.0/10.0 = 1000 Days or 2.7 years). Of course you won't update a
program every day and you will use a new device for new projects, so it
will last far longer than that.
EEPROM lifetime
The EEPROM is far better. For the same example of writing it 10 times a day the EEPROM life will be
100000/10 # 10000 Days or 27 Years!
How to preserve EEPROM
I was once at a firm that managed to have their units randomly fail.
The EEPROM was being written continuously to the
same location to save data as parameters changed. The
problem was that the data was always written every time round the program loop, so even with the huge
lifetime of the EEPROM it was written so much that the EEPROM wore out.
The solution they chose was to move the starting write address after
every block of data was written so that the same area of EEPROM was not
continuously used; Extending the life of the EEPROM.
A better way is to make sure you only write to the EEPROM at a
defined time. For instance if a user starts a calibration sequence -
only write it once after that has ended. Alternatively update parameters on brown-out detection or power down initiation.
Never write to the same address in EEPROM memory from within a for loop!
Warning: Don't make your program continuously write to EEPROM.
Note: Reading from the EEPROM does not degrade the memory. You can read an EEPROM address as many times as you want.
TIP: To extend EEPROM life first
read the contents to be written - if
it is the same as the value you want to write, then don't write to it! -
See functions update() and put() that perform a Read-Before-Write.
TIP: Each time you write a set of data - read it back to ensure it
was written correctly. If it fails then retry. If there are multiple
failures then generate an error e.g an message to a screen or light a
red LED.
A write of one byte takes 3.3ms [source Arduino documentation] - however it seems faster (see output from programs below).
Arduino EEPROM functions
EEPROM Read and Write Bytes
The basic unit of an EEPROM transaction is a byte. To read and write these bytes you can use the following functions:
EEPROM.write(address,byteValue);
EEPROM.read(address);// returns a byte.
EEPROM Write a Changed byte
EEPROM.update(address, bytevalue);
This function will only perform a write operation if the current
value is not the same as bytevalue. So it saves you from
wearing out EEPROM if you try and write the same byte to the EEPROM.
Really, this is the function you should use to preserve the EEPROM
memory. The only reason not to do so, is that it must perform a read
first so it will be slower than an EEPROM.write operation.
EEPROM Write Standard type or Structure
It is Ok writing bytes, but there's an easier way to write a set of
data to the EEPROM and that us by using the put() function (get is the
equivalent for retrieval).
The put function writes out a set of bytes using the update function.
In addition it measures the size of the data type being used to write
out the correct number of bytes.
You can use this function to write out an char, int, long or float
type object without knowing the number of bytes used by the type object.
So this function is portable across different compilers (that use
different type sizes).
The really useful point about this function is that it can also write
out your own defined types e.g. if you create a struct type (with lots
if variables inside) then it will write a variable of this type to
EEPROM without you having to know the number of bytes that the type
occupies.
The upshot is, if you bundle your data into a structure then it is easy to put and get it, to and from EEPROM.
The previous member functions are useful for writing single bytes or
single struct objects to/from EEPROM but quite often want to switch
between sets of
data (or store more than just a single variable).
This is especially useful for a system where you are trying out different options
(and you don't want to recompile each time just to change a few
control parameters!).
You just want to select from a set of previously saved data.
Single Type Method Sketch1
The Idea here is to store a set of simple type variables sequentially in the EEPROM at a specific EEPROM address.
Just attach a push button connected to ground and pin 5 of the
Arduino. On start up the EEPROM values are retrieved from the EEPROM and
sent to serial Monitor.
When you push the button random values are saved to the EEPROM. To
retrieve the values simply press the reset button on the Arduino and
these same numbers are displayed (having been read from the EEPROM).
When you hit the button you can also see write execution time.
// Storing variables in EEPROM
// Sequential read / write of variables.
#include <EEPROM.h>
#define BUTTON_TEST 5
#define EEADDR 166 // Start location to write EEPROM data.
staticunsignedintminx,maxx,miny,maxy;
voidshow_vars(void){
Serial.print("MIN x ");Serial.println(minx);
Serial.print("MAX x ");Serial.println(maxx);
Serial.print("MIN y ");Serial.println(miny);
Serial.print("MAX y ");Serial.println(maxy);
}
voidsetup(){
pinMode(BUTTON_TEST,INPUT_PULLUP);
pinMode(LED_BUILTIN,OUTPUT);
digitalWrite(LED_BUILTIN,LOW);
Serial.begin(115200);
Serial.println("EEPROM variable read and write.");
// Read EEPROM
intEEAddr=EEADDR;
EEPROM.get(EEAddr,minx);EEAddr+=sizeof(minx);
EEPROM.get(EEAddr,maxx);EEAddr+=sizeof(maxx);
EEPROM.get(EEAddr,miny);EEAddr+=sizeof(miny);
EEPROM.get(EEAddr,maxy);EEAddr+=sizeof(maxy);
show_vars();
}
voidloop(){
staticunsignedlongtimeWas,timeNow;
intr=random(100,65535);
minx=r;
maxx=r+1;
miny=r+2;
maxy=r+3;
Serial.println("Press button to write to EEPROM");
if(digitalRead(BUTTON_TEST)==0){
digitalWrite(LED_BUILTIN,HIGH);
intEEAddr=EEADDR;
timeWas=micros();
EEPROM.put(EEAddr,minx);EEAddr+=sizeof(minx);
EEPROM.put(EEAddr,maxx);EEAddr+=sizeof(maxx);
EEPROM.put(EEAddr,miny);EEAddr+=sizeof(miny);
EEPROM.put(EEAddr,maxy);EEAddr+=sizeof(maxy);
timeNow=micros();
Serial.println("EEPROM Written");
show_vars();
Serial.print("EEPROM Write time (us) ");
Serial.println(timeNow-timeWas);
Serial.print("EEPROM Write time per byte (us) ");
Serial.println((timeNow-timeWas)/(4*sizeof(minx)));// same type.
delay(500);
digitalWrite(LED_BUILTIN,LOW);
}
delay(500);
}
[eeprom1.ino]
Here's an example of the output from the serial monitor:
Press button to write to EEPROM
EEPROM Written
MIN x 58478
MAX x 58479
MIN y 58480
MAX y 58481
EEPROM Write time (us) 23300
EEPROM Write time per byte (us) 2912
Press button to write to EEPROM
Press button to write to EEPROM
Press button to write to EEPROM
Press button to write to EEPROM
EEPROM variable read and write.
MIN x 58478
MAX x 58479
MIN y 58480
MAX y 58481
Press button to write to EEPROM
The lower text beginning 'MIN X' is the read-back output after hitting
the reset button. The first one is the 'write action' after hitting the
push button.
Struct type Method Sketch2
The Idea here is to use a structure to store data at a specific EEPROM address.
Using a struct object allows you to group variables together and use
the EEPROM.put() and get() to access the EEPROM. These functions make it
trivial to store and retrieve the structure data to/from the EEPROM.
The following program is very similar to the above but uses a struct
variable instead of lots of different ones. Note how you could use
multiple struct variables in the program since pointers are used to
display the contents of the struct variable 'StoreData'.
// Storing struct variables in EEPROM
// Sequential read / write of variables.
#include <EEPROM.h>
#define BUTTON_TEST 5
#define EEADDR 166 // Start location to write EEPROM data.
// Put variables into structure.
structStoreData_s{
floatkp;// kp, ki and kd store normalised values to 1000ms
floatki;// They are recalculated in the PID algorithm
floatkd;// proportional to the sample time.
intdt;// SampleTime
intlimitR;// limit roll
intlimitP;// limit pitch
};
StoreData_sStoreData={1,0.1,0,1000,30,60};
voidshow_vars(StoreData_s*p){
Serial.print("Kp ");Serial.println(p->kp);
Serial.print("Ki ");Serial.println(p->ki);
Serial.print("Kd ");Serial.println(p->kd);
Serial.print("dt ");Serial.println(p->dt);
Serial.print("LR ");Serial.println(p->limitR);
Serial.print("LP ");Serial.println(p->limitP);
}
voidsetup(){
pinMode(BUTTON_TEST,INPUT_PULLUP);
pinMode(LED_BUILTIN,OUTPUT);
digitalWrite(LED_BUILTIN,LOW);
Serial.begin(115200);
Serial.println("EEPROM struct read and write.");
// Read EEPROM
EEPROM.get(EEADDR,StoreData);
show_vars(&StoreData);
}
voidloop(){
staticunsignedlongtimeWas,timeNow;
intr=random(100,65535);
StoreData.kp =r++;
StoreData.ki=r++;
StoreData.kd=r++;
StoreData.dt=r++;
StoreData.limitR=r++;
StoreData.limitP=r++;
Serial.println("Press button to write struct to EEPROM");
if(digitalRead(BUTTON_TEST)==0){
digitalWrite(LED_BUILTIN,HIGH);
timeWas=micros();
EEPROM.put(EEADDR,StoreData);
timeNow=micros();
Serial.println("EEPROM Written");
show_vars(&StoreData);
Serial.print("EEPROM Write time (us) ");
Serial.println(timeNow-timeWas);
Serial.print("EEPROM Write time per byte (us) ");
Serial.println((timeNow-timeWas)/(sizeof(StoreData)));delay(500);
digitalWrite(LED_BUILTIN,LOW);
}
delay(500);
}
[eeprom2.ino]
Here an example of the output from the serial monitor:
Press button to write struct to EEPROM
EEPROM Written
Kp -4639.00
Ki -4638.00
Kd -4637.00
dt -4636
LR -4635
LP -4634
EEPROM Write time (us) 46596
EEPROM Write time per byte (us) 2588
Press button to write struct to EEPROM
Press button to write struct to EEPROM
Press button to write struct to EEPROM
Press button to write struct to EEPROM
Press button to write struct to EEPROM
Press button to write struct to EEPROM
Press button to write struct to EEPROM
EEPROM struct read and write.
Kp -4639.00
Ki -4638.00
Kd -4637.00
dt -4636
LR -4635
LP -4634
Press button to write struct to EEPROM
The top data is displayed after pressing the button while the lower data is displayed after pressing reset on the Arduino.
Note: Write times will vary if the same data is detected in the
EEPROM. For accurate timing use the write function (you would write your
own version of put() that does not perform a read).
Frequently Asked Questions
How to reset an EEPROM.
The EEPROM can be erased during programming using the chip erase function.
The EEPROM does not really need resetting since it stores whatever
was programmed into it (there is no EEPROM reset operation). You are
probably wanting to initialise it.
One way is to perform a write to EEPROM during normal program
operation - or use a button input to indicate rewrite (as in above
programs - but choose another button).
Alternatively create a separate sketch and loop 0 to 999, write each byte as 0xFF.
Note: The erased state of the EEPROM is 0xff.
How to clear Arduino EEPROM.
You have to to write to it as above or use the chip erase function (during serial programming).
How to erase Arduino EEPROM.
Same as above.
Arduino EEPROM vs Progmem
As described earlier, Flash memory (PROGMEM) has a lower lifetime
than EEPROM. So EEPROM is useful for data that should be stored between
sessions (or logged in a data logging application).
Arduino EEPROM vs Flash
Same as above.
Arduino EEPROM vs SD card.
The advantage of an EEPROM is that it is fast .
The disadvantage of an EEPROM is that it is small (1k Byte)
The advantage of an SD card is that it is huge (Giga Bytes).
The disadvantage of an SD card is that it is slow.
The disadvantage of an SD card interface is that it needs a RAM buffer (probably 2 of about 512 bytes of SRAM each).
The SD card takes time to write - hence the need for a double buffer. One buffer is updated while the other is written.
Comparisons of EEPROM member functions
Arduino EEPROM put vs update
update() operates on a single byte.
It reads, and then writes to an address only if the byte is different.
This is the byte primitive function used by put().
put() writes multiple bytes starting from an address.
The number of bytes written is the size of the type.
put() uses the update function
(which only overwrites data if it has changed - to preserve memory).
Arduino EEPROM update vs write
update() operates on a single byte.
It reads, and then writes to an address only if the byte is different.
This is the byte primitive function used by put().
write() operates on a single byte.
It writes a single byte to an address.
Arduino EEPROM get vs read
read() operates on a single byte.
It reads a single byte from an address.
get() reads multiple bytes starting from an address.
The number of bytes read is the size of the type.
Arduino EEPROM write vs put
write() operates on a single byte.
It writes a single byte to an address.
put() writes multiple bytes starting from an address.
The number of bytes written is the size of the type.
put() uses the update function
(which only overwrites data if it has changed - to preserve memory).
Conclusions
The Arduino EEPROM library provides easy access to read and write the
EEPROM memory. The examples in this page show you how to write
individual bytes as well as complete structured data to EEPROM memory.
In this page you found out that the Arduino EEPROM can be extremely
useful in your projects. It allows you to save data between power
cycles, allowing parameters, calibration values and other settings to
persist for your projects.
Through the examples and explanations, you saw how to read and write
single bytes as well as structures containing grouped data to sequential
EEPROM addresses. The put() and get() Arduino EEPROM functions
let you store and retrieve structured data very easily and actually stop
too many EEPROM writes in a limited way - they do a pre-read to make
sure the data is new.
Tips were provided on how you can maximize EEPROM lifetime through
techniques like delaying writes and avoiding consecutive overwriting of
addresses in your code. Comparisons to flash memory highlighted EEPROM's
significantly higher rewrite endurance for your use.
The provided examples demonstrate the core EEPROM programming techniques
you can use - from saving and retrieving simple variables, through to
saving and retrieving complete structured data.
This provides you with useful starting point for adding EEPROM data
storage methods into any of your Arduino projects, whether sensors,
industrial equipment or data loggers.
Written by John Main who has a degree in Electronic Engineering.
Note: Parts of this page were written using claude-instant
as a research assistant.
How to get accurate DHT22 digital humidity sensor readings with an Arduino. Did you know it also measures temperature as Well? Find out why, in this page...
A PIR sensor lets your Arduino sense movement without contact. This tutorial covers PIR sensor basics, connecting one to an Arduino board and coding a motion detector.
Arduino Hall Effect Sensor: Add magnetic sensing superpowers to your Arduino projects with an easy-to-use hall effect sensor. With full code and layout...
Comments
Have your say about what you just read! Leave me a comment in the box below.
Don’t see the comments box? Log in to your Facebook account, give Facebook consent, then return to this page and refresh it.