j4flmao/agent-skills/bare-metal-rust

Claude Code and agent skill by j4flmao/agent-skills

Trust tier 3
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

Use this skill when the user says 'embedded rust', 'no_std', 'cortex-m rust', 'embedded-hal', 'PAC', 'svd2rust', 'RTIC', 'Embassy', 'probe-rs', 'defmt', 'rust on microcontroller'. Builds and reviews `#![no_std]` firmware in Rust: crate layers (PAC/HAL/BSP), safe sharing between interrupts and main code, concurrency frameworks (RTIC, Embassy), allocation-free collections, and the flash/debug toolchain. Do NOT use for: general Rust application code (use lang-rust), C firmware (use c-cpp-patterns), RTOS theory (use rtos-fundamentals).

Install

npx vskill@latest install j4flmao/agent-skills/bare-metal-rust

SKILL.md

Bare-Metal Rust

Purpose

Rust removes whole classes of firmware bugs (buffer overruns, use-after-free, data races between ISR and main) at compile time while compiling to code comparable with C. This skill shows how to structure a no_std project, share state with interrupts soundly, pick between RTIC, Embassy and a plain superloop, and build/flash/debug with the standard toolchain.

Agent Protocol

Trigger

"embedded rust", "no_std", "cortex-m rust", "embedded-hal", "PAC", "svd2rust", "RTIC", "Embassy", "probe-rs", "defmt".

Input Context
  • MCU family and existing HAL crate (e.g. stm32f4xx-hal, nrf-hal, rp2040-hal/embassy-rp, esp-hal)
  • Concurrency model wanted (superloop, RTIC, Embassy async)
  • Memory budget and whether an allocator is acceptable
Output Artifact

Rust code (main.rs, Cargo.toml, memory.x, .cargo/config.toml) or a review. No file unless requested.

Response Format
Target: {thumbv7em-none-eabihf | riscv32imac-unknown-none-elf | ...}
Stack: {PAC/HAL crate versions} + {RTIC | Embassy | superloop}
Shared state: {mechanism and why it is sound}
Code: {snippet}
Build/flash: {commands}

1. The no_std Environment

  • #![no_std] links only core (and optionally alloc if you provide a #[global_allocator]). No threads, files, or heap by default.
  • #![no_main] + cortex-m-rt's #[entry] provide the reset handler, vector table and memory.x linker layout.
  • You must supply a panic handler: panic-halt, panic-probe (with defmt), or your own #[panic_handler].
rust
#![no_std]
#![no_main]
use cortex_m_rt::entry;
use panic_halt as _;
#[entry]
fn main() -> ! {
let dp = pac::Peripherals::take().unwrap(); // singleton: second take() returns None
// configure clocks/GPIO via the HAL ...
loop {
cortex_m::asm::wfi(); // sleep until an interrupt
}
}

main returns ! — firmware never returns.

2. Crate Layers

LayerWhat it isExample
PAC (Peripheral Access Crate)Generated by svd2rust from the vendor SVD; register-level, mostly unsafe writes of raw bits are wrapped in typed field APIsstm32f4, nrf52840-pac
HALSafe drivers implementing embedded-hal traitsstm32f4xx-hal, nrf52840-hal, esp-hal
embedded-hal 1.0Portable traits (digital::OutputPin, spi::SpiDevice, i2c::I2c, delay::DelayNs); embedded-hal-async for asyncstable since Jan 2024
BSPBoard pin mapping on top of the HALmicrobit-v2
DriversDevice drivers generic over the traitssensor crates

Write drivers against embedded-hal traits so they run on any HAL.

3. Sharing State with Interrupts

static mut requires unsafe for every access, and in the 2024 edition creating references to it is denied by default (static_mut_refs). Use one of:

  1. critical-section Mutex — portable, short critical sections:
