Use when explaining System V AMD64, ARM AAPCS, RISC-V psABI, stack frames, variadic calls, or FFI register rules. Not for the Rust FFI binding layer: use rust-ffi.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when writing no_std Cortex-M or RISC-V firmware in Rust with cortex-m-rt, probe-rs, defmt, RTIC, or a panic handler. Not for no_std library constraints: use rust-no-std.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
설치 방법 보기설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.
| Field | Bound contract |
|---|---|
| Trigger | A Rust firmware project needs to be set up or fixed: #![no_std] #![no_main] layout, cortex-m-rt startup, probe-rs flashing and log streaming, defmt logging, an RTIC application, or the choice of panic handler. |
| Authority | Reversible local: writes only the project files under the directory the user names (Cargo.toml, .cargo/config.toml, memory.x, src/); rollback is deleting that directory or reverting it in version control. No remote mutation. |
| Side effect | New or edited project files in the named directory. Flashing a board writes the board's flash, which the next cargo run overwrites. |
| Done | cargo build --release produces an ELF for the target triple, cargo run --release flashes it and streams defmt output to the terminal, and exactly one panic handler is linked. |
probe-rs chip list prints the names).memory.x).#[entry] loop, RTIC, or Embassy.defmt transport).Pick the target triple from the core and install it. Done when: rustup target add <triple> succeeds and the triple appears in rustc --print target-list. The full table is in references/embedded-rust-targets.md.
| Core | Target triple |
|---|---|
| Cortex-M0, M0+ | thumbv6m-none-eabi |
| Cortex-M3 | thumbv7m-none-eabi |
| Cortex-M4, M7 without FPU | thumbv7em-none-eabi |
| Cortex-M4F, M7F | thumbv7em-none-eabihf |
| Cortex-M33 with FPU | thumbv8m.main-none-eabihf |
| RISC-V RV32IMAC | riscv32imac-unknown-none-elf |
Write Cargo.toml and .cargo/config.toml. Use edition 2024. The versions below are the current crates.io releases on 2026-09-05; run cargo add <crate> to take the current one rather than copying a number. debug = true in the release profile keeps DWARF for defmt and probe-rs; it does not change the flashed code size because debug info is not loaded to flash. Done when: cargo build --release links.
# Cargo.toml
[package]
name = "my-firmware"
version = "0.1.0"
edition = "2024"
[dependencies]
cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
cortex-m-rt = "0.7"
defmt = "1"
defmt-rtt = "1"
panic-probe = { version = "1", features = ["print-defmt"] }
[profile.release]
opt-level = "s"
lto = true
codegen-units = 1
debug = true
# .cargo/config.toml
[build]
target = "thumbv7em-none-eabihf"
[target.thumbv7em-none-eabihf]
runner = "probe-rs run --chip STM32F411CEUx"
rustflags = ["-C", "link-arg=-Tlink.x"]
link.x is the linker script cortex-m-rt generates; it includes your memory.x:
MEMORY
{
FLASH : ORIGIN = 0x08000000, LENGTH = 512K
RAM : ORIGIN = 0x20000000, LENGTH = 128K
}
Write the minimal program. #![no_std] drops the standard library, #![no_main] hands the entry point to cortex-m-rt, and the two as _ imports link the RTT transport and the panic handler without naming them. Done when: the program builds and cortex_m::Peripherals::take() is called at most once.
#![no_std]
#![no_main]
use cortex_m_rt::entry;
use defmt::info;
use defmt_rtt as _;
use panic_probe as _;
#[entry]
fn main() -> ! {
info!("boot");
let _core = cortex_m::Peripherals::take().unwrap();
loop {
info!("tick");
cortex_m::asm::delay(8_000_000);
}
}
Flash and stream logs with probe-rs. probe-rs run flashes, resets, and prints RTT and defmt output; probe-rs attach connects without reset or flash and keeps the running state. Done when: cargo run --release prints the info! lines.
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/probe-rs/probe-rs/releases/latest/download/probe-rs-tools-installer.sh | sh
probe-rs list # connected probes
probe-rs chip list | grep -i stm32 # chip names for --chip
cargo run --release # build, flash, stream defmt
probe-rs attach --chip STM32F411CEUx target/thumbv7em-none-eabihf/release/my-firmware
If probe-rs run fails to find a probe or chip, read probe-rs run --help and probe-rs list before changing the config.
Log with defmt. defmt sends an interned string index plus raw arguments; the host decodes them from the ELF, so the ELF that is running must be the one the host reads. Done when: a #[derive(Format)] type prints through info!("{:?}", value).
use defmt::{Format, error, info, warn};
#[derive(Format)]
struct Packet { id: u8, len: u16 }
info!("temperature {} C", temp);
warn!("stack {}/{}", used, total);
error!("i2c {:?}", err);
defmt::assert_eq!(result, expected);
Transport: defmt-rtt needs a probe attached and is the default. defmt-semihosting works through a GDB or OpenOCD semihosting channel and is slower; use it when RTT is unavailable.
For interrupt-driven concurrency, use RTIC 2. Tasks with binds are hardware interrupt handlers; software tasks run on the dispatcher interrupts you list. Shared resources are locked, so RTIC proves no data race at compile time. Done when: the RTIC app compiles and the bound ISR fires on the hardware event.
#[rtic::app(device = stm32f4xx_hal::pac, peripherals = true, dispatchers = [SPI1])]
mod app {
use defmt::info;
#[shared]
struct Shared { counter: u32 }
#[local]
struct Local {}
#[init]
fn init(_cx: init::Context) -> (Shared, Local) {
periodic::spawn().unwrap();
(Shared { counter: 0 }, Local {})
}
#[task(shared = [counter])]
async fn periodic(mut cx: periodic::Context) {
loop {
let n = cx.shared.counter.lock(|c| { *c += 1; *c });
info!("count {}", n);
rtic_monotonics::systick::Systick::delay(500.millis()).await;
}
}
#[task(binds = EXTI0, priority = 2)]
fn button(_cx: button::Context) {
info!("button");
}
}
Cargo dependencies for this: rtic with the thumbv7-backend feature and rtic-monotonics with the cortex-m-systick feature. Embassy (embassy-executor) is the async alternative; pick one executor per binary.
Pick exactly one panic handler. Two handlers produce a duplicate #[panic_handler] link error. Done when: Cargo.toml lists one of the crates below and the build links.
| Crate | Behavior | Use when |
|---|---|---|
panic-halt | Infinite loop | Production without a probe |
panic-probe | Prints the message through defmt, then a breakpoint | Development with probe-rs |
panic-semihosting | Prints through semihosting | Development under GDB or OpenOCD |
panic-reset | Resets the core | Recovery where a watchdog would reset anyway |
| Symptom | Cause | Fix |
|---|---|---|
can't find crate for core | Target not installed | rustup target add <triple>. |
Link error naming memory.x or _stack_start | memory.x missing or not on the linker search path | Put memory.x next to Cargo.toml, or emit its directory from build.rs with cargo:rustc-link-search. |
Duplicate #[panic_handler] | Two panic crates linked | Keep one. |
No defmt output | Host reads a different ELF than the one flashed, or RTT is not linked | Rebuild and flash in one cargo run; keep use defmt_rtt as _;. |
probe-rs reports no probe | USB permissions or no udev rule | Run probe-rs list; install the udev rules from the probe-rs docs. |
| HardFault at boot | Wrong MEMORY origins or FPU triple on a core without FPU | Check memory.x against the datasheet and the triple against the core. |
A project directory that builds for the target triple, flashes with cargo run --release, streams defmt logs, and links one panic handler, plus a note naming the target triple and the probe-rs chip name that were used.
아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.
로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.
아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.
Use when explaining System V AMD64, ARM AAPCS, RISC-V psABI, stack frames, variadic calls, or FFI register rules. Not for the Rust FFI binding layer: use rust-ffi.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when configuring ADC sampling time, DMA-driven ADC, calibration, or DAC channel setup on bare-metal MCUs. Not for the DMA stream itself: use dma-baremetal.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when creating AF_XDP sockets, configuring UMEM and XSK rings, writing an XDP redirect program, or choosing copy versus zero-copy mode. Not for full kernel bypass: use dpdk.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when a completed session needs an agent-environment retrospective. Not for an engineering retrospective from telemetry: use engineering-retrospective.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when a redacted, trimmed agent transcript must be appended to a GitHub PR or issue body, with human approval and preview. Not for automated or model-initiated insertion.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when a repo needs agent setup, AGENTS.md added or made lean, CLAUDE.md audited, or agent instructions scored or pruned. Not for remote, credential, publish, deploy, or irreversible changes.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.