mirror of
https://github.com/liquidraver/ZephCore.git
synced 2026-10-22 12:42:34 +00:00
DESIGN.md is the reconciled high-level design after the 2026-09 restructure: system context, roles, build-time composition, layers and dependency rules (with the known exceptions), threading and event loop, end-to-end flows, cross-cutting concerns and the upstream alignment policy. docs/adr/ holds the nine decision records (ESP32 boot layout, S3 native USB, overlay precedence, BLE privacy, Zephyr main pin, SX126x duty cycle and RX-busy gating, adaptive contention window, storage backend, WiFi companion boards). ARCHITECTURE.md stays the detailed component reference and links both. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
69 lines
4.4 KiB
Markdown
69 lines
4.4 KiB
Markdown
# ADR 0001 — ESP32 boot: simple boot for plain builds, MCUboot for OTA builds and releases
|
|
|
|
Status: accepted (recorded 2026-09-25)
|
|
|
|
## Context
|
|
|
|
**ESP32 flash** — Zephyr uses `CONFIG_ESP_SIMPLE_BOOT` by default (no MCUBoot). The standard build produces a
|
|
self-contained `zephyr.bin` that the ESP32 ROM bootloader loads directly from `0x0`. Just `west flash` — no
|
|
`--sysbuild`, no ceremony, works on a bare chip:
|
|
|
|
```bash
|
|
west build -b <board>/esp32s3/procpu zephcore --pristine
|
|
west flash --esp-device COMX
|
|
```
|
|
|
|
**Exception — WiFi AP OTA** (`wifi_ota.conf`): the HTTP OTA updater writes to MCUBoot slot1 and requires
|
|
MCUBoot. When building with `wifi_ota.conf`, add `--sysbuild` and flash once to seat MCUBoot:
|
|
|
|
```bash
|
|
west build -b <board>/esp32s3/procpu zephcore --pristine --sysbuild -- \
|
|
-DEXTRA_CONF_FILE="boards/common/wifi_ota.conf"
|
|
west flash --esp-device COMX
|
|
```
|
|
|
|
Subsequent OTA-capable builds still need `--sysbuild`; plain builds without `wifi_ota.conf` do not.
|
|
|
|
**`repeater.conf` pulls `wifi_ota.conf` in by itself on S3/C-series boards, so ESP32 repeater builds always need
|
|
`--sysbuild`.** The ESP32 auto-include block in `CMakeLists.txt` appends it whenever the platform is `esp32`, the
|
|
build is classified as repeater (from the user conf *names* — `repeater.conf` — or
|
|
`-DCONFIG_ZEPHCORE_ROLE_REPEATER`; checked against Kconfig after `find_package`), and the board is not a classic
|
|
`/esp32/` one. Without `--sysbuild` the app still comes out built *for* the MCUboot slot
|
|
(`CONFIG_BOOTLOADER_MCUBOOT=y`, `CONFIG_FLASH_LOAD_OFFSET=0x10000`) but is never signed: `west flash` writes it to
|
|
`0x10000`, leaves `0x0` untouched, and whatever MCUboot is already there rejects the unsigned header. The symptom
|
|
is not a build or flash error — both report success and the hash verifies — but the board stops enumerating USB
|
|
entirely, and only the BOOT button gets it back. Companion builds on the same boards really are simple-boot
|
|
(`CONFIG_ESP_SIMPLE_BOOT=y`, load offset `0x0`), which is why this bites only when switching a board to the
|
|
repeater role.
|
|
|
|
**GitHub Release artifacts diverge from the plain-build default.** `build.sh` always builds S3/C-series boards
|
|
(`heltec_wifi_lora32_v3/v4/v43/v4_r8`, `station_g2`, `xiao_esp32s3`, `xiao_esp32c6`, `lilygo_tlora_c6`,
|
|
`heltec_wireless_tracker`, `thinknode_m9`) with `--sysbuild`, regardless of `wifi_ota.conf` — `sysbuild.conf` at
|
|
the repo root forces `SB_CONFIG_BOOTLOADER_MCUBOOT=y` whenever `--sysbuild` is passed. So the published release
|
|
for these boards is always an MCUboot layout (MCUboot @ `0x0`, signed app @ `0x10000`), never the simple-boot
|
|
`zephyr.bin`. (The app slot is at `0x10000` — right after the 64 KB MCUboot region, matching the
|
|
Arduino/ESP-IDF app offset; it was `0x20000` before 2026-07-09. The flash map lives in per-board
|
|
`boards/esp32/<board>/partitions.overlay`, fed to **both** the app and the MCUboot image via
|
|
`sysbuild/CMakeLists.txt` so their slots match. Before that split, `board.overlay` reached only the app, so
|
|
MCUboot used the upstream base table and looked for OTA images at a different `image-1` address than the app
|
|
wrote them to, silently reverting every WiFi-OTA update on the slot-customizing boards.) Only `-merged.bin`
|
|
(MCUboot + signed app, esptool `merge-bin`) is published for them — the signed app alone isn't bootable
|
|
standalone and isn't shipped (see [GH #42](https://github.com/liquidraver/ZephCore/issues/42): publishing it as a
|
|
"plain .bin" caused bricked boards when flashed like classic-ESP32's self-contained image). Classic ESP32 boards
|
|
(T-Beam, PICO-D4 — chip name `esp32`, not `esp32s3`/`esp32c*`) still use simple-boot and ship a genuinely
|
|
self-contained plain `.bin` at the `0x1000` ROM bootloader offset. Flashing `-merged.bin` via
|
|
`west flash`/`esptool write_flash 0x0 <file>` only touches MCUboot + the app slot — it does not reach
|
|
`storage_partition`/`lfs_partition` (identity, prefs, contacts, BLE bonds), so it's safe for routine updates as
|
|
well as first flash.
|
|
|
|
## Decision
|
|
|
|
Plain local builds of S3/C-series companions stay simple-boot; repeater builds and every release build use
|
|
MCUboot (`--sysbuild`), with one per-board `partitions.overlay` shared by app and MCUboot.
|
|
|
|
## Consequences
|
|
|
|
- A repeater build without `--sysbuild` bricks USB silently (see above): always pass it.
|
|
- Releases publish only `-merged.bin` for S3/C-series boards.
|
|
- `sysbuild.conf` sets `SB_CONFIG_BOOT_SIGNATURE_TYPE_NONE` (the RSA default overflows MCUboot's 64 KB slot).
|