0

I'm working on some software using an Uno (ATmega328P). I have a stage byte that can be 1 of 5 values (0-4) in my code and it will increase by 1 every 2.5 hours. If I lose power I need to ensure that on wake up the stage is the same as it was at the time of power loss, so each time the stage is updated I save it to EEPROM.

To ensure the EEPROM lasts as long as possible I want to write some code that uses more than a single byte which I continually erase and write to. I was wondering if there is any library to do this or if my idea below would work?

I currently don't need to use the EEPROM for anything else so to extend the EEPROM life I was going to section of 1 quarter of it (0-255 bytes) for saving this value. Each time I change the stage I will write 3 bytes to EEPROM which will be:

  • An index byte (used to shift addresses I write to).
  • A stage byte (the stage I need to store).
  • A count byte (the amount of times I have wrote the stage at the current index).

To begin with the index will be written to byte 0 in the EEPROM, the stage to byte 1 and the count to byte 2.

My plan is to allow the stage to be written to byte 1 250 times, then clear the count and shift the index to 3. This will in turn move the bytes that the stage and count are being written to to 4 and 5. I will do this until the index reaches the end of the 255 bytes and then return the index to 0. So in total I should be able to shift 85 times.

Each byte has 100,000 erase/write cycles so this means I can pass through bytes 0-255 400 times, writing the stage 250 times each pass. So instead of having 100K writes I would have about 8.5 million writes.

This is my first idea and I realize there is also some waste in the way I do it. I haven't worked with EEPROM much and I was just hoping for some advice as I'm sure I could be going at this completely wrong.

  • 1
    @MichelKeijzers Page Size for the ATMega328Ps EEPROM is 4 bytes. So it would be better to not use byte 1, 2 and 3. So the first page is only uses for the index byte. – Gerben Jan 17 '18 at 16:04
  • 1
    The RTC is the best solution. Avoiding that the Arduino has a power down is the second best. For an algoritme, I would not count up to 250, but use the EEPROM as a ring buffer and continuously write to the next location. The Arduino could be turned off while writing to EEPROM, perhaps the variable has to writting twice and maybe with a checksum. Only two bits needs to be remembered... someone who is more creative than me can do something with that (a protocol to store it, or remember it in a different way). – Jot Jan 17 '18 at 17:11
  • 1
    @CodeGorilla I do use the RTC technique elsewhere in my code but using the RTC in this case would not be suitable as I need the process to pick up exactly where it left off regardless of how long it is powered off for. – user1649972 Jan 18 '18 at 11:08
  • 1
    @CodeGorilla it kind of wastes once cycle, but in doing so make the code a bit simpler. Using the full 1k of memory, but writing it twice, will still give you 500 times the number of write cycles (ignoring page size). If that’s enough for the lifecycle of the product... – Gerben Jan 18 '18 at 16:04
  • 1
    @CodeGorilla Been trying to think of a way around this as it will mean I write twice for every 1 write each loop around. Unfortunately I have to remove the old data before returning to my start point. My plan is when I reach the end of the EEPROM I will scan through all elements and return them to 0xFF (default value). I need to do this so I can find my last index on wakeup after a power loss. On wakeup I will scan all indexes until I reach one that has the value 0xFF, then step back to the previous index, which will be the last index I have saved. I cant think of a way around this just yet – user1649972 Jan 18 '18 at 16:41
1

You can load spread by saving the current value ORred 0x80 or 0x00.

When writing you write to the next memory location and when it wraps you take the other value to OR with.

The values in the eeprom will be

[{0x00|value},{0x00|value},{0x00|value},...,{0x00|value},{0x00|value},{0x00|value},{0x80|value},{0x80|value},{0x80|value},...,{0x80|value},{0x80|value}]

or

[{0x80|value},{0x80|value},{0x80|value},...,{0x80|value},{0x80|value},{0x80|value},{0x00|value},{0x00|value},{0x00|value},...,{0x00|value},{0x00|value}]

Then you read the first and last byte and if the upper bit is equal you take the last value.

If they are not equal you binary search until to the position changes, the most recent value will be the one right before the change.

0

There are many ways of achieving what you want. The method I would use would be to use pairs of bytes, but split up differently.

For each 16 bits I would have 13 for a counter, and 3 for a value. The counter, being 13 bits, can count from 0 - 2^13-1, or 0 - 8191. The 3 value bits can store 0 - 2^3-1, or 0 - 7, which is fine for your 0-4 value.

The size of the counter is important, since it is more than double the number of 16-bit pairs in the EEPROM. Assuming a 1kB EEPROM that's 512 16-bit values, so you want more than 1024 values available in your counter (if you wanted to change the split to store a larger number...).

The algorithm is simple:

  1. Read through the EEPROM looking at the next counter value. If the count increases by more than 1 the last value read is the current one.
  2. If the count goes from 8191 to 0 then keep going, you have just looped is all.
  3. Increase the counter by 1 and write to the EEPROM addresses where the count jumped by more than 1.

For example, if you have:

78 1
79 2
80 3
8191 7
8191 7
8191 7

you know that the space after 80 hasn't been used (0xFFFF is split as 0x1FFF and 0x7) so you write "81 4" to it.

Another:

8190 2
8191 3
0 4
1 0
2 1
7283 3
7284 4
7285 0

The jump from 8191 to 0 is just a wrap around and can be considered sequential. However the jump from 2 to 7283 isn't sequential, so you can overwrite entry 7283 with "3 2".

When you write, if you are going past the end of the EEPROM's memory space, you just loop back round to the start again.

This gives you 512 * 100,000 writes, or 51.2m writes.

  • This is excellent and I will 100% use this idea on another project I am working on that uses a larger EEPROM. I will only use 2 bytes as suggested, drop my count sticking with just the stage and index and move the index after every EEPROM write. As I am only planning to use 256 bytes I would not need such a large index to cover them all as 1 byte will do. Again thank you for this it is appreciated and will be used. Using my basic idea I had 28 years, the idea I posted on here would have given me 2425 years and now with using the byte pairs I will get up to 3652 years so I'm well covered. – user1649972 Jan 18 '18 at 11:18
0

Also, check that the values you want to write are actually changing. No point in erasing and writing a value that is already there. And you save 3.3 ms by not having to do the write.

  • Hi Edgar, thank you for the reply. The value will 100% change each time I try to write, the change in value is what prompts the write to EEPROM. Great advice tho, thanks again – user1649972 Feb 9 '18 at 11:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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