
Embedded Rust
- 285 installs
- 155 repo stars
- Updated June 27, 2026
- mohitmishra786/low-level-dev-skills
Build bare-metal and RTOS firmware in Rust with no_std, HAL crates, cross-compilation, probe flashing, peripheral drivers, and interrupt-safe patterns on microcontrollers.
About
Covers Rust embedded development for microcontrollers and bare-metal targets: no_std project layout, HAL and board support crates, cross-target builds, flash/debug probes, peripheral configuration, and safe patterns under tight RAM and flash constraints.
- no_std and embedded HAL patterns
- Cross-compilation and probe-rs flashing
- Peripheral and interrupt handler design
- Memory-constrained safety practices
- Hardware abstraction crate selection
Embedded Rust by the numbers
- 285 all-time installs (skills.sh)
- +38 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #44 of 121 Rust skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/mohitmishra786/low-level-dev-skills --skill embedded-rustAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 285 |
|---|---|
| repo stars | ★ 155 |
| Last updated | June 27, 2026 |
| Repository | mohitmishra786/low-level-dev-skills ↗ |
What it does
Build bare-metal and RTOS firmware in Rust with no_std, HAL crates, cross-compilation, probe flashing, peripheral drivers, and interrupt-safe patterns on microcontrollers.
Files
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 script2. 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 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-eabihf3. 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 STM32With cargo:
# Using the runner in .cargo/config.toml
cargo run --release # builds, flashes, and streams defmt logs
cargo build --release # build only4. 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
| 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.
Related skills
- Use
skills/embedded/openocd-jtagfor OpenOCD-based debugging alternative to probe-rs - Use
skills/rust/rust-no-stdfor#![no_std]patterns and constraints - Use
skills/embedded/linker-scriptsfor memory layout configuration - Use
skills/rust/rust-crossfor cross-compilation toolchain setup
Embedded Rust Target Reference
Source: https://docs.rust-embedded.org/book/
Target Triples
| Architecture | Target Triple | Notes |
|---|---|---|
| Cortex-M0, M0+ | thumbv6m-none-eabi | ARMv6-M, no hardware divide |
| Cortex-M3 | thumbv7m-none-eabi | ARMv7-M |
| Cortex-M4, M7 (no FPU) | thumbv7em-none-eabi | ARMv7E-M |
| Cortex-M4F, M7F | thumbv7em-none-eabihf | ARMv7E-M + hardware float |
| Cortex-M23 | thumbv8m.base-none-eabi | ARMv8-M Baseline |
| Cortex-M33, M55 | thumbv8m.main-none-eabihf | ARMv8-M Mainline + FPU |
| RISC-V RV32I | riscv32i-unknown-none-elf | Bare-metal RISC-V 32-bit |
| RISC-V RV32IMAC | riscv32imac-unknown-none-elf | With multiply + atomic |
| RISC-V RV32GC | riscv32gc-unknown-none-elf | Full standard extensions |
| RISC-V RV64GC | riscv64gc-unknown-none-elf | 64-bit RISC-V |
| AVR (experimental) | avr-unknown-gnu-atmega328 | Arduino/ATmega |
| MSP430 | msp430-none-elf | TI MSP430 |
| Xtensa LX6 (ESP32) | xtensa-esp32-none-elf | Requires espup toolchain |
Installing Targets
# Standard targets (rustup)
rustup target add thumbv7em-none-eabihf
rustup target add riscv32imac-unknown-none-elf
# Xtensa (ESP32) — requires esp-rs toolchain
curl -LO https://github.com/esp-rs/espup/releases/latest/download/espup-x86_64-unknown-linux-gnu
chmod +x espup-x86_64-unknown-linux-gnu
./espup-x86_64-unknown-linux-gnu install
source ~/export-esp.shCommon HAL Crates by MCU Family
| MCU | Crate |
|---|---|
| STM32F4 | stm32f4xx-hal |
| STM32L4 | stm32l4xx-hal |
| STM32H7 | stm32h7xx-hal |
| nRF52840 | nrf52840-hal |
| nRF9160 | nrf9160-hal |
| RP2040 | rp2040-hal |
| ESP32-C3 | esp32c3-hal (via esp-idf-hal) |
| STM32 all | embassy-stm32 (async HAL) |
| nRF all | embassy-nrf |
| RP2040 | embassy-rp |
Memory Configuration
# memory.x — place next to Cargo.toml for cortex-m-rt
MEMORY
{
FLASH : ORIGIN = 0x08000000, LENGTH = 512K
RAM : ORIGIN = 0x20000000, LENGTH = 128K
}# .cargo/config.toml
[target.thumbv7em-none-eabihf]
rustflags = [
"-C", "link-arg=-Tlink.x", # cortex-m-rt linker script
"-C", "link-arg=--nmagic", # disable page alignment (saves space)
]probe-rs Chip Names
# Find chip name
probe-rs chip list | grep -i "stm32f4"
probe-rs chip list | grep -i "nrf52"
probe-rs chip list | grep -i "rp2040"
# Common names
# STM32F411CEUx, STM32F407VGTx, STM32L476RGTx
# nRF52840_xxAA, nRF9160_xxAA
# RP2040
# ESP32C3 (via espflash, not probe-rs)