What are the files boot_app0.bin and bootloader_dio_80m.bin for? (ESP32 - Arduino IDE)

The ESP32 flash command, as executed by the Arduino IDE, seems to flash two bootloader files: boot_app0.bin at offset 0xe000 and bootloader_dio_80m.bin at offset 0x1000. I wonder what these two bootloader files actually do, and why there are two of them. Below I give some more information.

1. Context

I'm part of a team developing a new, free IDE for microcontrollers: Embeetle IDE. We're planning to support the ESP32 microcontroller family in the near future. Therefore, I'm now studying the ESP32 build system - both the ESP-IDF tool and the Arduino IDE approach to ESP32 projects.

2. Arduino IDE flash procedure for ESP32 projects

After building the .elf file, the Arduino IDE launches a command to convert it into a binary:

python esptool.py --chip esp32 elf2image
                  --flash_mode dio
                  --flash_freq 80m
                  --flash_size 4MB
                  -o /tmp/arduino_build_852524/WiFiScan.ino.bin
                  /tmp/arduino_build_852524/WiFiScan.ino.elf

Finally, this WiFiScan.ino.bin file is flashed to the board, alongside two bootloader files and the partitions table:

python esptool.py --chip esp32
                  --port /dev/ttyUSB0
                  --baud 921600
                  --before default_reset
                  --after hard_reset write_flash
                  -z
                  --flash_mode dio
                  --flash_freq 80m
                  --flash_size detect
                  0xe000  ~/.arduino15/packages/esp32/hardware/esp32/1.0.6/tools/partitions/boot_app0.bin
                  0x1000  ~/.arduino15/packages/esp32/hardware/esp32/1.0.6/tools/sdk/bin/bootloader_dio_80m.bin
                  0x10000 /tmp/arduino_build_852524/WiFiScan.ino.bin
                  0x8000  /tmp/arduino_build_852524/WiFiScan.ino.partitions.bin

The default partitions table, as used by Arduino IDE, looks like this (in csv format):

# Name,   Type, SubType, Offset,  Size, Flags
nvs,      data, nvs,     0x9000,  0x5000,
otadata,  data, ota,     0xe000,  0x2000,
app0,     app,  ota_0,   0x10000, 0x140000,
app1,     app,  ota_1,   0x150000,0x140000,
spiffs,   data, spiffs,  0x290000,0x170000,

The binary equivalent of this csv-file gets flashed to address 0x8000. There are also two bootloader files being flashed to addresses 0xe000 and 0x1000 respectively (see next paragraph).

3. Bootloader files

The two bootloader files being flashed are:

# flashed at 0xe000
~/.arduino15/packages/esp32/hardware/esp32/1.0.6/tools/partitions/boot_app0.bin

and:

# flashed at 0x1000
~/.arduino15/packages/esp32/hardware/esp32/1.0.6/tools/sdk/bin/bootloader_dio_80m.bin

Question 1: What do these two bootloader files do?

It's also interesting to observe their locations. The first one, boot_app0.bin is located in a folder named 'partitions'. It sits there alongside several partition .csv files. Why? But maybe that gets clear when Question 1 is answered.

The other one, bootloader_dio_80m.bin is located in a folder named 'sdk/bin/' and sits alongside other files that all start their name with the 'bootloader_' prefix:

enter image description here

Question 2: As for the bootloader file flashed at address 0x1000, I think the '_40m' and '_80m' suffixes stand for the flash speed in MHz. But I've no idea what the '_dio', '_dout' and '_qout' suffixes stand for.

Please enlighten me ^_^


Answer

Thanks to @Juraj, I now get a better insight into the startup procedure of an ESP32 chip. I believe it looks like this:

  1. FIRST STAGE BOOTLOADER:
    The hardwired ROM-bootloader runs first. This first stage bootloader is outside the Flash memory and cannot be programmed. It loads the second stage bootloader (see next step).

  2. SECOND STAGE BOOTLOADER:
    The first stage ROM-bootloader loads the second stage ESP-IDF Software bootloader at address 0x1000 in Flash. The code here is the bootloader_dio_80m.bin executable, which can be found in the components/bootloader directory of the ESP-IDF framework. This second stage bootloader reads the partition table found by default at offset 0x8000. If OTA app partitions are found in the partition table, the bootloader consults the ota_data partition to determine which one should be booted.

  3. BOOT SWITCH
    The ota_data section can be considered as merely a switch, located at 0xe000 in Flash. It determines if either app0 or app1 should boot. The switch itself is the boot_app0.bin binary. As Juraj says, the 2kB size is also used to take notes during OTA flashing.

  4. APPLICATION
    The application at app0 or app1 executes.

Thank you also for pointing me at these resources:

  • ESP32 bootloader
  • ESP32 startup procedure

The binary at 0x1000 is the bootloader. Arduino ESP32 has bootloader binaries corresponding to boards options in Tools menu in Arduino IDE (built from boards.txt).

The bootloader functions are documented here.

The ESP-IDF Software Bootloader performs the following functions:

  • Minimal initial configuration of internal modules;
  • Initialize Flash Encryption and/or Secure features, if configured;
  • Select the application partition to boot, based on the partition table and ota_data (if any);
  • Load this image to RAM (IRAM & DRAM) and transfer management to it.

The boot_app0.bin is the OTA data partition initial content. It is documented here.

The OTA data partition is two flash sectors (0x2000 bytes) in size, to prevent problems if there is a power failure while it is being written. Sectors are independently erased and written with matching data, and if they disagree a counter field is used to determine which sector was written more recently.

DIO, QIO, DOUT, QOUT are SPI modes for the flash memory. Different esp32 modules have different flash memory chips and their connection. (D is double, Q is quad)