User Guide¶
This guide is for researchers who need to flash and commission an ESP32-H2 board as a Thread RCP device.
1) Prerequisites¶
Linux (recommended)¶
- USB cable connected to the native ESP32-H2 USB port on the dev board.
- Shell access with Python available.
- Repo cloned locally.
Windows (native)¶
- ESP-IDF installed via Espressif Installer Manager.
- Use ESP-IDF PowerShell terminal.
- USB cable connected to the native ESP32-H2 USB port on the dev board.
WSL2 is not supported for this workflow.
2) Board Connection And Port Detection¶
The ESP32-H2-DevKitM-1 has two USB-C ports. Use the native ESP32-H2 USB port, not the CP210x UART bridge port.
Find your board port:
Linux:
ls /dev/ttyACM*
Windows:
- Open Device Manager.
- Expand
Ports (COM & LPT). - Plug/unplug board to identify the
COM*port.
3) Setup And Build¶
Linux¶
./scripts/setup.sh
. "${HOME}/esp/esp-idf/export.sh"
./scripts/doctor.sh
./scripts/build_rcp.sh
Windows (ESP-IDF PowerShell)¶
cd firmware\rcp
idf.py set-target esp32h2
idf.py build
4) Upload (Flash) Firmware¶
Linux¶
PORT=/dev/ttyACM0 ./scripts/flash_rcp.sh
Windows¶
idf.py -p COM3 flash
Replace COM3 with your board port from Device Manager.
If Linux reports Permission denied, run:
sudo usermod -a -G dialout "$USER"
Then log out and back in.
Default workflow does not include erase-flash so NVS is preserved.
5) First-Flash Boot Mode (if needed)¶
If flash does not start on a blank board:
- Hold
BOOT. - Press and release
RESET. - Release
BOOT. - Retry flash.
After first successful programming, auto-reset is usually enough.
6) Commissioning Checklist¶
After uploading firmware, validate readiness before field use.
- Open monitor and confirm stable boot: Linux:
PORT=/dev/ttyACM0 ./scripts/monitor.sh
Windows:
idf.py -p COM3 monitor
- Confirm no crash/reboot loops in serial output.
- Confirm host-side Spinel link initializes without timeout errors.
- Confirm target system can communicate over the Thread network.
7) Quick Recovery¶
If commissioning fails:
- Re-check you are on native ESP32-H2 USB port (not UART bridge port).
- Re-check port detection (
/dev/ttyACM*orCOM*). - Run clean rebuild:
cd firmware/rcp
idf.py fullclean
idf.py set-target esp32h2
idf.py build
- Reflash and monitor again.
8) Validation Gates¶
Flashing alone is not success. Validate at four stages:
| Stage | Check | Pass Criteria | Fail Indicators |
|---|---|---|---|
| 1. Flash | Firmware upload result | Exit code 0, no write/hash errors |
Non-zero exit, write failure, hash mismatch |
| 2. Boot | Serial monitor output | Clean startup, OpenThread RCP init messages, no crash loop | Guru Meditation, watchdog resets, reboot loop |
| 3. RCP Link | Host-side Spinel attach | Host connects without timeout, stable agent process | spinelFrame timeout, TimeoutError, repeated reset failures |
| 4. System | End-to-end Thread operation | Nodes attach and telemetry flows to host stack | Join failures, no traffic, unstable links |
Treat a board as deployment-ready only if all four stages pass.
9) Troubleshooting Triage¶
| Symptom | Likely Cause | Fix |
|---|---|---|
/dev/ttyACM0 not found |
Wrong cable, wrong USB port, disconnected board | Use native ESP32-H2 USB port, verify cable, reconnect board |
Permission denied on /dev/ttyACM* |
Linux user not in dialout |
sudo usermod -a -G dialout "$USER" and log in again |
| Flash repeatedly fails on first attempt | Board not in download mode | Hold BOOT, tap RESET, release BOOT, retry flash |
Host reports spinelFrame timeouts |
Wrong hardware port (UART bridge instead of native USB) | Move cable to native ESP32-H2 USB port |
Host reports spinelFrame timeouts after flash |
Firmware built with UART transport | Confirm CONFIG_OPENTHREAD_RCP_USB_SERIAL_JTAG=y, then idf.py fullclean and rebuild |
idf.py: command not found |
ESP-IDF environment not loaded | Linux: . "${HOME}/esp/esp-idf/export.sh"; Windows: use ESP-IDF PowerShell |
| Stale or inconsistent build behavior | Old build cache / target residue | cd firmware/rcp && idf.py fullclean && idf.py set-target esp32h2 && idf.py build |
Spinel timeout log pattern:
universal_silabs_flasher.spinel DEBUG Device did not respond to reset
...
TimeoutError
[WARNING] otbr-agent exited with code 1
Recovery sequence:
- Confirm cable is on native ESP32-H2 USB port.
- Confirm host sees expected serial device (
/dev/ttyACM*orCOM*). - Confirm firmware transport symbol in
firmware/rcp/sdkconfig.defaults. - Run clean rebuild.
- Reflash and monitor boot logs.