Bare-Metal Ada on the ESP32-S3 A step-by-step guide to running Ada on the ESP32-S3 with no ESP-IDF, no FreeRTOS, and no Python.

Step 07 of 13

What a build actually does

Five steps from your Ada to a flashable image, and two small host tools — both written in Ada — that replace esptool entirely.

The five steps

build.sh sets the profile and heap size, then the shared bare_build.sh:

  1. Regenerates or selects the runtime crate for the chosen profile. Cached after the first time.
  2. Compiles your Ada against that pinned runtime with gprbuild, producing a relocatable ada_app.o (with Main renamed to _ada_main).
  3. Compiles the shared bare bootstart.S, the interrupt vectors, the heap, and a freestanding libc — plus the example's C console glue.
  4. Links it all against the linker scripts into app.elf.
  5. Packages app.bin: image header plus segments.

Then flash.sh writes three images: the 2nd-stage bootloader, the partition table, and app.bin.

esp_elf2image — ELF to flash image

Turning app.elf into app.bin is more than a copy. The on-flash format the ROM and our bootloader expect has:

esp_flash — writing it to the chip

The flasher speaks the chip's ROM serial bootloader protocol directly. It is 100 % Ada: the OS serial interface (termios raw mode, the TIOCM* DTR/RTS modem lines, poll/read/write) is bound to libc through Interfaces.C, with no C source. The sequence, with no RAM stub and no compression:

  1. Reset into download mode — the USB-JTAG DTR/RTS pulse.
  2. SYNC — the handshake, repeated until the ROM answers.
  3. SPI attach and set-params (flash geometry).
  4. Per file, flash_begin (erase) then flash_data in 1 KB blocks, each carrying the ROM's XOR checksum.
  5. flash_end, then a hard reset to run.

A typical invocation writes the three images at their flash offsets:

esp_flash -p /dev/ttyACM0 --flash-size 2MB \
  0x0     bootloader.bin \
  0x8000  partition-table.bin \
  0x10000 app.bin

A ~225 KB image flashes in about three seconds. That is ROM speed — no stub, no compression. Note that only flash is written; the external PSRAM is mapped at runtime by the 2nd-stage bootloader.

Everyday build tips

GoalCommand
Rebuild after editing Ada./build.sh again, then ./flash.sh
Force the Ada to rebuildrm -f main/app_main.o
Force the runtime to regeneraterm -rf crates/esp32s3_rts/*-esp32s3
Use esptool instead (optional fallback)ESP_USE_ESPTOOL=1 ./build.sh (and ./flash.sh)