Like on a PC, data stored in RAM is lost during a reboot or when power is lost. Similarly, data that is stored on flash memory (e.g. a USB-Stick) remains intact.
Thus, we will store data that cannot be lost during power loss in the esp8266's flash memory. This is similar to storing data in EEPROM on an Arduino. So, when we are talking about EEPROM, we are actually referring to EEPROM emulation using the esp's flash memory.
This article is part of a complete ESP8266 reference you can find here.
As the esp8266 does not come with real EEPROM we emulate it using the built-in flash memory.
Depending on the esp8266 model the amount of flash memory can vary from 512KiB to 4MiB.
While for example, the esp-01 comes with 512KiB or 1MiB flash memory, the esp-12f has 4MiB built-in. You can find the exact amount built-into the model you are using in the datasheet.
Note: The flash memory is also used to store the program code itself.
Unlike using an Arduino we have to start the EEPROM emulation (before reading and writing) with
EEPROM.begin(SIZE);
This allocates a SIZE-bytes large block of RAM and copies the data from flash. SIZE can be anywhere between a minimum of 4 and a maximum of 4096.
From now on we work with the copy in RAM like we would with a normal array.
We now have to decide how much flash memory we want to use for EEPROM emulation. The maximum amount of flash we can use is one sector (4096B).
If we want to store standard data types, we can use the cheatsheet below:
1 byte | 2 bytes | 4 bytes | 8 bytes |
---|---|---|---|
bool | short | int | double |
char | uint16_t | long | long long |
byte | float | uint64_t | |
uint8_t | uint32_t |
However, the size of these data types can vary.
So, in general, the \(sizeof()\) function should be used to determine the amount of memory (in bytes) required to store a variable of a given type.
If we want to store an int we need the EEPROM size to be at least \(sizeof(int)\) bytes.
If we want to store an int and a 20 character long char array (string), we need \(sizeof(int)+20\cdot sizeof(char)\) bytes.
Note: As we will later see it is also important to remember which variable is stored at which address in EEPROM. For the second example, we could store the int at \(addr_1=0\) and the string at \(addr_2=sizeof(int)\).
To simplify reading and writing to EEPROM, we can use structs as shown in the next section.
Now that we know the required EEPROM size, we can use the Arduino EEPROM library to read and write bytes to and from EEPROM (flash memory).
As an example, we will now store the wifi SSID and password in EEPROM:
struct {
char mySSID[MAX_STRING_LENGTH] = "";
char myPW[MAX_STRING_LENGTH] = "";
} settings;
To start we will include the EEPROM library and use EEPROM.begin to allocate the required amount of memory.
#include <EEPROM.h>
[...]
EEPROM.begin(sizeof(settings));
Note: You can download the complete example below.
The simplest way to read data from EEPROM is using the EEPROM.get() function.
unsigned int addr = 0;
EEPROM.get(addr, settings); //read data from array in ram and cast it into struct called settings
If necessary, we can also read individual bytes from EEPROM using EEPROM.read():
unsigned int addr = 0;
for(int i=0; i<MAX_STRING_LENGTH; ++i){
settings.mySSID[i] = EEPROM.read(addr + i); //read individual byte from ram at (addr + i) and copy it to settings.mySSID[i]
}
addr += MAX_STRING_LENGTH;
for(int i=0; i<MAX_STRING_LENGTH; ++i){
settings.myPW[i] = EEPROM.read(addr + i); //read individual byte from ram at (addr + i) and copy it to settings.myPW[i]
}
As mentioned above, we are working with an array in RAM, not directly with the data stored in flash/EEPROM. We, therefore, have to use the EEPROM.commit() function to save changes in RAM to flash.
This will get clearer as you take a look at the two examples below:
The simplest way to store data in EEPROM is using the EEPROM.put() function:
unsigned int addr = 0;
EEPROM.put(addr, settings); //write data to array in ram
EEPROM.commit(); //write data from ram to flash memory. Do nothing if there are no changes to EEPROM data in ram
We can write individual bytes using EEPROM.write():
unsigned int addr = 0;
for(int i=0; i<MAX_STRING_LENGTH; ++i){
EEPROM.write(addr + i, settings.mySSID[i]); //write individual byte from settings.mySSID[i] to ram at (addr + i)
}
addr += MAX_STRING_LENGTH;
for(int i=0; i<MAX_STRING_LENGTH; ++i){
EEPROM.write(addr + i, settings.myPW[i]); //write individual byte from settings.myPW[i] to ram at (addr + i)
}
EEPROM.commit(); //write data from ram to flash memory. Do nothing if there are no changes to EEPROM data in ram
Write changes to the EEPROM data in RAM to flash memory.
If there are no changes in RAM, this function does nothing. If a single byte is changed in RAM, the complete EEPROM array in RAM is written to flash memory.
Calling EEPROM.end() is not required to read or write from/to EEPROM. All EEPROM.end is doing, is removing the cache array from RAM.
If for some reason, you want to "erase" the EEPROM, you can overwrite it with e.g. zeros.
The code is very simple:
for (int i = 0; i < SIZE; EEPROM.write(i++,0));
where \(\text{SIZE}\) is the EEPROM size.
This post is part of a complete ESP8266 reference/guide. You can find more information on how to use your ESP8266 module effectively at blog.hirnschall.net/esp8266/.
The content published on this page (with exceptions) is published under the CC Attribution-NonCommercial 3.0 Unported License. You are free to share on commercial blogs/websites as long as you link to this page and do not sell material found on blog.hirnschall.net/* or products with said material.
1: As an Amazon Associate I earn from qualifying purchases.