← board

What was asked

"does this include what IDF uses? (because likely network buffers etc do eat up some)." — the owner, 2026-09-17

Rung 0 of [[umbrella-an-esp32-image-is-as-small-as-it-can-be]]. Until it had a number, no rung of that umbrella could claim an image fits, because "149 KB for nothing" had no denominator.

How, and why it needed no chip

pxx --doctor already says this box has ESP-IDF (/home/neo/esp/esp-idf, v6.0.1) and the Espressif toolchain (/home/neo/.espressif), and the toolchain ships qemu-riscv32 with an esp32c3 machine. So the measurement is an IDF build plus a boot, entirely local.

idf.py set-target esp32c3 && idf.py build && idf.py size
qemu-system-riscv32 -M esp32c3 -drive file=qemu_flash.bin,if=mtd,format=raw ...

Read the serial log, not idf.py size alone. The static table is a link-time accounting of 321,296 B of "DRAM"; the chip has 400 KiB of SRAM and hands out four separate pools. Only the boot log says what is actually left.

The numbers

Static, idf.py size, esp32c3, IDF v6.0.1:

build Flash .text Flash .rodata DRAM total DRAM .text .data .bss
hello_world 55,146 23,236 46,144 36,372 5,932 3,840
wifi/getting_started/station 552,838 98,872 101,352 70,856 13,184 17,312

Runtime, from the boot log's own heap_init lines:

build RAM Retention Retention RTCRAM pool total
hello_world 215,504 116,496 10,576 8,132 350,708
station 160,480 116,496 10,576 8,132 295,684

And the figure that settles it, printed by the example itself:

Minimum free heap size: 340124 bytes

So startup (main_task stack and friends) costs 10,584 B beyond the pools, and IDF's total SRAM cost for a do-nothing app is 409,600 - 340,124 = 69,476 B — 17% of the chip.

The answer to the question as asked

Ours to spend: 340,124 bytes with no networking linked.

Linking WiFi costs 55,024 B of pool before any buffer is allocated (215,504 -> 160,480), which tracks the +55,208 B static DRAM delta to within alignment. Applying the same 10,584 B startup overhead projects ~285,100 B free at app_main for a networking image — marked as a PROJECTION because the station example never reaches its own heap print (below).

Against that budget, our NilPy print("hi") needs data+bss = 146,612 B (i386 and arm32, identical; 152,880 on x86-64):

It fits in both.

What is NOT measured, and it is the half he named

The runtime WiFi buffers. qemu's esp32c3 machine has no WiFi radio model; the instrumented station build boots, prints heap_init, and then stops at eFuse: calibration efuse version does not match and never returns from esp_wifi_init(). Both RUNGZERO heap prints were added and neither was reached. That term needs a chip, and the 55,024 B above is a LOWER BOUND on the networking case, not the answer to it.

Two traps this measurement walks past, recorded so the next one does too

Consequence for the umbrella

The budget is a number now, so the rungs are gradeable. And the direction is the opposite of what the rejected Track U escalation assumed: the SRAM question is not "does it fit" but "how much headroom is left for the heap" — 147 KB static leaves ~193 KB of heap on a non-networking C3, which is where the interesting work is.