Saving LED Configurations to Arduino Using EEPROM

While working on the next release of PixelMaestro, I came across a significant problem: I had a system in place for storing configurations as byte arrays, and I had a system in place for reading in and executing these arrays. This was perfectly fine on a computer, since I could save these arrays to a file. But on an Arduino (where files aren’t a thing), where and how was I supposed to store a series of bytes that would persist across reboots? Enter EEPROM.

What is EEPROM?

EEPROM (short for electrically erasable programmable read-only memory) is a special type of memory that stores data after it’s been powered off. The data is non-volatile, meaning it will still be there even if the device loses power. Any values written to EEPROM persist until you overwrite it, making it ideal for storing long-term data. Think of it as a tiny, fast hard drive.

Arduinos have a built-in EEPROM that stores anywhere from 512 to 4096 bytes (0.5 – 4KB) depending on the type of Arduino. The Arduino library treats EEPROM as an array of bytes which you can access using normal array indices. The only limitation is the lifespan: the Arduino EEPROM has a maximum lifespan of 100,000 writes, which isn’t much if you plan on writing to it frequently. However, the real-world life expectancy can end up being much longer than this.

EEPROM in Action

The way I use EEPROM is fairly straightforward: read in a series of bytes sent over a serial connection and store them to EEPROM. When starting the Arduino, check EEPROM to see if we have any data stored in it, and if we do, execute it. You can find the full Arduino sketch by clicking here.

Wait, What’s Going On?

There’s a lot going on in that sketch that’s specific to PixelMaestro, so this section is meant to provide some context.

PixelMaestro uses a system called Cues to send commands over a serial connection. A Cue is just an array of bytes that can be translated by the receiving end back into a valid command. Each Cue begins with the bytes “PMC” (short for PixelMaestro Cue), which indicate the start of the Cue. An object called a CueController reads in each individual byte, reconstructs the entire Cue, then runs it as a command.

In this sketch, multiple Cues are being sent to the Arduino all at once. A collection of multiple Cues is known as a Cuefile. The Cuefile begins with the bytes “ROMBEG” and ends with the bytes “ROMEND”, indicating the start and end of the Cuefile (this is important once we start writing the Cuefile to EEPROM). Once the Cuefile is written completely to EEPROM, we can then run the contents of EEPROM through the CueController as if we were running a normal Cuefile.

Stepping Through the Sketch

The most important part of the sketch is the run_eeprom_cue() function. This steps through each byte in EEPROM and passes it to the CueController. The CueController reconstructs any valid Cues it finds and executes them.

void run_eeprom_cue() {
  for (int index = 0; index < EEPROM.length(); index++) {
    maestro.get_cue_controller()->read(EEPROM[index]);
  }
}

In setup(), we run this method if we detect an existing Cue inside of it. To do this, we check the first three bytes for the “PMC” header found in every Cue:

void setup() {
  if (EEPROM[0] == 'P' && EEPROM[1] == 'M' && EEPROM[2] == 'C') {
    run_eeprom_cue();
  }
}

loop() is where things get a bit trickier. Remember how the Cuefile starts with “ROMBEG” and “ROMEND”? These actually act as triggers that tell the Arduino when to start writing serial data to EEPROM and when to stop. Without these flags, we would just keep writing serial input to EEPROM indefinitely. Not only would this needlessly shorten the life of EEPROM, but it would screw with our Cuefile.

To track the flag, we use the boolean variable “eeprom_read”. If eeprom_read is true, any serial input we detect is written to EEPROM. The “ROMBEG” header sets eeprom_read to true, and the “ROMEND” header sets it to false. After reading in “ROMEND”, we immediately run the Cuefile. The sketch includes some additional variables to detect the flags, and track the current index in EEPROM.

// In loop():
// If we read in the EEPROM start header, write the following serial data to EEPROM.
if (header[0] == 'R' && header[1] == 'O' && header[2] == 'M' && header[3] == 'B' && header[4] == 'E' && header[5] == 'G') {
  eeprom_read = true;
}
// If we read in the EEPROM end header, stop writing to EEPROM and reset the eeprom read index.
else if (header[0] == 'R' && header[1] == 'O' && header[2] == 'M' && header[3] == 'E' && header[4] == 'N' && header[5] == 'D') {
  eeprom_read = false;
  eeprom_index = 0;
  run_eeprom_cue();
}

Now, whenever we restart the Arduino, we immediately detect the Cuefile in EEPROM and run it against our CueController. Listening for new Cues is optional once the Cuefile is baked into EEPROM, but keeping this logic means you can change the Cuefile at any time.

What’s the Use?

My goal was to create a code-free way to configure and change LED animations on an Arduino-powered device, and EEPROM was the way to do it. Instead of having to replicate a Maestro configuration in an IDE, you can now upload an animation designed in PixelMaestro Studio directly to an Arduino where it will persist across reboots. My aim now is to refine the process, simplify the interface, add error checking, and reduce the memory footprint on the Arduino side.

As always, you’re welcome to clone or fork the repository and play with the code yourself. The core library is available here, and the companion GUI app is available here. The Arduino sketch is available here, and the GUI class that interacts with it is available here. You can learn more about using EEPROM on Arduino here.

Happy hacking!

Share your thoughts

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s