Efficient reading and writing to EEPROM

I want to keep track of the value of six long variables (4 bytes each) in EEPROM so if the power goes out I can pickup where I left off. The values get updated only once every 30 seconds (these are test cycle counters) so I have no speed constraints but I want to make sure I don't lose track of the number of completed cycles. To that end I plan on also writing another 2 bytes of data as a CRC checksum of the six values and storing that in EEPROM as well (just in case the power goes out at the moment I am writing the six variables to EEPROM and they get corrupted).

So my question is this: how do I declare the six variables so they reside in contiguous RAM space so when I calculate the CRC I can just start at one byte and run through the 15 others using some type of an indexing pointer? This would simplify the CRC calculation and make the writing to EEPROM quick and painless.

I know how to manipulate bytes in SPIN (the Parallax Propeller language) but I am just now trying to learn how to do this with the Arduino IDE C language. From what I have read so far something like a "union" or a "typedef struct" might be what I am looing for but not sure which one to choose (and why).

Any help or a linkto a good online reference would be greatly appreciated.

Declare the variables in an array, then you can cast the array to a byte array when needed:

#define NUM_COUNTERS 6
long cycle_counters[NUM_COUNTERS];

void write_counters ()
{
  byte * counters_as_bytes = (byte*)cycle_counters;
  for (byte i = 0 ; i < NUM_COUNTERS*sizeof(long); i++)
    EEPROM.write (base_address+i, counters_as_bytes[i]) ;
}

That sort of thing.

Note that EEPROM has a wear-life of 100,000 cycles, and writing every 30 seconds will use that up in a month.

You could monitor Vcc.

When it gets low, assuming power failing, write the counters, no CRC needed no writing every 30 seconds.

FYI Power loss discussion (one way)

@Mark, nice code.

Note that EEPROM has a wear-life of 100,000 cycles, and writing every 30 seconds will use that up in a month.

Yes, I read that so I am also including an int at address 0 that will be used as the value of the beginning of the completed cycle counts. I will change it once I exceed the 100,000 mark.

I discovered the EEPROM.put() and EEPROM.get() functions along with a typedef will get me exactly what I need. Here is my very basic test code:

#include <EEPROM.h>

/*
 * EEPROM Map:
 *    EEPROM Addr  |   Contents
 *              0-3 Long value of address of completed cycles (ADDR)
 *              4-7 Long value of Target Cycles of test bank 1
 *             8-11 Long value of Target Cycles of test bank 2
 *            12-15 Long value of Target Cycles of test bank 3
 *            16-17 Int value of CRC of bytes 0 to 15 
 *      ADDR-ADDR+3 Long value of Completed Cycles of test bank 1
 *    ADDR+4-ADDR+7 Long value of Completed Cycles of test bank 2
 *   ADDR+8-ADDR+11 Long value of Completed Cycles of test bank 3
 *  ADDR+12-ADDR+13 Int value of CRC of bytes ADDR to ADDR+11
 * 
 * 
 */

typedef struct Targets
{
   unsigned int addr;
   unsigned long bank1;
   unsigned long bank2;  
   unsigned long bank3;
   unsigned int crc;
} Targets;

typedef struct Completed
{
   unsigned long bank1;
   unsigned long bank2;  
   unsigned long bank3;
   unsigned int crc;
} Completed;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  while (!Serial);

  Targets targetCycles;
  targetCycles.addr = 18;
  targetCycles.bank1 = 1001;
  targetCycles.bank2 = 2002;
  targetCycles.bank3 = 3003;
  targetCycles.crc = 4444;

  Serial.print( "\nAssigned Target values: " );
  Serial.print( targetCycles.addr );
  Serial.print( "\t" );
  Serial.print( targetCycles.bank1 );
  Serial.print( "\t" );
  Serial.print( targetCycles.bank2 );
  Serial.print( "\t" );
  Serial.print( targetCycles.bank3 );
  Serial.print( "\t" );
  Serial.print( targetCycles.crc );
  Serial.print( "\n" );

  // Write these value to EEPROM starting at address 0
  EEPROM.put( 0, targetCycles );

  // Read in these data from EEPROM
  Targets readTargetCycles;
  EEPROM.get( 0, readTargetCycles );

  // Now display the read values
  Serial.print( "\n    Read Target values: " );
  Serial.print( readTargetCycles.addr );
  Serial.print( "\t" );
  Serial.print( readTargetCycles.bank1 );
  Serial.print( "\t" );
  Serial.print( readTargetCycles.bank2 );
  Serial.print( "\t" );
  Serial.print( readTargetCycles.bank3 );
  Serial.print( "\t" );
  Serial.print( readTargetCycles.crc );
  Serial.print( "\n" );

  // Do the same thing for the completed cycle counters.
  Completed completedCycles;
  completedCycles.bank1 = 101;
  completedCycles.bank2 = 202;
  completedCycles.bank3 = 303;
  completedCycles.crc = 444;

  Serial.print( "\nAssigned Completed values: " );
  Serial.print( completedCycles.bank1 );
  Serial.print( "\t" );
  Serial.print( completedCycles.bank2 );
  Serial.print( "\t" );
  Serial.print( completedCycles.bank3 );
  Serial.print( "\t" );
  Serial.print( completedCycles.crc );
  Serial.print( "\n" );

  EEPROM.put( targetCycles.addr, completedCycles );

  // Read in these data from EEPROM
  Completed readCompletedCycles;

  EEPROM.get( readTargetCycles.addr, readCompletedCycles );

  Serial.print( "\n    Read Completed values: " );
  Serial.print( readCompletedCycles.bank1 );
  Serial.print( "\t" );
  Serial.print( readCompletedCycles.bank2 );
  Serial.print( "\t" );
  Serial.print( readCompletedCycles.bank3 );
  Serial.print( "\t" );
  Serial.print( readCompletedCycles.crc );
  Serial.print( "\n" );
 
}
void loop() {
  // put your main code here, to run repeatedly:

}

This is my first foray into C/C++ programming and so far it doesn’t seem all that difficult to navigate.

Thanks for all the help!

The only time you need to write to EEPROM is at ‘power fail time’.