Write to pgmspace?

Wishing to preserve a sketch's state through a reboot, I thought of checkpointing to non-volatile memory. I first discovered EEPROM, but not wishing to wear out its 100k write cycles too quickly I looked further and found PGMSPACE. Unfortunately, the examples given assume that a bunch of variables are going to be loaded into there when the sketch is uploaded and that the space is used ever after as read-only: there is no mention of writing there. So either I find another piece of non-volatile memory that is read-writeable but without EEPROM's limit or I use EEPROM and start saving for a replacement ATmega. Any ideas?

First of all, you should note that program space (a.k.a. flash memory) wears out an order of magnitude faster than EEPROM. Flash can withstand 10,000 write/erase cycles while EEPROM can withstand 100,000 write/erase cycles. Note this endurance spec applies individually to each memory location, so this means that writing 100,000 times to the same EEPROM address will potentially wear out that address, but the remaining 511 EEPROM addresses will still function just fine. Additionally, this endurance spec is just a safe lower bound; I've heard of people testing EEPROM by writing to the same address millions of times without any negative consequences.

If you schedule it so that you only back up your state every minute or so, you should be fine using EEPROM, especially if you can periodically change the EEPROM addresses used to store the state. Another idea is to create your own RESET by connecting a pushbutton to one of your digital inputs and by connecting another digital input to your RESET line. When someone pushes your custom RESET button, call a function that saves the state to EEPROM and then have your Arduino drive its own RESET low to reset itself. Of course this idea won't help you if someone pushes the real reset button or if your power supply dies or gets disconnected.

  • Ben

Your reply goes some way towards explaining why we're not allowed to write to pgmspace. My aim is to log some readings on a stand-alone ardy then unplug it from the battery and plug in a usb lead to upload results to a PC. With that in mind, a pushbutton connected to a digital pin should do the trick. Poll the pin and when the button is pressed write the state to eeprom which should preserve the data through the battery->usb changeover.

Thanks for your help, bens.

I may be missing something but why disconnect it from the battery?
If it has to go how about a small rechargeable cell that keeps it going between battery and USB?

Finally you could use some I2C EEPROM, they are usually specked at > 1 million writes.

then have your Arduino drive its own RESET low to reset itself.

I'm too lazy to double check this now but I seem to recall attaching to your own reset line is specifically "prohibited" by Atmel. Or maybe it was something else...

Presumably you'd use the Watchdog to actually achieve this result within spec.

--Phil.

Your reply goes some way towards explaining why we're not allowed to write to pgmspace.

Just to confuse things and be pedantic, you can write to pgmspace but the limitations on how you can do so are so significant it's not of practical use except for specific circumstances. (Limitations include that you must access a "page" at a time, the actual instructions that do the writing must be in the bootloader segment and probably more.) For these reasons and more, using EEPROM would probably be the way to go for you.

My aim is to log some readings on a stand-alone ardy then unplug it from the battery and plug in a usb lead to upload results to a PC.

As mentioned above, you can have the device be battery powered and still connect via USB to the PC.

--Phil.

I'm too lazy to double check this now but I seem to recall attaching to your own reset line is specifically "prohibited" by Atmel. Or maybe it was something else...

It's definitely possible to have an AVR reset itself using an I/O line (I've done it many times without ever having a problem). If you can point me to someplace where Atmel advises against this I'd be very interested to see it.

  • Ben

then have your Arduino drive its own RESET low to reset itself.

I'm too lazy to double check this now but I seem to recall attaching to your own reset line is specifically "prohibited" by Atmel. Or maybe it was something else...

Maybe it was having something on the reset line when using the AVR Dragon or a similar debugger? For those, Atmel says the debugger needs full control of the line, and having a capacitor or something else on it will bugger with things.

If you're paranoid about "burning out" the internal eeprom, you can alway connect a cheap external eeprom chip; if you wear it out, you just replace it. (although... a new ATmega168 is not so much more expensive than an external eeprom chip. "Under $5" means your "real" costs may be dominated by postage, etc, rather than the cost of the chip itself.)

Farnell says ATmega168 PUs for AUD9.42 ea, kess for 25+. I don't think I'll worry about wearing it out...

Farnell says ATmega168 PUs for AUD9.42 ea, kess for 25+. I don't think I'll worry about wearing it out...

Dude don't be buying from Farnell in Australia unless you are in a real hurry and can't wait for Futurlec to deliver. The have '168s for AU$4.20 each. Delivery is AU$4 for orders under AU$50.

http://www.futurlec.com.au/test13.jsp?category=Integrated%20Circuits%20-%20Atmel&category_title=Atmel%20Microcontrollers&main_menu=IC&sub_menu=ICATMEL

+1 for the external EEPROM, if you can stand the 3ms write time

