agentleFS
mohitmishra786mohitmishra786/low-level-dev-skills/skills/embedded/embedded-rust/SKILL.md

embedded-rust

Skill290 starsChanged 7 months agoMITView on GitHub

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.

  • Pipes a download into a shell

The file

We split this skill into the rules it gives an agent

4 rules. About 0 are common, 0 are distinctive, and 4 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈0

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 4

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Use skills/embedded/openocd-jtag for OpenOCD-based debugging alternative to probe-rs

    line 221
  2. Very specific:

    Use skills/rust/rust-no-std for #![no_std] patterns and constraints

    line 222
  3. Very specific:

    Use skills/embedded/linker-scripts for memory layout configuration

    line 223
  4. Very specific:

    Use skills/rust/rust-cross for cross-compilation toolchain setup

    line 224

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Embedded Rust

Purpose

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.

Triggers

  • "How do I flash my Rust firmware to an MCU?"
  • "How do I debug my embedded Rust program?"
  • "How do I use defmt for logging in embedded Rust?"
  • "How do I use RTIC for interrupt-driven concurrency?"
  • "What does #![no_std] #![no_main] mean for embedded Rust?"
  • "How do I handle panics in no_std embedded Rust?"

Workflow

1. Project setup

# 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

2. Minimal bare-metal program

// 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 familyTarget triple
Cortex-M0/M0+thumbv6m-none-eabi
Cortex-M3thumbv7m-none-eabi
Cortex-M4 (no FPU)thumbv7em-none-eabi
Cortex-M4F / M7thumbv7em-none-eabihf
Cortex-M33thumbv8m.main-none-eabihf
RISC-V RV32IMACriscv32imac-unknown-none-elf
rustup target add thumbv7em-none-eabihf

3. probe-rs — flash and debug

# 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

4. defmt — efficient logging

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"

5. RTIC — Real-Time Interrupt-driven Concurrency

// 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!");
    }
}

6. Panic handlers

CrateBehaviorUse when
panic-haltInfinite loopProduction, no debug probe
panic-probedefmt message + haltDevelopment with probe-rs
panic-semihostingGDB semihosting outputDevelopment with GDB
panic-resetHard resetWatchdog-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.

Related skills

  • Use skills/embedded/openocd-jtag for OpenOCD-based debugging alternative to probe-rs
  • Use skills/rust/rust-no-std for #![no_std] patterns and constraints
  • Use skills/embedded/linker-scripts for memory layout configuration
  • Use skills/rust/rust-cross for cross-compilation toolchain setup

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.