9

Is there any way to store the values of necessary variables somewhere (may be in a file that gets updated by the program at various events), which can be read back when program starts after rebooting the Arduino board?

I am trying to control my AC appliances using IR remote control. Where I want Arduino to remember what was on and what was off in my room after a power failure.

Using EEPROM looks like a fairly good solution, though it has a limitation of 100,000 writes which is making me try to find another way out.

Using an external EEPROM which doesn't have that limitation or is fairly big, is a really good idea I got from fuenfundachtzig, thanks for this great idea. But I don't know how to implement this in my project. Any resource to gather knowledge on using external EEPROM, will be much appreciated.

2
  • 1
    If you are only concerned about reboot, and not power cycling, then you can use RAM - you just have to keep any init code from wiping it. Of course if you need to survive power cycling too, then you need the EEPROM. Commented May 17, 2015 at 22:43
  • Actually I am really concerned about the power cycling. I am trying to control my AC appliances using IR remote control. Where I want Arduino to remember what was on and what was off in my room after a power failure. Commented May 19, 2015 at 16:36

7 Answers 7

7

The internal RAM of the Arduino will be reset when you repower the chip, so if you want to keep your data, you need to store it in EEPROM.

If you are worried about the limited write/erase cycles, you should estimate how often the data would be updated (i.e. written to EEPROM) and how long you plan the lifetime of the device you build. If 100,000 cycles then still is an issue, you have several options:

  • Keep the variables in RAM and only write them to EEPROM say every 5 minutes (100,000 cycles then makes about one year of continuous usage until the EEPROM might fail).
  • Use an external EEPROM (in a socket) that could be easily replaced if needed.
  • If replacing it is not an option, consider using an FRAM instead (advantage vs EEPROM: much more erase/write cycles but also very expensive, so not an option for large amounts of data but certainly for a few variables).

Note, however, that your description sounds like a typical use-case for user settings that you don't want to get lost on reboot. For those the internal EEPROM is the right place: only store them when they're changed and you're golden -- the user won't change them a 100,000 times easily...