The external EEPROM sounds fairly unnecessary given what verstapp seems to want to do (all he needs is some signal to tell him when to back up the state to EEPROM, which means he won't be burning anything out). Additionally, he might not even need to backup the state since he doesn't have to turn off the Arduino to plug it into USB. Lastly, the internal EEPROM has a write time of 3.4 ms, too. Lastly lastly, if he does burn out the internal EEPROM, he can buy external EEPROM at that point and use it instead (the AVR will still function with burned out EEPROM addresses).

  • Ben

An honest question, has anyone seen an over used eeprom location in an ATMega? I've seen over-used flash, but never eeprom.
I figure it's time to find out. I've just grabbed a fresh new ATMega168 (I can't find the manufacture date for this lot, but it's recent) and loaded the following sketch into it. With a 0.1s delays, it should destroy this address in about 2.7 hours by Atmel's standards. For reference, VCC=~4.8V.

In all honesty, this doesn't stress the retention characteristics of the memory, only asking for 100uS of retention and with the power on, but any other test would take forever!

#include <EEPROM.h>

unsigned char x = 1;
unsigned long c=0;

void setup(){
Serial.begin(9600);
EEPROM.write(55,x);
delay(100);
}

void loop(){
unsigned char y=EEPROM.read(55);
if(x==y){
Serial.print("OK for ");
Serial.print((unsigned)x,HEX);
Serial.print(", tick# ");
Serial.println(c);
}else{
Serial.print("Failure at tick# ");
Serial.println(c);
Serial.print("Expected: ");
Serial.print((unsigned)x,HEX);
Serial.print(" - Read: ");
Serial.println((unsigned)y,HEX);
while(1);
}
x+=3;
c++;
EEPROM.write(55,x);
delay(100);
}

That looks like a good test. I might have just had the stored value alternate between 0x55 (01010101) and 0xAA (10101010), but incrementing the value by 3 each time sounds reasonably robust. I also might have chosen to do this test on EEPROM address 511 so that it would be easier to remember which address is bad later.

  • Ben

OK for DB, tick# 99998
OK for DE, tick# 99999
OK for E1, tick# 100000
OK for E4, tick# 100001
OK for E7, tick# 100002

So it looks like 100,000 is a conservative estimate. (Not that we should be surprised. It's currently up around 125K write/read cycles to the same location.)

I might have just had the stored value alternate between 0x55 (01010101) and 0xAA (10101010), but incrementing the value by 3 each time sounds reasonably robust.

A history with SDRAM testers has shown that an alternating pattern can occasionally be stored in otherwise dead cells. As we're not looping through address, it should be safe to write sequential values, but the +3 test works reliably for other memory testing, so I'll use it here.

I also might have chosen to do this test on EEPROM address 511 so that it would be easier to remember which address is bad later.

I'll either bin the ATmega or give it a purpose that uses no eeprom. A middle of the road address should give a more reasonable estimate of eeprom life too; if 511 or 0 are located at the extreme corners of the die, they may suffer worse or better reliability than something away from the corner; OK, it's a long shot, but it's worth thinking about. Ideally I should have stressed a few locations, but oh well.

So it looks like 100,000 is a conservative estimate. (Not that we should be surprised. It's currently up around 125K write/read cycles to the same location.)

Not too long ago I heard of someone doing a test like this and they claimed to be over a million writes and counting with no failure yet, though I don't think I saw their code so I'm not sure how valid their test was. Still, I wouldn't be surprised if the 100,000 writes endurance spec was highly conservative (e.g. maybe the EEPROM manufacturing process produces a few weak cells that die long before the others and Atmel just decided to put the endurance of these cells as the overall endurance for the EEPROM).

If 511 or 0 are located at the extreme corners of the die, they may suffer worse or better reliability than something away from the corner; OK, it's a long shot, but it's worth thinking about. Ideally I should have stressed a few locations, but oh well.

That's a reasonable argument. You're right, it would have been best to test several locations spread throughout the EEPROM, but I think it's pretty cool that you're taking the time to test this at all! I definitely appreciate it.

  • Ben

It's definitely possible to have an AVR reset itself using an I/O line (I've done it many times without ever having a problem). If you can point me to someplace where Atmel advises against this I'd be very interested to see it.

It took an age to find but thanks to sheer stubbornness and my character flaw of disliking being wrong I eventually found a reference:

You should not try to:

  • Use another pin of the AVR to pull the external RESET line. The pins of the AVR are tristated halfway through the minimum reset time, this releases the RESET line and hence nothing happens.

You will note from that thread and others on the avrfreaks forum that the matter is still heavily debated. There seems to be references to other posts by Atmel employees stating the same thing but I stopped once I found this one.

Having said that, the "accepted wisdom" seems to be that extra capacitance on the /RESET pin could extend the pulse long enough to trigger a reset.

YMMV but I wasn't imagining things. :slight_smile:

--Phil.

Edit: Better still, here it is on the Atmel site: http://support.atmel.no/bin/customer?=&action=viewKbEntry&id=21

In the case where I used it there was a 0.1uF capacitor between the reset line and ground, which is probably why it's never caused me any problems. Thanks for taking the time to find that info!

  • Ben

OK for DB, tick# 2499998
OK for DE, tick# 2499999
OK for E1, tick# 2500000
OK for E4, tick# 2500001
OK for E7, tick# 2500002

Rolling over on the 2.5million write mark and going strong!