rust
use core::cell::RefCell;
use critical_section::Mutex;
static COUNTER: Mutex<RefCell<u32>> = Mutex::new(RefCell::new(0));
#[interrupt]
fn TIM2() {
critical_section::with(|cs| *COUNTER.borrow_ref_mut(cs) += 1);
}
fn read_counter() -> u32 {
critical_section::with(|cs| *COUNTER.borrow_ref(cs))
}

The CriticalSection token proves interrupts are masked (single core) while borrowing. Provide an implementation via cortex-m's critical-section-single-core feature or your HAL.

  1. Atomics (core::sync::atomic) for single words — no masking. Cortex-M0/M0+ lacks CAS (fetch_add etc.); use portable-atomic there.
  2. RTIC resources — compile-time priority-ceiling locking (below).
  3. Embassy channels/signals (embassy-sync) between async tasks and interrupts.

4. Concurrency Frameworks

OptionModelChoose when
Superloop + interruptsloop { wfi } + ISRsvery small programs
RTIC 2Hardware tasks bound to interrupts, software tasks, Stack Resource Policy (priority ceiling) — deadlock-free, no runtime schedulerhard real-time with static priorities; analysable timing
Embassyasync/await executor, async HALs (embassy-stm32, embassy-nrf, embassy-rp), timers, networking (embassy-net), USB, BLE via nrf-softdevice/troubleI/O-heavy firmware, many concurrent waits, low power
RTOS bindingsFreeRTOS/Zephyr with Rustmixing with existing C RTOS code

5. Memory Without a Heap

  • heapless::{Vec, String, spsc::Queue, pool} — fixed capacity in the type (heapless::Vec<u8, 64>).
  • static_cell::StaticCell to obtain &'static mut buffers once at startup (common with Embassy).
  • If alloc is truly needed, use embedded-alloc with a static arena and handle allocation failure.
  • Check stack usage: flip-link puts the stack below .data/.bss so overflow faults instead of silently corrupting statics.

6. Toolchain

toml
# .cargo/config.toml
[build]
target = "thumbv7em-none-eabihf" # Cortex-M4F/M7
[target.thumbv7em-none-eabihf]
runner = "probe-rs run --chip STM32F411CEUx"
rustflags = ["-C", "link-arg=-Tlink.x", "-C", "link-arg=-Tdefmt.x"]
  • rustup target add thumbv7em-none-eabihf; cargo run --release flashes and streams logs.
  • probe-rs (flash, RTT, GDB server) replaced most OpenOCD workflows; defmt + defmt-rtt give compact deferred-formatted logging.
  • Size: cargo size --release (cargo-binutils); set opt-level = "s" or "z", lto = true, codegen-units = 1, panic = "abort" in the release profile.

7. Anti-Patterns

Anti-patternProblemFix
static mut + unsafe everywheredata races the compiler cannot seeMutex<RefCell<_>>, atomics, RTIC/Embassy
Long work inside critical_section::withadds to interrupt latencycopy out, process outside
unwrap() on fallible HAL calls in productionpanic = reset/halthandle errors, log with defmt
Blocking delays in Embassy tasksstalls the whole executorTimer::after(...).await
Writing PAC registers alongside a HAL that owns the peripheralbreaks HAL invariantslet one owner configure each peripheral

8. Checklist

  • [ ] #![no_std], #![no_main], panic handler chosen deliberately
  • [ ] Peripherals taken once; ownership moved into drivers/tasks
  • [ ] Every ISR-shared value behind a sound primitive (no static mut)
  • [ ] No heap, or a bounded allocator with failure handling
  • [ ] Release profile optimised; size and stack measured; flip-link enabled
  • [ ] Logs via defmt; flashing/debugging via probe-rs

Security

  • Security scanPassed, 100 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
28
Repository forks
1
7-day trend score
22

Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/j4flmao/agent-skills/bare-metal-rust/badge)](https://verified-skill.com/skills/j4flmao/agent-skills/bare-metal-rust)

Something wrong with this skill or its page? Tell us.