7
  • I usually use for this type of things an external EEPROM; something like an AT24C02 works fine for most projects (it's 256 bytes). I just prefer external memory as it lasts more R/W cycles and because you can change it if it doesn't work anymore.
    – Stefa168
    Commented May 17, 2015 at 21:00
  • 1
    The ram is not cleared. The global variables are set to zero according to the 'c' standard. The unused ram keeps its value during a reset.
    – Jot
    Commented May 1, 2017 at 18:25
  • Yes, you are right. I was thinking of a power failure which leads to a loss of the data in RAM (and which makes a reinitialization necessary). Commented May 1, 2017 at 20:04
  • what about to use sdcard reader. is not so much expensive and sdcard will live lot of time.
    – m3nda
    Commented Jun 3, 2018 at 14:49
  • adafruit seems to have FRAM for $5. Am i missing something?
    – rfii
    Commented Jan 29, 2021 at 4:05
3

EEPROM space, as already mentioned, will work if non-volatile is required. However, you have not qualified if it needs to be non-volatile or not. If not then you can use an __attribute__ to define the variable space not to be initialized. As the SRAM on the ATmega's are not cleared by reset or power cycle. The Compiler defaults to initializing them. Where this can be turned off per variable as in the below example:

//non-initialized value
union configUnion{
  uint8_t    byte[6]; // match the below struct...
  struct {
    uint16_t value1;
    uint16_t value2;
    uint16_t chksum;
  } val ;
} config  __attribute__ ((section (".noinit")));

void setup() {
  uint16_t sum; 
  //Initialize serial and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }

  // prints title with ending line break
  Serial.print("Out of Reset -");
  sum = getchksum();
  printValues();

  if (sum != config.val.chksum) {
    config.val.chksum = sum;
    Serial.print("chksum is incorrect setting config.val.chksum = 0x"); Serial.println(config.val.chksum, HEX);
  }

  config.val.value1++;
  config.val.value2++;
  Serial.print("setup new values - ");
  printValues();
  config.val.chksum = getchksum();
  Serial.print("updating chksum config.val.chksum = 0x"); Serial.println(config.val.chksum, HEX);
}

int counter = 0;

void loop() {
  if (counter < 200) {
    Serial.print("after a while - ");
    printValues();
    Serial.println();
    while (true) {
      continue;
    }
  }
  counter++;
}

void printValues() {
  Serial.print(" value1 = 0x"); Serial.print(config.val.value1, HEX);
  Serial.print(", value2 = 0x"); Serial.print(config.val.value2, HEX);
  Serial.print(", sum = 0x"); Serial.print(getchksum(), HEX);
  Serial.print(", chksum = 0x"); Serial.println(config.val.chksum, HEX);
}

uint16_t getchksum() {
  int sum = 0;
  for (int position = 0; position < (sizeof(config) - sizeof(config.val.chksum)); position++) {
    sum = sum + config.byte[position];
  }
  return sum;
}

Output of above code is below. Note that the first output was the result of powering the UNO up with the Reset button depressed and then released after the Monitor window was started. Otherwise the "incorrect setting" print would have been missed, before the monitor window can be started.

Out of Reset - value1 = 0xBFED, value2 = 0xD2F9, sum = 0x377, chksum = 0xF457
chksum is incorrect setting config.val.chksum = 0x377
setup new values -  value1 = 0xBFEE, value2 = 0xD2FA, sum = 0x379, chksum = 0x377
updating chksum config.val.chksum = 0x379
after a while -  value1 = 0xBFEE, value2 = 0xD2FA, sum = 0x379, chksum = 0x379

Out of Reset - value1 = 0xBFEE, value2 = 0xD2FA, sum = 0x379, chksum = 0x379
setup new values -  value1 = 0xBFEF, value2 = 0xD2FB, sum = 0x37B, chksum = 0x379
updating chksum config.val.chksum = 0x37B
after a while -  value1 = 0xBFEF, value2 = 0xD2FB, sum = 0x37B, chksum = 0x37B

Out of Reset - value1 = 0xBFEF, value2 = 0xD2FB, sum = 0x37B, chksum = 0x37B
setup new values -  value1 = 0xBFF0, value2 = 0xD2FC, sum = 0x37D, chksum = 0x37B
updating chksum config.val.chksum = 0x37D
after a while -  value1 = 0xBFF0, value2 = 0xD2FC, sum = 0x37D, chksum = 0x37D

With this your variables will persist resets. As long as the power is not lost. Noting the above where you will get random data, to start.

Using either EEPROM or .noinit I would recommend that you checksum your persistent variable space during setup and if incorrect you can initialize or issue a warning.

3

If you really need to update your NVRAM frequently, look into FRAM (Ferroelectric Random Access Memory) which claims a write life of 10^13 cycles (that's ~ 318,000 years if you write once/sec!). They're 8KB, and faster than Flash or EEPROM at 20MHz (SPI).

Adafruit (in the US) sells them on a breakout board for about US$6 in onesies. Or you can buy the bare chips from the usual suppliers for around US$1.30, but not DIP, only SOP8 packages.

2

Store them in the on-chip EEPROM.

1
  • The EEPROM memory has a specified life of 100,000 write/erase cycles, so using EEPROM can be a limitation where program automatically writes values in it frequently, though, it reads them quite rare. Commented May 17, 2015 at 20:10
0

If you're open to a off-chip solution, it isn't too difficult to buy/build an SD card reader.

3
  • 2
    Please try to provide a more thorough answer: provide links to such SD card readers, post some sample code on how to read/write variables from it, and mention how it is better than EEPROM.
    – jfpoilpret
    Commented May 22, 2015 at 4:27
  • Good suggestion. SD is using a regular SPI interface. So all you need is some logic-level-conversion. Beside that you wire them directly to an Arduino. Just solder some wires to a micro-SD to SD adapter.
    – Gerben
    Commented May 27, 2015 at 15:12
  • +jfpoilpret IMHO SD Card Readers are ubiquitous and shouldn't need examples or citation. The code is dependent on the brand of reader so no point in providing arbitrary code. I did mention how it is better than EEPROM, it isn't too difficult to buy or build.
    – linhartr22
    Commented May 28, 2015 at 22:24
0

This was puzzling me too. I just wanted to use the onboard button to trigger a "count up an integer" regardless any setup routines. For me, mpflaga's answer gave me the right direction. But the given example was far too complicated for my needs. So here's the bare minimum example for an integer value that survives a reset, counting up. (But NOT a power loss, as it's in RAM!) Enjoy!

uint8_t c __attribute__ ((section (".noinit")));

void setup() {
  Serial.begin(9600);
  Serial.print("Just startet. c = ");
  Serial.print(c);
  if(c>7){c=0;}else{c++;}
  Serial.println(" - Waiting for RESET.");
}

void loop() {
  // Do more stuff.
}
0

I am very late to this party ... I just bought an UNO WiFi and I am looking at creating a simple protocol to persist data with a data store on another device connected to the WiFi. Probably will use HTTP with simple end points, treat the remote storage as a contiguous memory block:

GET IP:port/addr/len
PUT IP:port/addr data

I could also create named blocks (think files):

GET IP:port/name
PUT IP:port/name data

The actual remote storage could be anything, memory mapped disk file, SQLite3 database, etc.

There are many drawbacks, such as reliance on the external service, connectivity issues, error handling, etc. I could run out of code space just supporting the protocol.

EDIT: I got a little flack for my answer, including downvotes, however, read the OP - he stated "somewhere" for retrieving variable data; a LAN device certainly falls in the category of "somewhere", especially when the UNO has WiFi. My answer might not be suitable for the OP, however, after reading my answer, the OP might opt to get a WiFi enabled device. I do not believe in "keyhole" solutions, but rather to provide options that fit the general tone of the question even if it means getting out of its box.

13
  • 2
    so your answer is "add WiFi and store the values on a remote server"? isn't that a little complicated if the project doesn't use WiFi for anything else?
    – Juraj
    Commented Jun 23, 2023 at 14:59
  • Does EEPROM not work for you?
    – Nick Gammon
    Commented Jun 24, 2023 at 8:46
  • @Juraj - Yes, that is my answer, and yes, it is complicated if your project does not use WiFi for anything else, but as I stated in my answer, WiFi is my best solution and I offered it as yet another possible answer for certain situations, see my response for Nick Gammon Commented Dec 13, 2023 at 16:01
  • @NickGammon - The EEPROM solution is not my best solution as I cannot predict how many updates to the persisted data, both in updates and new data, so I could eventually use all of the EEPROM data and/or perform too many writes to it, effectively destroying the UNO's capability for me. Commented Dec 13, 2023 at 16:03
  • All - the OP stated: "Is there any way to store the values of necessary variables somewhere" - emphasis on "somewhere" in my answer. "Somewhere" includes on a local network, which is what my answer provides. Commented Dec 13, 2023 at 16:04

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.