skills/embedded-rust/SKILL.md
Embedded Rust skill for bare-metal microcontroller development. Use when using probe-rs or cargo-embed for flashing and debugging, setting up defmt logging, using the RTIC framework, configuring cortex-m-rt startup, writing no_std + no_main firmware, or choosing between panic-halt and panic-semihosting. Activates on queries about embedded Rust, probe-rs, cargo-embed, defmt, RTIC, cortex-m-rt, no_std embedded, or panic handling in embedded Rust.
npx skillsauth add awfixers-stuff/opencode-config embedded-rustInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Guide agents through embedded Rust development: flashing and debugging with probe-rs/cargo-embed, structured logging with defmt, the RTIC concurrency framework, cortex-m-rt startup, no_std configuration, and panic handler selection.
# Cargo.toml
[package]
name = "my-firmware"
version = "0.1.0"
edition = "2021"
[dependencies]
cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
cortex-m-rt = "0.7"
defmt = "0.3"
defmt-rtt = "0.4"
panic-probe = { version = "0.3", features = ["print-defmt"] }
# Embassy (async embedded) — alternative to RTIC
# embassy-executor = { version = "0.5", features = ["arch-cortex-m"] }
[profile.release]
opt-level = "s" # size optimization for embedded
lto = true
codegen-units = 1
debug = true # keep debug info for defmt/probe-rs
# .cargo/config.toml
[build]
target = "thumbv7em-none-eabihf" # Cortex-M4F / M7
[target.thumbv7em-none-eabihf]
runner = "probe-rs run --chip STM32F411CEUx" # auto-run after build
rustflags = ["-C", "link-arg=-Tlink.x"] # cortex-m-rt linker script
// src/main.rs
#![no_std]
#![no_main]
use cortex_m_rt::entry;
use defmt::info;
use defmt_rtt as _; // RTT transport for defmt
use panic_probe as _; // panic handler that prints via defmt
#[entry]
fn main() -> ! {
info!("Booting up!");
// Access peripherals via PAC or HAL
let _core = cortex_m::Peripherals::take().unwrap();
// let dp = stm32f4xx_hal::pac::Peripherals::take().unwrap();
loop {
info!("Running...");
cortex_m::asm::delay(8_000_000); // rough delay
}
}
Target triples for common MCUs:
| MCU family | Target triple |
|-----------|---------------|
| Cortex-M0/M0+ | thumbv6m-none-eabi |
| Cortex-M3 | thumbv7m-none-eabi |
| Cortex-M4 (no FPU) | thumbv7em-none-eabi |
| Cortex-M4F / M7 | thumbv7em-none-eabihf |
| Cortex-M33 | thumbv8m.main-none-eabihf |
| RISC-V RV32IMAC | riscv32imac-unknown-none-elf |
rustup target add thumbv7em-none-eabihf
# Install probe-rs
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/probe-rs/probe-rs/releases/latest/download/probe-rs-tools-installer.sh | sh
# Flash firmware
probe-rs run --chip STM32F411CEUx target/thumbv7em-none-eabihf/release/firmware
# Interactive debug session
probe-rs debug --chip STM32F411CEUx target/thumbv7em-none-eabihf/release/firmware
# List connected probes
probe-rs list
# Supported chips
probe-rs chip list | grep STM32
With cargo:
# Using the runner in .cargo/config.toml
cargo run --release # builds, flashes, and streams defmt logs
cargo build --release # build only
defmt (de-formatter) encodes log strings to integers, transmits minimal bytes, decodes on host:
use defmt::{info, warn, error, debug, trace, Format};
// Basic logging
info!("Temperature: {} °C", temp);
warn!("Stack usage: {}/{}", used, total);
error!("I2C error: {:?}", err);
// Derive Format for custom types
#[derive(Format)]
struct Packet { id: u8, len: u16 }
info!("Received: {:?}", pkt);
// Assertions (panic with defmt message)
defmt::assert_eq!(result, expected);
defmt::assert!(condition, "message with {}", value);
defmt backends (choose one):
# RTT (fastest, needs debug probe connected)
defmt-rtt = "0.4"
# Semihosting (slower, works without RTT support)
defmt-semihosting = "0.1"
// Cargo.toml
// rtic = { version = "2", features = ["thumbv7-backend"] }
#[rtic::app(device = stm32f4xx_hal::pac, peripherals = true, dispatchers = [SPI1])]
mod app {
use stm32f4xx_hal::{pac, prelude::*};
use defmt::info;
#[shared]
struct Shared {
counter: u32,
}
#[local]
struct Local {}
#[init]
fn init(cx: init::Context) -> (Shared, Local) {
info!("RTIC init");
periodic_task::spawn().unwrap();
(Shared { counter: 0 }, Local {})
}
#[task(shared = [counter])]
async fn periodic_task(mut cx: periodic_task::Context) {
loop {
cx.shared.counter.lock(|c| *c += 1);
info!("Count: {}", cx.shared.counter.lock(|c| *c));
rtic_monotonics::systick::Systick::delay(500.millis()).await;
}
}
#[task(binds = EXTI0, local = [], priority = 2)]
fn button_isr(cx: button_isr::Context) {
info!("Button pressed!");
}
}
| Crate | Behavior | Use when |
|-------|----------|----------|
| panic-halt | Infinite loop | Production, no debug probe |
| panic-probe | defmt message + halt | Development with probe-rs |
| panic-semihosting | GDB semihosting output | Development with GDB |
| panic-reset | Hard reset | Watchdog-style recovery |
# Choose exactly one panic handler
[dependencies]
panic-halt = "0.2" # or:
panic-probe = { version = "0.3", features = ["print-defmt"] }
For embedded Rust target triples reference, see references/embedded-rust-targets.md.
skills/embedded/openocd-jtag for OpenOCD-based debugging alternative to probe-rsskills/rust/rust-no-std for #![no_std] patterns and constraintsskills/embedded/linker-scripts for memory layout configurationskills/rust/rust-cross for cross-compilation toolchain setupdevelopment
Use when starting dev servers, watchers, tilt, or any process expected to outlive the conversation. Provides zmx session management patterns for long-lived processes.
development
Zig testing skill for writing and running tests. Use when using zig build test, writing comptime tests, using test filters, working with test allocators to detect leaks, or using Zig's built-in fuzz testing (0.14+). Activates on queries about Zig tests, zig test, zig build test, comptime testing, test allocators, Zig fuzz testing, or detecting memory leaks in Zig tests.
development
Zig debugging skill. Use when debugging Zig programs with GDB or LLDB, interpreting Zig runtime panics, using std.debug.print for tracing, configuring debug builds, or debugging Zig programs in VS Code. Activates on queries about debugging Zig, Zig panics, zig gdb, zig lldb, std.debug.print, Zig stack traces, or Zig error return traces.
tools
Zig cross-compilation skill. Use when cross-compiling Zig programs to different targets, using Zig's built-in cross-compilation for embedded, WASM, Windows, ARM, or using zig cc to cross-compile C code without a system cross-toolchain. Activates on queries about Zig cross-compilation, zig target triples, zig cc cross-compile, Zig embedded targets, or Zig WASM.