4

Is it possible to store a variable directly in EEPROM and retrieve it without needing to use a library?

I'm building a project that can change the colour of an RGB LED and I want to store the colour in a non-volatile memory space, but I was wondering if I could avoid using one of the EEPROM libraries and have a global variable stored in nonvolatile memory, but still accessed directly, without needing to call a function.

5
  • It is possible - but comes down to rewriting it yourself, as there is quite a complex requirement to write EPROM & the libraries are not doing it a long way round just for fun ; take a look at the source code in the library to see how to do it. Commented Mar 15, 2015 at 8:31
  • Also be aware that EEPROM access time is slower than SRAM. It is preferrable to not use an EEPROM memory cell as a variable in your program, and rather save the value to EEPROM from time to time, and read it at reset time only.
    – jfpoilpret
    Commented Mar 15, 2015 at 8:47
  • 1
    "Without needing to call a function" is a curious requirement -- what is the benefit of that? Even if you write the EEPROM access yourself, you would wrap it in a function to avoid code duplication. (Unless you need it only in one place, but still wrapping in a function would be good programming style.) Commented Mar 15, 2015 at 8:53
  • 2
    Just use <avr/eeprom.h>, instead of the arduino library, which is atrocious.
    – Gerben
    Commented Mar 15, 2015 at 12:34
  • "Without using a library" is probably a better description. I'd attempted to use the Arduino EEPROM library and it appeared to crash the chip, seemingly regressing to a prior Pin13-flashing program instead of the program I'd spent hours writing. Commented Mar 17, 2015 at 8:33

3 Answers 3

3

Writing and reading EEPROM is possible to do without a library. Take a look at the datasheet of the ATmega328P to find an example: On page 25 / 26 there are example codes for reading and writing both in assembler and C. They do wrap it in a function but as I said in a comment if you only have place in your code where you would like to access EEPROM you can put the code there without duplication. These functions write and read one byte at a time, so if you want to store larger datatypes (a 16-bit integer for example) you already need to call the routines more than once.

Note that the EEPROM has a limited life cycle of at least 100,000 write/erase cycles (cells must be erased before they can be written, reads are unlimited) and it is considerably slower than SRAM (typ. 3.3 ms for writing a byte). You also need to make sure no interrupts interfere with the write process.

However, in the sense of the question it seems this is not what you want: You cannot just create a global variable and have it magically being written to EEPROM.

2

EEPROM can store one byte at a location. To store Integer variable, it requires two consecutive location. For Double, it requires four consecutive memory location. I have written function to store and read, int & double to and from built-in EEPROM. As per your question, you can modify it as per your need.

Actually this answer was copied from another thread.

/*
  StackExchange Question: "How to Store 2 analogRead values and read using EEPROM for Arduino uno?"
  Question Id: 15910 (https://arduino.stackexchange.com/questions/15910/how-to-store-2-analogread-values-and-read-using-eeprom-for-arduino-uno)
  Author: Anurag S. Vasanwala ([email protected])

  Tested on Arduino Version 1.6.7

  Description:  This sketch helps to store and read, Integer & Double to and from built-in EEPROM.
  Objectives:
    + Write Integer @ Specified Address (Fn: EEPROM_Write_Int)
      + Conversion from Integer to Byte Array
      + Store Bytes
    + Read Integer from Specified Address (Fn: EEPROM_Read_Int)
      + Read Bytes
      + Conversion from Byte Array to Integer
    + Write Double @ Specified Address (Fn: EEPROM_Write_Double)
      + Conversion from Double to Byte Array
      + Store Bytes
    + Read Double from Specified Address (Fn: EEPROM_Read_Double)
      + Read Bytes
      + Conversion from Byte Array to Double
 */
#include <EEPROM.h>

// MACRO : Combines FROM_BYTES into TO_OBJECT of datatype "DATATYPE"
#define CombineBytes(FROM_BYTES, DATATYPE, TO_OBJECT) \
  TO_OBJECT = *((DATATYPE *)FROM_BYTES);

// MACRO : Splits FROM_DATA of DATATYPE into equivalent byte array TO_BYTES
#define GetBytes(FROM_DATA, DATATYPE, TO_BYTES) \
  *((DATATYPE *)TO_BYTES) = FROM_DATA;

