A quick guide to using the flash on the ESP8266

If you’re anything like me, and learning how to use micro controllers, you have probably learned that there is value in being able to save data, or settings between power cycles of your device.

For a long time, there was a significant learning curve, and no good explanation of how that would work.  However, during a recent project, the incentives to learn became significant enough, that I took it upon myself to do research, and piece together what tidbits I could find, until things started making sense.

Now that I have a working knowledge of the process, I though I might attempt to share that information, so that the learning process might be easier for others.

First, flash memory structure.

It is imporant to understand that memory ultimately deals with bits and bytes.  When you look at your ESP8266, and it says that it has 4MB of flash or 32Mb, what that means is, there are actually 4,194,304 bytes, or 33,554,432 bits.

Hypothetically, the smallest amount of data that you can work with at one time is 1 byte, meaning that any data value/setting will occupy, at minimum, 8 bits.

Imagine all of this as if it were a book, with enough room for 4,194,304 letters (each letter is equal to 1 byte).

As a rough estimate:  If each word is 6.1 characters, that would be enough room for ~686,919 words.  In comparison, Harry Potter and the Order of the Phoenix is 257,045 words.

Now, in addition to the memory being divided into bytes, the memory is divided into sectors of of 4096 bytes.  These sectors are a way of managing the memory.  When you want to save data, you have to use a whole sector, even if your data is only a few bytes.  However, if your data is more than 4096 bytes, you can split that data into multiple sectors.

Thinking of a sector as a page, If you want to write anything at all, it has to go on one of these pages.  If you write a single letter, it takes a page, if you want to write a sentence, or paragraph, it takes a page, even if it doesn’t fill it up.  If you write a chapter, it may take up several whole pages, plus a little bit of another page.

Second, reading the flash memory.

When you want to start reading from Flash, you have to know two things: the address to start at, and the number of bytes to read (length).

In shool, you may have received instructions from a teacher, “Read chapter 3, on page 148”.  You would then, without thinking about it, start on page 148, and read until you reached the end of chapter 3.  However, when dealing with computers, you have to be very literal.  The computer doesn’t know what the end of chapter 3 looks like, it doesn’t know the end of chapter 3 from the beginning of chapter 4.  A better way of giving instructions would be, “Start reading at the beginning of page 148, and read for 2737 characters”.

Additionally, when reading from flash memory, you need to know how the data you’re reading is structured.  If you previously wrote data with a structure, that consisted of:

  • int (1 byte)
  • long (4 bytes)
  • long (4 bytes)

it was written as a total of 9 bytes, one after the other, into flash memory.

In the context of a book, it would be akin to writting a sentence without spaces.  You would take some letters that make sense to you, “i love cats”, (1 character, 4 characters, 4 characters) and write them on the page in a little less organized, but more compact, way “ilovecats” (9 characters).

Later, when you come back to read that data out of flash memory, you need to make sure that you read it into the same structure that you wrote it from. (1 byte, 4 bytes, 4 bytes)

If you don’t do that properly, you’re going to be data out, but it won’t be accurate and wont’ make sense.

So, when reading the letters we wrote earlier, you need to know how it was organized before, if you read letter back from the page incorrectly (4 characters, 4 characters, 1 character) instead of 1, 4, and 4 characters, you get incomprehensible words: “ilov ecat s”.

In C, the language that was used for programming the ESP8266, this is done be creating a data structure, the same that was used to store the data before it was written, and then effectively, read the data from flash, into that data structure, that way, ints, longs, and strings end up where they are supposed to.

Third: Writing to flash memory.

When writing to memory, you have to erase the entire sector first, you can’t just write to the first 9 characters of the sector, instead, you have to erase all 4096 bytes, and then write 9 bytes of data, and effectively, 4087 bytes of nothing.

Like, when writing in a book, you have to start with the clean page, you can’t erase the first 9 letters of the page with existing content, and then add your own stuff.  If you want to add something, you need to erase the whole page, and then add your content.


When you see documentation referring to the memory addresses, these are the address for the start of a sector.  Each of these sectors are 4096 bytes long.  The first sector starts at 0x00000, the second sector starts at 0x01000, etc.

### Flash size 32Mbit-C1: 1024KB+1024KB
    boot_v1.2+.bin              0x00000
    user1.2048.new.5.bin        0x01000
    esp_init_data_default.bin   0x3fc000 (optional)
    blank.bin                   0xfe000 & 0x3fe000

In the scenario above, these different files are going to be written to flash memory, starting at the specified addresses, and continuing on for as many sectors as necessary, until the entire file is written.

To illustrate this idea further, take a look at the Google Sheet showing the flash layout for my project.

The boot.bin files is written to sector 0x00000, and takes up all 4096 bytes.

The user1.4096.new.4.bin file (my application) is written to flash starting at address 0x1000, and, because it 302080 bytes in size, it will fill up all the sectors until 0x4C000.

Hypothetically, I could save my data to any sector that isn’t being used by some other file.  I decided to use a sector near the “end” so that it is far away from my other files, and isn’t likely to be accidentally overwritten if I work on my program, and it grows in size.  The address that I used was 0x7B000.

Because my settings persist between power cycles, if I want those settings to be erased, I can write blank.bin to that same address (0X7B000), if I don’t write blank.bin to that address, the program will be able to load those settings once it powers back up.


Learning how to integrate the ESP8266 chip into a project.

For a while now, I’ve been wanting to create a sensor network that will help me keep an eye on my garden.  I had heard of the Esp8266 chip, and was very interested in integrating that micro controller into my design, but I hadn’t any experience with a non-arduino device.

My objectives were:

  • Learn how to program an ESP8266 chip.
  • Establish the groundwork for an expandable sensor network.
  • Establish a basic bi-directional communication platform.

In an effort to achieve these goals, I decided to embark upon a project to make a Morse transmitting device.



The design consists of a central web server, and ESP devices functioning as clients.

For a less responsive, but more flexible configuration, the ESP clients will check in with the server at a regular interval for commands that have been queued up.  Upon finding commands, the client will request one command at a time, executing each, until the queue is empty.  This design requires less knowledge of networking, and eliminates the need to configure a firewall.  This design becomes more beneficial as the number of ESP clients on a network increases.

An alternate design, not fully implemented, but more responsive, is to have the Web Server function as a client, and make requests to the ESP hosts as soon as a command is issued.  The greatest drawback to this design is that it would require the opening of ports in a firewall, a prospect which becomes more daunting when there are multiple devices on the same network.

In this case, the server has a list of submissions that will be transmitted when someone selects them for transmission.  Additionally, recurring messages can be configured, with an interval (in minutes) at which they should be transmitted.

A cron job runs at a specified interval, and checks for configured recurring messages.  If it finds that the difference between the current time and the last transmission is greater than the configured transmission interval, it will queue commands for the devices, and wait for a request for the message string.

Upon checking with the server, if the ESP client finds a command to start a transmission, it makes a request to the server for a string to transmit.  Upon completion of that transmission, it requests the next section of the string.  If there is none, the device stops transmission.

To keep this project simple, a website allows a user to view a list of preconfigured submissions, and queue it up for a device.  Additionally, a user may follow along with the devices transmission of the submission.


The files for this project can be found on GitHub: https://github.com/abradburn

Photos of the layout can be found on Google Photos: https://goo.gl/photos/aCAtACVjU1uPTc9E6