Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

STM32 / Cortex-M Workflow (Preview)

STM32 (and Cortex-M in general) is a Champion-tier preview in esphome.cloud. The flash / monitor / debug-probe surface is in espctl today; the cloud build executors land tier by tier.

Status (2026-05-24). What works locally now: discover and claim a USB debug probe, flash a pre-built Cortex-M flash bundle via probe-rs, and stream RTT over the same probe. What is still rolling out: the three remote-build paths (Path A / B / C) that produce those flash bundles in the cloud. Local-ELF + cloud archive (Path C) is the first to land. NUCLEO-G431RB is the first board family; F7 / H7 / L4 follow.


Tier gating

TierSTM32 access
Hobby / Maker / MasterESP32 only
Champion +STM32 build executor unlocked
Self-hostedAll targets (your own runners)

The pricing page at esphome.cloud/pricing has the current executor matrix.


The three paths

PathSourceWhere it buildsCloud does
A · CMake + arm-gccCMake project (structurally compatible with CubeMX output; you run the CubeMX GUI locally)Remote agentConfigure + build with arm-gcc-none-eabi + STM32CubeG4 HAL, sign, package as flash bundle
B · Cargo + embassy-rsCargo project, #[no_std], embassy-rsRemote agentcargo build --release against the target triple, sign, package
C · Local ELF + cloud archiveYou compile the ELF on your machineLocal for ELF; remote for archivearm-none-eabi-objcopy to produce raw flash images + sign + package

esphome.cloud explicitly does not ship a desktop IDE or GUI. CubeMX, CubeIDE, Keil, PlatformIO all stay on your machine. The cloud only takes:

  • a CMake / Cargo project (Path A / B), or
  • a finished ELF (Path C).

The output is the same in all three cases: a flash_bundle.tar.gz that espctl flash can consume.

Internally the three paths surface in espctl skills (once shipped) as three named recipes — cortexm_cube_build (Path A), cortexm_embassy_build (Path B), cortexm_rust_elf (Path C) — so an agent can pick the right one without text matching.


What each path produces

Whichever path produces the bundle, the cloud emits the same set of artifacts inside flash_bundle.tar.gz:

ArtifactPurpose
firmware.elfUnstripped application ELF. Retained for espctl elf <build_id> retrieval and for RTT debugging on the user’s side.
firmware.binRaw flash image at the linker-script base address.
firmware.hexIntel HEX form of the same image.
manifest.jsonFlash-bundle manifest — chip, probe_rs_chip, flash segments + offsets, SHA-256 hashes, build_provenance.
sbom.jsonToolchain pins (Path A / B) or empty toolchain section (Path C — you supplied the ELF) plus declared project dependencies.

The whole bundle is signed before delivery. espctl flash and espctl monitor --bundle consume any of the three path outputs interchangeably.


Toolchain pinning + reproducibility goals

The remote build store pins toolchain versions per store release and reuses them across every Cortex-M build in that release. You do not pick them per-build — picking is per-store, on the maintainer side.

ComponentPinned version (current store release)
arm-none-eabi-gcc (Path A)13.2.0
Rust + cargo (Path B)1.85.0
STM32CubeG4 HAL (Path A, NUCLEO-G431RB)bundled per store release
probe-rs (client-side, used by espctl flash / monitor --rtt)tracks the version baked into your local espctl

Reproducibility goal:

  • L1 — text section byte-identical across rebuilds with the same source tree and toolchain pin. Mandated.
  • L2 — full flash image byte-identical across rebuilds. The goal is 90% of production scenarios. SOURCE_DATE_EPOCH is honored; remaining 10% are usually third-party crates with embedded timestamps or non-determinstic config emission.

Pin shifts only happen across store-manifest revisions, and a pin shift is published in the store changelog before it lands.


CubeMX project layout — zero CMakeLists.txt edits

For Path A, the standard CubeMX-generated CMakeLists.txt works as-is. The toolchain file the cloud injects attaches the firmware.elf → firmware.bin / firmware.hex + signing pipeline to every executable target automatically, via CMake’s CMAKE_PROJECT_INCLUDE_BEFORE hook. You do not need to add add_cortexm_firmware(...) calls.

If your project already defines its own CMAKE_PROJECT_INCLUDE or CMAKE_PROJECT_INCLUDE_BEFORE, the cloud appends to it — your existing hooks are preserved, not replaced.

Net effect: a freshly exported CubeMX project from a CubeG4 template compiles and packages on the cloud with zero modifications.


What works today (local Cortex-M surface)

Everything below works right now against any pre-built Cortex-M flash bundle, regardless of how the bundle was produced.

1. Provision the host

Make probe-rs able to talk to debug probes without root:

espctl provision-host --dry-run       # print the plan
espctl provision-host                 # apply it (Phase 3+; Phase 0 is dry-run only)

On Linux this writes udev rules; on Windows it prints a Zadig pointer; macOS works out of the box. See CLI Utilities — espctl provision-host.

2. List connected probes

espctl probes list             # table
espctl probes list --json      # for piping into an agent

