How to store a JSON document in EEPROM?
What is EEPROM?
EEPROM is a non-volatile memory supported on many Arduino boards. “Non-volatile” means that it keeps its content when you power off the device.
The table below summarizes the capacity of the popular IoT boards:
Board | EEPROM capacity |
---|---|
Arduino Leonardo | 1 KB |
Arduino Mega 2560 R3 | 4 KB |
Arduino Micro | 1 KB |
Arduino Nano | 1 KB |
Arduino Nano Every | 256 B |
Arduino UNO | 1 KB |
Arduino UNO WiFi | 256 B |
Arduino Yún | 1 KB |
SparkFun RedBoard | 1 KB |
Teensy 2.0 | 2.5 KB |
Teensy 3.2 | 2 KB |
Teensy 3.5 | 4 KB |
Teensy 3.6 | 4 KB |
Teensy 4.0 | 4 KB |
Teensy 4.1 | 4 KB |
Teensy LC | 128 B |
Teensy++ 2.0 | 4 KB |
Several other platforms support an emulation for EEPROM. For example, ESP32 uses a file in the Flash memory to replace EEPROM.
EEPROM is a perfect location to store your application configuration, and JSON is an excellent choice for the configuration format.
The only problem with EEPROM is that it’s slow to read and extremely slow to write.
How to use EEPROM?
The EEPROM is not mapped in the memory address space, so you must use dedicated functions. To write a byte to EEPROM, you must write:
EEPROM.write(address, value);
To read a byte from EEPROM, you must write:
value = EEPROM.read(address);
How to use EEPROM with ArduinoJson?
ArduinoJson doesn’t know about EEPROM.read()
and EEPROM.write()
, so it cannot natively use EEPROM.
However, serializeJson()
and deserializeJson()
support a generic interface that we can be used for virtually any kind of storage: Stream
.
It’s quite easy to create a Stream
class that calls EEPROM.read()
and EEPROM.write()
, but you don’t need to write it yourself because the StreamUtils library already provides an EepromStream
class that does exactly this.
To write a JSON document to EEPROM, use:
EepromStream eepromStream(address, size);
serializeJson(doc, eepromStream);
As you can see, we pass two arguments to the constructor of EepromStream
: the address and the size of the region of EEPROM that we want to expose as a Stream
.
If you don’t know what to use for address
, use 0.
If you don’t know what to use for size
, use the value from the table above. On some platforms, you can use EEPROM.length()
, which returns the quantity EEPROM available on the board.
Similarly, you can read a JSON document from EEPROM with:
EepromStream eepromStream(address, size);
deserializeJson(doc, eepromStream);
Of course, don’t forget to include StreamUtils.h
at the top of your source file.
StreamUtils is a powerful library that deserves more attention. Please give it a star to spread the word.
Notes for ESP8266 and ESP32
ESP8266 and ESP32 don’t have a real EEPROM, but they emulate one:
- ESP8266 uses a 4KB sector in the SPI Flash
- ESP32 uses a blob in the Non-volatile storage (NVS)
To use the EEPROM emulation on these platforms, you must initialize the EEPROM library:
EEPROM.begin(512);
In this example, 512
is the amount of memory that you reserve for the EEPROM emulation.
The documentation says you can go up to 4096 on ESP8266 and 508000 on ESP32.
The second thing you must do is to “commit” the changes (i.e., to write the cache to the non-volatile memory). You do it like so:
EEPROM.commit();
To make your code portable (i.e., work on other platforms as well), you can use EepromStream::flush()
instead:
eepromStream.flush(); // (calls EEPROM.commit() on ESP)
This function calls EEPROM.commit()
on ESP and does nothing on other platforms.