Second counter saved in flash memory - How to avoid deterioration?

Let's say I have a flash memory that has a 100,000 write cycle endurance. Each segment is 512 bytes, and as usual has to be erased fully to be rewritten to.

If I want to save the amount of elapsed seconds (and therefore perform a write cycle each second), I will have to start using an other segment after every 100,000 seconds. This means that after 10 years, I would have used 3165 different segments - or 1,615,872 bytes of memory - for that purpose only.

Is there a more efficient way to store a second counter into flash memory?

Is using flash memory for this purpose simply a bad design choice? I'd like to use the internal flash of my MCU instead of adding external memory, but if the latter is a more sane idea, please still propose.

PS. I cannot use RAM because my MCU could be shut down at any given time. Seconds need to be safely stored in non-volatile memory.

• "I cannot use RAM because ..." off-topic, but make sure you know what to do about partial writes, or make sure that a write is never partial (by using a big-enough hold-off cap, and an interrupt on power-down that insures that any write that's been started before the plug is pulled finishes before power to the CPU goes away). Aug 16, 2022 at 19:58
• Yeah that's why there is a "battery backed RAM". even some RTC chips have a few bytes of spare RAM on board for other purposes than time. Aside from that, there are microcontrollers that can preserve some critical datum on very low power modes, usually backed by battery. Aug 16, 2022 at 20:13
• You should consider other system solutions. How accurate does this elapsed time need to be? How often do you lose power? Maybe write once per day instead? Aug 16, 2022 at 20:46
• With a super-cap and a power failure circuit you could write the data on the event of power outage. Aug 16, 2022 at 21:26
• "Save the amount of elapsed seconds" - between what? Are you just trying to save the elapsed time between two events? That only requires a few bytes, depending on the dynamic range required. Aug 17, 2022 at 0:02

Each segment is 4096 bits. Erasing turns all the bits to ones. Writing can only set bits to zero.

If you store the erase timestamp in the first 64 bits, that leaves 4032 bits. If you set a bit to zero every second without erasing the page, each page can last for 4033 seconds. So that multiplies your endurance calculation by 4033.

This will only work if the flash doesn't have ECC. If it does, then rewrites will make the error detection codes invalid, and it will most likely crash.

Note that power to the micro must absolutely never be shut down during a flash write. If that happens, the behavior is usually undefined, which means the controller may write garbage into random pages unrelated to the one you're writing to, or other undesirable things that will brick it.

I have never tried this, and honestly I would recommend using battery backed up RAM instead. If your micro has 1.5M of Flash it most likely already has a special RTC power domain that can keep some data around for years on a coin battery.

• Assuming that you can write 4033 times to the same page without erasing it. Sometimes there is a limit. Aug 16, 2022 at 21:46
• We used to use this feature. There was a counter in the data block. When it was close to the lifecycle limit, we would write all 1s to that block. So, we didn't need another counter or a hash table etc. Aug 17, 2022 at 1:17
• I like this solution and I will be stealing this algorithm in the future! Aug 17, 2022 at 2:13
• In many cases, it will be possible to ensure that power can only be lost during flash-erase operations, rather than flash-program operations (e.g. by ensuring that the CPU would be forcibly reset, preventing it from trying to initiate a flash write, while there's enough stored energy to let any pending program operation run to completion). If that is indeed possible, then algorithms can be designed to be robust even if every attempt to read a partially-erased were to independently yield the most vexing bit patterns possible. Aug 17, 2022 at 18:41

You can use something called FRAM, it runs at memory speed and will support trillions of cycles. A small cap would keep it up while you write. You could also save your results in several locations, whatever works for you. The ones I use are 32K x 8 and cost less than \$5 US. You could also place each write into a new location, you have 32K of them. If a write fails the previous one will still be there as the previous ... etc. You could write with a checksum and validate that to check the last write.

Option 1: Do you need the result to be second accurate, or is it only providing an approximation to the runtime? You can use probabilistic/approximate counting to (say) increment with probability 1/600 every second to get a 600-fold reduction in writes. You may tune your probability. You can also have multiple levels of approximation. After running for 2 days, you can then switch to only incrementing with probability 1/86400. Then after running for 2 months, switch to probability 1/2592000 (there are more formal ways of specifying this backoff if you read the literature in this area). While you can also do this via only incrementing the counter when time()%86400==0, if someone was trying to work around something that this was defending against they could turn off the system at the correct time--where as probabilistic increment cannot be gamed in that way, at least not if the probability is truly random.

Option 2: Have the first block be the base sum of seconds and a bitfield of seconds as bobflux suggested. Have the second block be a backup of the base sum of seconds an a continuation of the bitfield (the backup is so that if you lose power when you are updating the counter you can recover, as @supercat was complaining about). Then have another 8 blocks which are just bitfield counter extensions. The time is stored as the base + the number of 1 bits set in the 40832 bit long bitfield). Every second, you set bit (now()-base) in the bitfield. When you run out of space, erase block zero, write the new base, then erase blocks 1-N and write the backup base. Using this approach, you can store 129 years worth of data. Need more time? Increase the number of blocks. Need less time? Decrease. For example, using only 4 blocks gives you 64 years.

The two techniques can be combined to allow (essentially) infinite counters.

You've gotten a number of solid answers already, but there's another I haven't seen mentioned.

At least assuming you have other data to store in the same flash that gets written substantially less often, you could do some wear-leveling, kind of like most SSDs, thumb-drives, etc.

The basic idea is to start with a block that tells you the locations of data you care about. Choose a location for your seconds counter, and update it in that location until you've used something like 90% of that location's writes. Then put some data in that location that rarely changes, and put the seconds counter into a new location that still has lots of write cycles left available.

Follow a deterministic algorithm for choosing a new location, so knowing the current location tells you which blocks have already had their write life mostly used up, so it's relatively easy to choose a new, nearly-virgin location to use.

With reasonably typical data usage patterns, this can easily extend the life out beyond any reasonable estimate of the system's likely lifetime.