Tuesday, December 23, 2014

Arduino EEPROM - Power Trip

I've continued to work on the rocket telemetry platform. One of my last issues (beyond frying my Nano by back-feeding power) was that the combination of GPS + IMU + microSD card was simply consuming more power than the little Nano could produce. Right now I'm working on a small instrument package for a model rocket payload, so I really didn't want to go to all the trouble of adding a power regulator and such.

Well, since I fried my nano and missed the launch date anyhow, that gave me some time to noodle over the issue. In reading one of my Arduino books (Exploring Arduino, by Jeremy Blum), I came across a discussion of EEPROMs. That led to a fair amount of research and I ultimately concluded that, for a rocket, using an EEPROM is a great idea!

What is an EEPROM? 

An EEPROM chip is a small non-volatile memory chip. Each Arduino has between 512k and 1024k EEPROM built in, and it's rarely ever used. For less than $5, you can buy an external EEPROM and use it for the same purpose, and the external EEPROMs are generally larger (I bought an 8k RCA chip from Ballard Supply (which just happens to be in my home town). I haven't used the chip yet, but the onboard EEPROM has worked like a charm.

This will work great for a rocket project, where I am gathering minimal telemetry data and the flight is short. For the balloon platform, I'm still planning to use the microSD reader along with a Mega - more memory, more expansion.

What's in a Structure?

With the storage issue solved, at least partly, my next challenge was writing data to the card. The built-in EEPROM.h library is a byte-by-byte read/write tool, and the data I'm storing is variable in length and format so I was stumped by how I could store and retrieve that data. My original thought was to store it as a long string, which is how I planned to do it with the microSD card. The challenge was that the string length would vary as numbers had more or fewer digits. Plus, building strings on Arduino can suck up memory. And along came... the struct. I've never really messed with structs before, but they are a sort of 'uber' datatype, which contains data within. In essences, it is a complex data type which includes datatypes within.

A struct looks something like this:
// Struct for storing a blog of data
struct store_t {
    float gpsLat, gpsLon;
    float gpsSpeed, gpsAlt;
    float imuX, imuY, imuZ;
    float imuPress, imuAlt;
  } storeBlob;

With the EEPROManywhere library from Arduino Playground, I can actually write an entire struct directly into the EEPROM. No mess, no fuss, no pointers or array indeces. Just write and read.

Writing to the EEPROM

With some research in the Adafruit GPS library, I realized every bit of data I'm writing is a float and, since floats have fixed length, my struct is a predictable 36 bytes, every single time. That means I have a predictable length and, therefore, a predictable starting point to read the next struct.

With a struct of 36 bytes, I can write 28 'blobs' to the Arduino's internal EEPROM, and 227 blobs to an 8K EEPROM chip. I anticipate about a 30-second flight, so I could write 7 times per second (if the Arduino could keep up). I intend to write 2 times per second, not much more.

Reading from the EEPROM

The EEPROManything library is dirt-easy to use. To write, you give it a starting location and the object (struct, in my case). To read, give it a starting location and an object to store the result in (again, a struct). So writing looks like this:
EEPROM_writeAnything(0,storeBlob);

And reading looks like this
EEPROM_readAnything(0,storeBlob);

The only challenge in all of this will be to keep track of the starting point, but it's actually straightforward, just have to careful of 0-based indexing.

Test Code

Here is some test code for writing and reading:
#include <EEPROManything.h>
#include <EEPROM.h>


// Struct for storing a blog of data
struct store_t {
    float gpsLat, gpsLon;
    float gpsSpeed, gpsAlt;
    float imuX, imuY, imuZ;
    float imuPress, imuAlt;
  } storeBlob;
  
  
void setup ()
{
  Serial.begin(9600);
  Serial.println ("Creating storeBlob");
  storeBlob.gpsLat = 4026.1162;
  storeBlob.gpsLon = 11202.8095;
  storeBlob.gpsSpeed = 141.2;
  storeBlob.gpsAlt = 1506.80;
  storeBlob.imuX = 13.2;
  storeBlob.imuY = 4.2;
  storeBlob.imuZ = 97.9;
  storeBlob.imuPress = 847.69;
  storeBlob.imuAlt = 1547.39;
  
  // Calculate length
  Serial.print("storeBlob length:" ); Serial.println(sizeof(storeBlob));
  
  // Now write to EEPROM
  Serial.println (EEPROM_writeAnything(0,storeBlob));
}

void loop ()
{
  
}



#include <EEPROManything.h>
#include <EEPROM.h>


// Struct for storing a blog of data
struct store_t {
    float gpsLat, gpsLon;
    float gpsSpeed, gpsAlt;
    float imuX, imuY, imuZ;
    float imuPress, imuAlt;
  } storeBlob;
  
  
void setup ()
{
  Serial.begin(9600);
  Serial.println ("Reading storeBlob");
  
  // Read from EEPROM
  EEPROM_readAnything(0,storeBlob);
  
  // Write to screen
  Serial.print("Lat:.. ");  Serial.println(storeBlob.gpsLat);
  Serial.print("Lon:.. ");  Serial.println(storeBlob.gpsLon);
  Serial.print("Speed: ");  Serial.println(storeBlob.gpsSpeed);
  Serial.print("Alt:.. ");  Serial.println(storeBlob.gpsAlt);
  Serial.print("X:.... ");  Serial.println(storeBlob.imuX);
  Serial.print("Y:.... ");  Serial.println(storeBlob.imuY);
  Serial.print("Z:.... ");  Serial.println(storeBlob.imuZ);
  Serial.print("Press: ");  Serial.println(storeBlob.imuPress);
  Serial.print("Alt:...");  Serial.println(storeBlob.imuAlt);
}

void loop ()
{
  
}