ESP32 (4) – Flash, bootloader and FreeRTOS

luca 22/12/2016 8

In the previous posts I’ve described the new esp32 chip and explained how to setup the development environment, including the use of one – optional – graphical IDE, Eclipse.

Before starting to develop your programs, you need to understand three key components of the framework: flash, bootloader and FreeRTOS operating system. But don’t worry! At the end of this post you’ll write, compile and execute your first program (even if “minimal”) and starting from the next tutorial we’ll work together on more complex examples.


As I wrote in the first post of this tutorial, the esp32 chip requires an external flash memory to store programs, data, configuration parameters…

The external memory is connected to the chip via the SPI bus and the supported capacity is up to 16Mb. The official Espressif module (ESP-WROOM-32) includes a 4Mb flash memory made by GigaDevice (GD25Q32):


The flash memory can store different elements: programs, data… hence it’s divided into sections (partitions). The list partitions, their size and position within the flash memory is stored in the memory itself (at address 0x8000) and it’s called partition table.

Two partition types are defined by default:

  • app (type 0) – partition that contains an application (program)
  • data (type 1) – partition that contains data

When writing a new program, the developer can decide how to organize the flash memory based on the program’s specific needs. The esp-idf framework offers two pre-configured memory layouts, you can choose from the configuration menu:


You can also show the project’s partition table with the make partition_table command:


In the screenshot above, you can see the partition table layout that corresponds to the simplest configuration (Single factory app, no OTA):

  • a data partition (named “nvs“) with a size of 24Kb starting from address 0x9000
  • a data partition (named “phy_init“) with a size of 4Kb starting from address 0xf000
  • an app partition (named “factory“) with a size of 1Mb starting from address 0x10000


To better understand why the flash memory is divided into partitions, I have to describe you how the esp32 bootloader works, that is how the application is started and how a new firmware is uploaded.

In the esp32 ROM memory there’s a small program, named first-stage bootloader. This program is executed at each reset of the chip: it configures the access to the external flash memory and, if required, stores on it new data coming from the serial/USB port (flash process). Once finished, it accesses the flash memory (at address 0x1000) and loads and executes the second-stage bootloader.

Even if the standard behavior of the esp-idf framework is to use this second-stage bootloader, you can also develop a stand-alone application that, stored at address 0x8000 of the flash memory, is directly executed by the first-stage bootloader.

The second-stage bootloader reads the partition table at address 0x8000 and searches for app partitions. It decides which application has to be executed based on the content of the otadata partition: if this partition is empty or doesn’t exist, the bootloaded executes the application stored in the factory partition. This allows to implement an over-the-air (OTA) application update process: you send the new version of your application to the esp32 chip; the version is stored in a new app partition. Once the upload is completed, the id of the partition is saved in otadata and the chip is rebooted; the bootloader will execute the new version:



The esp-idf framework is based on the FreeRTOS Real-Time Operating System. It may sound strange to talk about operating systems when working on a “small” chip like the esp32… but you don’t have to think that FreeRTOS is an operating system like Windows, Linux or MacOS. The main feature an embedded operating system offers – thanks to its internal scheduler, is multitasking, that is the ability to run different tasks in parallel. We know that a microprocessor core can execute an instruction at a time: it seems that different applications run simultaneously because of the scheduler is rapidly switching between their tasks.


different task statuses in FreeRTOS

A real-time operating system is design to guarantee that task scheduling is deterministic: you can predict the behavior of its scheduler. FreeRTOS allows the developer to define a priority for each task: the scheduler uses priority values to define the execution pattern of the different tasks.

Our first program

Let’s write our first program that used the esp-idf framework. This program, available in my Github repository, will be the skeleton for all the next tutorials.

First we must include some libraries:


The stdio.h library (Standard I/O) is used for input/output functions (printf…) and the two freertos header files are used to define and execute the different tasks.

Every program is executed starting from the app_main() function:


In the app_main() a new task is created using the xTaskCreate method. This method requires the following parameters: the pointer to the function (&loop_task) that contains task code, the name of the task (“loop_task”), the size, in words, of the stack memory to be assigned to the task (512), additional parameters for the task (NULL), the task’s priority (5) and the pointer – optional – to retrieve an handler of the task (NULL).

Once the task is created, the FreeRTOS scheduler executes it based on the different tasks and priorities.

The task has the following code:


it’s a continuous loop that every second prints the sentence Hello World!”. The vTaskDelay method pauses the task for the specified number of ticks. The portTICK_RATE_MS constant defines the duration, in milliseconds, of a tick; if you therefore divide 1000 for that constant you get the number of ticks in a second.

Additional files

To be able to compile your project, you need to add a couple of additional files:

  • a Makefile in the main folder of your project that contains the name of the project and an include for the main makefile of the framework:


  • file – it can be empty – in the folder where the source code is saved into to tell the compiler to process the files in that folder:



When the program is ready, you can compile and load it on the board as explained in a previous post:

make flash

If everything is ok, when you connect to the board with a serial emulator you should see:




  1. Mauro 24/12/2016 at 18:53 - Reply

    Ottimi articoli (mi riferisco anche alle puntate precedenti) chiaro e coinciso: capito tutto in un baleno–
    Spero nelle prossimi si esamini il framework per accedere ai pin (accendere led e leggere un valore analogico….) e magari usare i due core (esp32 ha 2 core invece di uno del esp8266).
    Comunque grazie e attendo con trepidazione la prossima puntata..Per Ora Buon Natale e Buon Anno


  2. Michele 04/01/2017 at 15:20 - Reply

    Ottimo tutorial!!!!! Complimenti e molto molto interessante!! …. spero in altri articoli su esp32

    • luca 09/01/2017 at 08:27 - Reply

      Ciao Michele e grazie! Ho postato poco fa proprio un nuovo articolo… ho intenzione di approfondire molto l’utilizzo di questo chip quindi segui periodicamente il blog ;)

  3. Roberto 23/01/2017 at 00:56 - Reply

    Ciao, Sto smanettando anche io con l’esp32, sono riuscito a far funzionare il progetto blink in esp-pdf, poi ho provato a creare un progetto nuovo ed ho copiato il tuo sorgente wifi_scanner ma quando assemblo mi da un sacco di errori, nel tuo articolo dici che “In fase di compilazione del programma, è fondamentale attivare il modulo wifi dal menu di configurazione” ora però non sono riuscito a lanciare questo menu di configurazione? dovrebbe apparire quando lancio il make?

    • luca 23/01/2017 at 08:40 - Reply

      Ciao Roberto… si la prima volta che lanci il comando make ti deve apparire il menu; in alternativa puoi lanciare “make menuconfig” per eseguirlo esplicitamente. Ti consiglio di seguire tutti i tutorial dall’inizio: da quello che scrivi sembra che il tuo ambiente di compilazione non sia configurato completamente.

  4. flyword 08/09/2017 at 13:38 - Reply

    hey! once I run the original code, the ESP32 board will get panic,and finally I discovery that the parameter “512” should be set as 1024 or 2048 in the function xCreateTask() ,then the program will run perfectly,why??

    • luca 08/09/2017 at 23:47 - Reply

      Hi, that parameter is the stack size, so it depends on how much memory (= variables…) the task will allocate

Leave A Response »

Click here to cancel reply.

This website uses cookies to ensure you get the best experience on our website maggiori informazioni

Questo sito utilizza i cookie per fonire la migliore esperienza di navigazione possibile. Continuando a utilizzare questo sito senza modificare le impostazioni dei cookie o clicchi su "Accetta" permetti al loro utilizzo.