Returns vendor / product / serial / VID:PID and the probe-rs identifier you’ll pass to --probe. See CLI Utilities — espctl probes.

3. Flash a Cortex-M bundle

espctl flash flash_bundle.tar.gz \
    --probe auto                    # or VID:PID[:SERIAL]
    --chip STM32G431RBTx            # override bundle's probe_rs_chip if your variant differs
    # --no-verify                   # skip probe-rs verify step

espctl flash reads the bundle’s FlashTarget:

  • Esp32 { .. } → dispatches through pure-Rust espflash (USB-serial, requires --port).
  • CortexM { probe_rs_chip, elf, .. } → dispatches through probe-rs (USB, no serial port). --probe, --chip, and --no-verify apply; --port and --baud are ignored.

ADR-007 defines the FlashTarget enum. See Firmware & Flash.

4. Monitor over RTT

espctl monitor --bundle flash_bundle.tar.gz     # mode auto-resolves to RTT from the bundle
espctl monitor --rtt --chip STM32G431RBTx       # explicit RTT without a bundle

When --bundle is supplied, espctl monitor reads the bundle’s FlashTarget and:

  • CortexM → defaults to RTT mode, auto-extracts the ELF for probe-rs attach.
  • Esp32 → defaults to UART mode (existing serial-port flow).

Force a specific mode with --rtt or --uart. --rtt and --uart are mutually exclusive.


What is rolling out (the cloud build paths)

The three paths land tier by tier. The remote build endpoints share the same auth flow, signing pipeline, and flash-bundle output schema with the ESP32 / ESP-IDF path; the difference is the toolchain image and the bundle’s FlashTarget field.

When a path is live, the public surface looks like:

# Path A or B — remote build (planned)
espctl build --target stm32g431 --remote     # CMake or Cargo project in cwd
                                              # → flash_bundle.tar.gz

# Path C — local ELF + cloud archive (planned)
espctl build --rust-elf path/to/local.elf \
             --target stm32g431              # objcopy + sign + package
                                              # → flash_bundle.tar.gz

Today, espctl build --rust-elf produces ESP32-S3 bundles (espflash save-image --merge); the same flag will accept an --target stm32* once Path C lands.

Until then, you can hand-produce a Cortex-M flash bundle from any toolchain that emits an ELF, then run espctl flash against it. The flash_bundle crate defines the manifest schema.

Path C details — espctl build --rust-elf for Cortex-M (rolling out)

When Path C opens for Cortex-M, the contract on the wire looks like this (visible via espctl skills --format json once shipped):

FieldValue / limitNotes
elf_blob max size16 MiBAnything larger rejects at submission.
Pre-flight ELF validationELF magic + 32-bit class + little-endian + e_machine == EM_ARM (40)Fails fast with a structured error if you upload a non-ELF / 64-bit ELF / big-endian ELF / non-ARM ELF. Note: VFP / soft-float ABI flags in e_flags are not checked — thumbv6m soft-float and thumbv7em-eabihf both pass.
Memory limit (archive-only)512 MiBEnough for arm-none-eabi-objcopy + Intel HEX + signing + packaging.
Wall-clock timeout60 sAn archive-only job that runs longer is killed.
Manifest build_provenance"client_supplied"Lets buyers / verifiers see at a glance that the ELF was not produced by the cloud toolchain.
SBOM toolchain sectionemptyThe cloud only knows what objcopy did. Fill in your source-side toolchain via the build_meta field (free text, ≤ 64 KiB) if you want it captured.

Bundle integrity (the signature + hashes) is identical to Path A / B. The difference is provenance: a Path C bundle says “Aegis processed this ELF”, whereas a Path A / B bundle says “Aegis built this from source inside its pinned toolchain”. Downstream verifiers and the deposit ledger record both states distinctly.


Hardware first-class support

Champion preview ships with first-class support for:

  • STM32G4 family — beginning with NUCLEO-G431RB. Path A templates target STM32CubeG4 HAL.

Roadmap:

  • STM32F7 / STM32H7 / STM32L4 — order subject to user demand.

Anything outside the supported set works under Path C (local ELF

  • cloud archive) — arm-none-eabi-objcopy is target-family agnostic, the bundle format is probe_rs_chip-driven, so anything probe-rs supports can be flashed and monitored.

Build → Deposit → Review still applies

The three-phase loop in Typical Workflow is the same for Cortex-M as for ESP32:

  1. Build → produces flash_bundle.tar.gz (any of the three paths).
  2. Depositespctl deposit add <build_id> writes the (requirement, code, physical verification) triple to ~/maker-assets/. STM32 builds land in the same triple ledger as ESP32 builds.
  3. Review → the MakerStatsSnapshot pushed to /ops/funnel-review has a hardwareMix[] field — STM32 platforms show up there alongside esp32-s3 etc. See Weekly Maker Asset Review.

See also

  • CLI Utilitiesespctl probes, espctl provision-host, --json semantics.
  • Firmware & Flashespctl flash, espctl monitor, FlashTarget dispatch (ADR-007).
  • Pricing — the executor matrix and Champion tier specifics.
  • System Overview — where the remote build agent sits and how flash bundles are signed.