Jul 31

Mitigating FLASH wear on the ESP8266 (or any other microcontroller with attached FLASH memory)

Category: Design,electronics  , — Published by goeszen on July 31, 2017 at 8:22 pm

The ESP8266 has a user-writeable FLASH chip attached to the CPU via SPI. They are even separate units on common dev boards (in contrary to the ESP8285 which has the FLASH memory integrated into one tiny all-in-one package).

As with all FLASH media, this SPI Flash is subject to write wear, where each storage unit allows for only a certain amount of flip-cycles until it gets unreliable or unresponsive. Or the number of write operations flash can endure, known as program/erase (P/E) cycles. This limitation, as it leads to data corruption, will inevitably lead to errors and crashes, or data rot or data loss. But read this again, it's "write wear", reading FLASH memory doesn't do any harm.

In my specific use case, the reason why I'm thinking about FLASH memory and it's endurance, life expectancy, end-of-life, finite lifetime or MTBF is because one sketch I'm running on an ESP8266 came to a point where I wanted to keep some data over reset / power-loss cycles. It has a display and a few operating modes the user can flip-through by pressing a button. And now I wanted the ESP to "remember" the mode the user selected over pressing the RST button, and over disconnecting the ESP from power. So I threw in the EEPROM library, which is the ESP's facility of accessing flash memory. And I wrote() and commit()ed the button state to FLASH every time the user toggled the mode.

I already knew that writing to FLASH from the loop() would be the worst idea! Don't ever do that! Also, I didn't want to attach a timer / Ticker / interrupt to trigger a commit() every x seconds. The slowest, most infrequent thing I could think of was, actually, the user pressing this button. (and I made sure this button event was properly debounced, btw.) But still, this event happens a few times per use, and these events add up. So I started thinking..., thinking about how many times the one byte where I was storing the button state would be able to cope with me writing to it.

Apart from that, re-flashing the firmware, which is frequent and common during development imposes the same problem - so it would be good to know how many flash cycles this chip can endure - even if you're not storing runtime values like I need to do.

What does Espressif tell us about the endurance of the used Flash chip?

Well, not much. At least not easily. Usually, FLASH chips come with specifications, and these specs in the form of a datasheet or spec sheet outline how reliable the storage media is. The Arduino AVRs usually spell it out in documentation, I'm hearing that its said there the FLASH being used is expected to fail after about 10,000 write-cycles.

So far I was unable to find what Espressif has to say about the life expectation of the Flash chips in use on the ESP8266. Some fellow tinkerers are discussion flash wear here and here. All spec sheets (listing, datasheet) I found were not giving any numbers. All information I could unearth was

an answer to "Which APIs will write or save data to the flash memory?" in FAQ > Peripherals. This is in relation with people being worried that the flash area where WiFi settings are stored will wear out due to repeated re-setting of such credentials.

The only other section where Espressif mentions wear is in a Tech doc PDF, p. 56,

where the worried user can learn that the firmware tries to write only real changes, and further, indirectly, that Espressif expects the used Flash chip to endure over the life span of the ESP under normal use. How often do you change WiFi settings?

But then there's the ESP8266 Module Reference Design, a .zip file, which contains a Bill of Materials, telling us the Flash is a Flash, SOP8-150mil, FM25Q16/ GD25Q16, the latter being names of (some) Flash chips being used, as it seems used on varying runs of production.

Ah, and there it is, a number, page 3 of the FM25Q16 datasheet:

High Reliability
– Endurance: 100,000 prog
ram/erase cycles
– Data retention: 20 years

and for the GD25Q16:

Cycling endurance
Minimum 100,000 Program/Erase Cycles

That's a surprising high number, given that Arduino folks usually expect the endurance of their common Arduino board's flash chips to be "a few thousand" cycles. But the high numbers explain why Espressif isn't particularly worried about endurance ever becoming a broader topic among tinkerers.

Wear leveling techniques

The guts of this post, finally: There are a number of strategies to prevent wearing out Flash memory, so called wear levelling. Although for most uses the expected endurance of the Flash is high enough, in certain scenarios thinking about being easy on your Flash might be helpful. Here's a list of ideas:

  • Never ever write to flash every few milliseconds, as you would do with RAM! Never on loop(). And better don't do it in a recurring interrupt every few seconds. The way you have to write to EEPROM on the ESP8266 already gives a hint (docs here) that writing and actually commit()in to Flash are separate operations and should be well thought out.
  • Postpone writes to Flash as long as possible. It's on you to write a clever program. Look out if there's an option to have writes happen seldomly. My use-case is that I want to store a toggle button state. But a user probably toggles the button a few times in quick succession and then settles on one position. For this scenario, one idea is to start a timer to do a commit(), restarting the timer each time the user toggles. This introduces a certain threshold, to filter when a user does hectic toggling, and only triggering a commit() when it makes sense, decoupling button-press and commit.
  • Spread your writes over a number of bits / bit array! Don't just write to one bit address on the Flash, but use an array of them. In my case, I could use 8, 16, 256, ... bit positions to encode my 1 and 0 of the toggle switch. Each time I write to Flash I increment the position of the write by 1, building a bit-map, an array of bits on Flash. Each time I want to know if my state is 1 or 0 I iterate over the array and count the 1s and 0s - even is 1, odd is 0. Or do it in proper binary encoded form, 11111111, then 01111111, then 10111111, 11011111, and so forth.
  • Don't actually store on the ESP8266. This little device has WiFi built-in, and you probably use it already. Get (read) your configuration settings over-the-air, OTA, from the Cloud. And write to the network, to another machine on local LAN, MQTT, websockets, some a key-value-store service on the Internet, you get the idea.
  • Lastly: A switch. A physical toggle. Simple as that. Think out of the box. In my use case I want the user to be able to toggle between operating modes, and this toggle's position I want to remember over power-cycles and resets. Easy: make it a physical toggle switch on your device, maybe a DIP switch on the back or some hidden position. It depends. Remember the bold toggle on earlier iPhones?, or your old transistor radio buttons? Click-clack. Product design gold.

Is there a penalty in writing to Flash in terms of how long it takes?

Thatr was one last lingering question in relation to storing data in Flash / EEPROM that came up for me. It's somewhat an open one.

The datasheet of the GD25Q16 has this information:

-Page Program time: 0.7ms typical
-Sector Erase time: 50ms typical
-Block Erase time: 0.2/0.28/0.6s typical

and the FM25Q16:

Typical page program time: 1.5ms
– Typical sector erase time: 90ms
– Typical block erase time: 500ms

In my sketch I have a timing facility for every loop, and I've noticed that sometimes when the sketch writes to EEPROM (one integer) the time one loop takes spikes to 40-50ms - but that's a very unscientific observation - but it nurtures my hunch that it takes a few ms to do an EEPROM write.

If you can confirm / correct anything said above, do so please in comments!


This post is part of a series of Mini Tutorials on the ESP8266 / Arduino IDE:
Previous post: Fixing being unable to access tty on Ubuntu - ESP8266 and Arduino
Or visit the YouTube Channel.

Leave a Reply