Reference Patterns
This chapter is a quick-reference you will come back to again and again. It collects the target triples, feature flags, pin mappings, and debugging checklists that save you from searching through documentation at 2am.
Target Triples
Every ARM Cortex-M core has a specific Rust compilation target. Using the wrong one means your binary will not run — or worse, will run with subtle bugs.
| Target Triple | Core | FPU | Used By |
|---|---|---|---|
thumbv6m-none-eabi | Cortex-M0, M0+ | No | F0, G0, L0 |
thumbv7m-none-eabi | Cortex-M3 | No | F1, F2, L1 |
thumbv7em-none-eabi | Cortex-M4 (no FPU) | No | L4 (some), G4 (if FPU unused) |
thumbv7em-none-eabihf | Cortex-M4, M7 | Yes | F3, F4, F7, H7, G4, L4+ |
thumbv8m.main-none-eabihf | Cortex-M33 | Yes | H5, U5, L5 |
The hf suffix means "hardware float." If your chip has an FPU (most F4, F7, H7, G4 do), always use the hf target. Using the non-hf target on an FPU-equipped chip works but wastes the hardware floating point unit — all float math gets done in software, roughly 10-50x slower.
Think About It: The target triple encodes the instruction set, not the chip model. An STM32F407 and an STM32F411 use the same target (
thumbv7em-none-eabihf) because they both have Cortex-M4F cores. An STM32G071 uses a different target (thumbv6m-none-eabi) because it has a Cortex-M0+ core.
Embassy Chip Feature Flags
Embassy uses Cargo feature flags to select the exact chip model. The feature name matches the chip part number in lowercase. Here are the most common ones:
| Board / Chip | Embassy Feature | Target | Notes |
|---|---|---|---|
| Blue Pill (F103C8) | stm32f103c8 | thumbv7m-none-eabi | Classic learning board |
| Black Pill (F411CE) | stm32f411ce | thumbv7em-none-eabihf | Great value, USB OTG |
| STM32F407 Discovery | stm32f407vg | thumbv7em-none-eabihf | 4 LEDs, audio codec |
| Nucleo-G071RB | stm32g071rb | thumbv6m-none-eabi | Budget, lots of peripherals |
| Nucleo-H743ZI | stm32h743vi | thumbv7em-none-eabihf | 480MHz, complex memory |
| Nucleo-U575ZI | stm32u575zi | thumbv8m.main-none-eabihf | Ultra-low-power |
| Nucleo-H563ZI | stm32h563zi | thumbv8m.main-none-eabihf | H5 mainstream |
| WeAct STM32G431 | stm32g431cb | thumbv7em-none-eabihf | Motor control, USB-C |
# In Cargo.toml — change only this feature to switch chips
[dependencies.embassy-stm32]
version = "0.2"
features = ["stm32f411ce", "time-driver-any", "memory-x"]
Common LED Pins by Board
When you are trying to blink an LED and nothing happens, the first question is: which pin is the LED on?
| Board | LED Pin | Active | Color |
|---|---|---|---|
| Blue Pill (F103) | PC13 | Low | Green |
| Black Pill (F411) | PC13 | Low | Blue |
| STM32F407 Discovery | PD12, PD13, PD14, PD15 | High | Green, Orange, Red, Blue |
| Nucleo-64 (most) | PA5 | High | Green |
| Nucleo-144 (most) | PB0, PB7, PB14 | High | Green, Blue, Red |
| WeAct H743 | PE3 | Low | Blue |
Fun Fact: The "active low" LED convention (PC13 on Blue/Black Pill) means you set the pin LOW to turn the LED ON. This is because the LED is wired between VCC and the GPIO pin. When the pin is low, current flows through the LED. When the pin is high, both sides are at the same voltage and no current flows.
Debug Checklist
When something does not work, walk through this checklist in order. Each item is listed roughly by how often it causes problems:
Power and Hardware
- Power connected? Check 3.3V rail with a multimeter. Should be 3.2V–3.4V.
- Debugger connected? ST-Link or J-Link wired to SWDIO, SWCLK, GND. Is the debugger LED solid?
- Correct chip selected? The Embassy feature flag must match your physical chip exactly.
- Reset pin? Some boards need NRST connected or have a reset button you need to press.
Basic Firmware
- LED blinks? Before debugging any peripheral, confirm the chip is running code at all.
-
defmt logs appearing? If not, check that
defmt-rttis in your dependencies andprobe-rsis configured correctly. - Clock configuration correct? Wrong PLL settings can make the chip run at the wrong speed or not run at all. Start with the default clock (HSI) to confirm basic operation.
GPIO and Pins
- Correct pin for this function? Check the datasheet's alternate function mapping.
- Correct alternate function number? PA9 might be USART1_TX on AF7 but SPI1_SCK on AF5. Getting the AF wrong means the peripheral is not connected to the pin.
- Pin mode correct? Push-pull vs open-drain, pull-up vs pull-down.
Communication Peripherals
- SPI: CS pin toggling? Scope it. If CS is stuck high, the slave ignores everything.
- SPI: Clock polarity and phase? CPOL and CPHA must match the slave device's requirements.
- I2C: Pull-up resistors present? I2C requires external 4.7k pull-ups to 3.3V on SDA and SCL. Without them, the bus stays low.
- I2C: Correct address? Some datasheets give 8-bit addresses, Rust expects 7-bit. Divide by 2 if needed.
- UART: TX and RX swapped? The most common UART mistake. Your TX connects to their RX and vice versa.
- UART: Baud rate match? Both sides must agree on the baud rate exactly.
STM32H7 Specific
- DMA buffer in correct memory region? Must be in SRAM1/2/3, NOT in DTCM or AXI SRAM.
- Cache coherency? If using AXI SRAM with DMA, cache invalidation or clean operations are required.
- Power supply configuration? H7 has SMPS and LDO options. Wrong power configuration prevents boot.
System Level
- Watchdog timeout too short? If the watchdog fires during initialization, the chip resets in a loop.
-
Stack overflow? Large local arrays can overflow the stack. Use
staticfor big buffers. Enable thepaintfeature incortex-m-rtto detect stack overflows. -
Flash full?
cargo sizeshows your binary size. If it exceeds your chip's Flash, linking fails with an obscure error.
Common Error Messages and Fixes
| Error Message | Likely Cause | Fix |
|---|---|---|
Error: connecting to the chip was unsuccessful | Debugger wiring, chip not powered, wrong chip in probe-rs config | Check wiring, power, and probe-rs chip setting |
SP is not 8-byte aligned | Corrupt vector table or wrong memory.x | Verify FLASH and RAM origins in memory.x |
292 or HardFault | Null pointer, stack overflow, or invalid memory access | Enable defmt panic handler, check stack size, review unsafe blocks |
292 292 292 292 292 292 (defmt gibberish) | defmt version mismatch between crate and probe-rs | Run cargo update and update probe-rs |
292 292 then silence | Panic during initialization | Simplify init code, add defmt::info at each step to find where it stops |
error[E0292]: stm32f411ce not found | Wrong feature flag or embassy version | Check embassy-stm32 version supports your chip |
292292 292292 292292 292292 (repeating) | Watchdog reset loop | Increase watchdog timeout or pet it earlier in init |
292292292292...292292292 (continuous) | Boot loop from brownout | Check power supply voltage and decoupling capacitors |
Think About It: Most embedded debugging follows a pattern: confirm the obvious first (power, wiring, chip selection), then narrow down to the specific subsystem. Resist the urge to change code before confirming the hardware is correct.
Quick Pin Reference Template
When starting a new project, fill in this table for your specific board:
Project: ____________________
Board: ____________________
Chip: ____________________
| Function | Pin | AF# | Notes |
|---------------|------|-----|-----------------|
| SPI1_SCK | | | |
| SPI1_MOSI | | | |
| SPI1_MISO | | | |
| SPI1_CS | | | Manual GPIO |
| I2C1_SCL | | | 4.7k pull-up |
| I2C1_SDA | | | 4.7k pull-up |
| USART1_TX | | | |
| USART1_RX | | | |
| ADC1_CH0 | | | |
| LED | | | Active High/Low |
| SWD_IO | | | |
| SWD_CLK | | | |
Debugging with probe-rs
Quick command reference for the tools you will use most often:
# Flash and run with defmt output
cargo run --release
# Just flash without running
probe-rs download target/thumbv7em-none-eabihf/release/my-project --chip STM32F411CE
# Reset the chip
probe-rs reset --chip STM32F411CE
# List connected probes
probe-rs list
# Check what chip is connected
probe-rs info
Summary
Keep this chapter bookmarked. The target triples table, the debug checklist, and the error message reference will save you hours over the course of any embedded Rust project. When something breaks — and it will — start at the top of the checklist and work down methodically.