// Writes Integer's equivalent bytes to Address and Address + 1
void EEPROM_Write_Int(unsigned int Address, int Data)
{
  // Get the size of datatype to write number of bytes
  const byte SizeOf_DataType = sizeof(int);

  // Create tem buffer to get Bytes of Datatype
  byte Temp_Buffer[SizeOf_DataType];

  // Call macro to store byte array into Temp_Buffer from Data
  GetBytes(Data, int, Temp_Buffer);

  // Write number of bytes to memory location specified in Address and so on
  for(byte Index = 0; Index < SizeOf_DataType; Index++)
  {
    EEPROM.write(Address + Index, Temp_Buffer[Index]);
  }
}

// Reads two bytes from Address and Address + 1 and returns equivalent int
int EEPROM_Read_Int(unsigned int Address)
{
  // Get the size of datatype to write number of bytes
  const byte SizeOf_DataType = sizeof(int);

  // Create tem buffer to get Bytes of Datatype
  byte Temp_Buffer[SizeOf_DataType];

  int Result;

  // Read number of bytes from memory location
  for(byte Index = 0; Index < SizeOf_DataType; Index++)
  {
    Temp_Buffer[Index] = EEPROM.read(Address + Index);
  }

  // Call macro to combine bytes into equivalent to int
  CombineBytes(Temp_Buffer, int, Result);

  return Result;
}

// Writes Double's equivalent bytes to Address, Address + 1, Address + 2 and Address + 3
void EEPROM_Write_Double(unsigned int Address, double Data)
{
  // Get the size of datatype to write number of bytes
  const byte SizeOf_DataType = sizeof(double);

  // Create tem buffer to get Bytes of Datatype
  byte Temp_Buffer[SizeOf_DataType];

  // Call macro to store byte array into Temp_Buffer from Data
  GetBytes(Data, double, Temp_Buffer);

  // Write number of bytes to memory location specified in Address and so on
  for(byte Index = 0; Index < SizeOf_DataType; Index++)
  {
    EEPROM.write(Address + Index, Temp_Buffer[Index]);
  }
}

// Reads four bytes from Address, Address + 1, Address + 2 and Address + 3 and returns equivalent double
double EEPROM_Read_Double(unsigned int Address)
{
  // Get the size of datatype to write number of bytes
  const byte SizeOf_DataType = sizeof(double);

  // Create tem buffer to get Bytes of Datatype
  byte Temp_Buffer[SizeOf_DataType];

  double Result;

  // Read number of bytes from memory location
  for(byte Index = 0; Index < SizeOf_DataType; Index++)
  {
    Temp_Buffer[Index] = EEPROM.read(Address + Index);
  }

  // Call macro to combine bytes into equivalent to double
  CombineBytes(Temp_Buffer, double, Result);

  return Result;
}


void setup()
{
  // Initialize Serial @ 9600 baud
  Serial.begin(9600);

  // Print size of datatype just for reference
  /* Serial.print("Size of byte = ");
  Serial.println(sizeof(byte));
  Serial.print("Size of int = ");
  Serial.println(sizeof(int));
  Serial.print("Size of float = ");
  Serial.println(sizeof(float));
  Serial.print("Size of double = ");
  Serial.println(sizeof(double)); */

  int myInt1 = -290;
  int myInt2;
  double myDbl1 = 23.41;
  double myDbl2;

  // Write myInt1 @ 100 memory location; It requires 2 consequtive memory location to store integer
  EEPROM_Write_Int(100, myInt1);

  // Read integer located @ memory location 100 and assign it to myInt2
  myInt2 = EEPROM_Read_Int(100);
  Serial.println(myInt2);

  // Write myInt1 @ 200 memory location; it requires 4 consequtive memory location to store double
  EEPROM_Write_Double(200, myDbl1);

  // Read double located @ memory location 200 and assign it to myDbl2
  myDbl2 = EEPROM_Read_Double(200);  
  Serial.println(myDbl2);
}

void loop()
{

}

This code is successfully tested on Arduino Version "1.6.7".

2

You can have a global variable in EEPROM if the EEPROM is memory mapped. Memory-mapping the EEPROM is possible on ATxmega chips. Notice that writes go to a temporary buffer, not the EEPROM itself, until you explicitly issue a write command.

Most Arduinos, however, use ATmega chips, which do not have this feature. I am not aware of any xmega-based Arduino or clone.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.