Build, upload, and monitor firmware on the ESP32-C3. TRIGGER when the user asks to flash the device, check serial output, build firmware, set up OTA, or debug a build/upload failure. DO NOT trigger for host-side test runs (use /tdd) or for hardware wiring questions (use /hardware).
platformio.ini defines two environments:
| Env | Target | Purpose |
|---|---|---|
esp32c3 | Seeed XIAO ESP32-C3 / DevKitM-1 | Real firmware |
native | Host (Mac) | Unit tests only — see /tdd |
Always specify -e explicitly. Forgetting it builds both and confuses errors.
pio run -e esp32c3 # compile only
pio run -e esp32c3 -v # verbose — use when link errors are obscure
A clean rebuild:
pio run -e esp32c3 -t clean && pio run -e esp32c3
ESP32-C3 has built-in USB-serial-JTAG. No DTR/RTS reset dance; esptool
triggers via USB CDC. Plug into the Mac's USB-C port directly.
pio run -e esp32c3 -t upload
If upload fails with Failed to connect:
ls /dev/tty.usbmodem* — the port must appearupload_speed = 460800 to platformio.inipio device monitor -b 115200
Exit: Ctrl-C then Ctrl-]. Or use pio device monitor --filter=esp32_exception_decoder
to get readable crash backtraces.
pio run -e esp32c3 -t buildfs # build the FS image from data/
pio run -e esp32c3 -t uploadfs # flash the FS image (wipes existing FS)
uploadfs is destructive — it erases any buffered batches stored on the
device. Don't run it on a unit that's been collecting data in the field
without first pulling the ring buffer contents via scripts/decode_capture.py
over serial.
After the device has been provisioned once, OTA is the preferred path — you don't want to climb to the mast to re-flash.
pio run -e esp32c3 -t upload --upload-port imu4.local
OTA requires the device to be on BigAir2.4 and reachable. If OTA is
unavailable (wifi down, firmware panicking in boot), fall back to USB.
ESP32-C3 panics print a register dump and a backtrace of PC addresses. The monitor filter decodes them against the ELF:
pio device monitor --filter=esp32_exception_decoder
If the filter isn't showing symbols, confirm the build on the device
matches the ELF at .pio/build/esp32c3/firmware.elf. A mismatch after
OTA means you're decoding against the wrong binary.
Serial.begin()
is missing or runs too late, you won't see early boot logs. Use
CORE_DEBUG_LEVEL=5 in platformio.ini for verbose core loggingmonitor_filters = esp32_exception_decoder in platformio.ini is
preferred over the CLI flag — it persists across invocations