PluginBench
Skill
Fail
Audit score 45

domain-embedded

actionbook/rust-skills

Embedded Rust development constraints: no_std, no heap, interrupt safety, and hardware ownership patterns.

What is domain-embedded?

Use this skill when developing embedded systems, microcontrollers, or bare-metal Rust code. It provides domain constraints, design patterns, and critical rules for no_std environments where dynamic allocation, standard library, and blocking operations are forbidden.

  • Enforces no_std and no-heap constraints using heapless collections and static buffers
  • Ensures interrupt-safe shared state via Mutex<RefCell<T>> and critical sections
  • Manages hardware peripheral ownership through singleton patterns and HAL abstractions
  • Guides framework selection (RTIC for priority-based, Embassy for async state machines)
  • Documents common embedded mistakes: Vec usage, missing critical sections, blocking in ISRs, unsafe peripheral access
  • Provides code patterns for entry points, static state initialization, and fixed-size data structures

How to install domain-embedded

npx skills add https://github.com/actionbook/rust-skills --skill domain-embedded
Prerequisites
  • Rust toolchain with embedded target support (e.g., thumbv7em-none-eabihf)
  • Understanding of microcontroller architecture and interrupt handling basics
  • Familiarity with Cargo.toml and .cargo/config.toml for target configuration
  • Knowledge of peripheral access crates (PAC) or hardware abstraction layers (HAL) for your target
Claude Code
Cursor
Windsurf
Cline

How to use domain-embedded

  1. 1.Review the domain constraints table to understand no_std, no-heap, real-time, and interrupt-safety rules
  2. 2.Check the framework comparison to choose between RTIC, Embassy, or bare-metal approaches
  3. 3.Apply the static peripheral code pattern for initializing and accessing hardware safely
  4. 4.Use heapless collections instead of Vec/Box for all dynamic data structures
  5. 5.Wrap shared state in Mutex<RefCell<Option<T>>> and access within interrupt::free() critical sections
  6. 6.Consult the common mistakes table to avoid heap allocation, missing critical sections, and blocking in ISRs

Use cases

Good for
  • Developing firmware for ARM Cortex-M, RISC-V, or ESP32/STM32 microcontrollers
  • Building interrupt-driven applications with real-time constraints and predictable timing
  • Creating device drivers and HAL layers that safely abstract hardware peripherals
  • Implementing no_std libraries and utilities for resource-constrained environments
  • Debugging race conditions and interrupt safety issues in concurrent embedded code
Who it's for
  • Embedded systems engineers and firmware developers
  • Microcontroller and IoT device programmers
  • Hardware abstraction layer (HAL) maintainers
  • Real-time systems developers requiring deterministic behavior
  • Rust developers transitioning from std to embedded domains

domain-embedded FAQ

When should I use RTIC vs Embassy?

Use RTIC for priority-based interrupt-driven applications with clear task priorities. Use Embassy for complex state machines and async workflows where you need structured concurrency.

Why can't I use Vec in embedded code?

Vec requires a heap allocator, which is unavailable in no_std environments and introduces non-deterministic memory behavior. Use heapless::Vec<T, N> with a fixed capacity instead.

How do I safely access peripherals from interrupts?

Use Mutex<RefCell<Option<T>>> to wrap peripheral state and access it only within interrupt::free(|cs| {...}) critical sections to prevent race conditions.

What's the difference between PAC and HAL?

PAC (Peripheral Access Crate) provides low-level register access; HAL (Hardware Abstraction Layer) wraps PAC with safe, ergonomic APIs and enforces ownership rules.

Can I use the standard library in embedded Rust?

No. Embedded code requires #![no_std] and cannot use std. Use core and alloc (if an allocator is available) or heapless for collections.

Full instructions (SKILL.md)

Source of truth, from actionbook/rust-skills.


name: domain-embedded description: "Use when developing embedded/no_std Rust. Keywords: embedded, no_std, microcontroller, MCU, ARM, RISC-V, bare metal, firmware, HAL, PAC, RTIC, embassy, interrupt, DMA, peripheral, GPIO, SPI, I2C, UART, embedded-hal, cortex-m, esp32, stm32, nrf, 嵌入式, 单片机, 固件, 裸机" globs: ["/Cargo.toml", "/.cargo/config.toml"] user-invocable: false

Project Context (Auto-Injected)

Target configuration: !cat .cargo/config.toml 2>/dev/null || echo "No .cargo/config.toml found"


Embedded Domain

Layer 3: Domain Constraints

Domain Constraints → Design Implications

Domain RuleDesign ConstraintRust Implication
No heapStack allocationheapless, no Box/Vec
No stdCore only#![no_std]
Real-timePredictable timingNo dynamic alloc
Resource limitedMinimal memoryStatic buffers
Hardware safetySafe peripheral accessHAL + ownership
Interrupt safeNo blocking in ISRAtomic, critical sections

Critical Constraints

No Dynamic Allocation

RULE: Cannot use heap (no allocator)
WHY: Deterministic memory, no OOM
RUST: heapless::Vec<T, N>, arrays

Interrupt Safety

RULE: Shared state must be interrupt-safe
WHY: ISR can preempt at any time
RUST: Mutex<RefCell<T>> + critical section

Hardware Ownership

RULE: Peripherals must have clear ownership
WHY: Prevent conflicting access
RUST: HAL takes ownership, singletons

Trace Down ↓

From constraints to design (Layer 2):

"Need no_std compatible data structures"
    ↓ m02-resource: heapless collections
    ↓ Static sizing: heapless::Vec<T, N>

"Need interrupt-safe state"
    ↓ m03-mutability: Mutex<RefCell<Option<T>>>
    ↓ m07-concurrency: Critical sections

"Need peripheral ownership"
    ↓ m01-ownership: Singleton pattern
    ↓ m12-lifecycle: RAII for hardware

Layer Stack

LayerExamplesPurpose
PACstm32f4, esp32c3Register access
HALstm32f4xx-halHardware abstraction
FrameworkRTIC, EmbassyConcurrency
Traitsembedded-halPortable drivers

Framework Comparison

FrameworkStyleBest For
RTICPriority-basedInterrupt-driven apps
EmbassyAsyncComplex state machines
Bare metalManualSimple apps

Key Crates

PurposeCrate
Runtime (ARM)cortex-m-rt
Panic handlerpanic-halt, panic-probe
Collectionsheapless
HAL traitsembedded-hal
Loggingdefmt
Flash/debugprobe-run

Design Patterns

PatternPurposeImplementation
no_std setupBare metal#![no_std] + #![no_main]
Entry pointStartup#[entry] or embassy
Static stateISR accessMutex<RefCell<Option<T>>>
Fixed buffersNo heapheapless::Vec<T, N>

Code Pattern: Static Peripheral

#![no_std]
#![no_main]

use cortex_m::interrupt::{self, Mutex};
use core::cell::RefCell;

static LED: Mutex<RefCell<Option<Led>>> = Mutex::new(RefCell::new(None));

#[entry]
fn main() -> ! {
    let dp = pac::Peripherals::take().unwrap();
    let led = Led::new(dp.GPIOA);

    interrupt::free(|cs| {
        LED.borrow(cs).replace(Some(led));
    });

    loop {
        interrupt::free(|cs| {
            if let Some(led) = LED.borrow(cs).borrow_mut().as_mut() {
                led.toggle();
            }
        });
    }
}

Common Mistakes

MistakeDomain ViolationFix
Using VecHeap allocationheapless::Vec
No critical sectionRace with ISRMutex + interrupt::free
Blocking in ISRMissed interruptsDefer to main loop
Unsafe peripheralHardware conflictHAL ownership

Trace to Layer 1

ConstraintLayer 2 PatternLayer 1 Implementation
No heapStatic collectionsheapless::Vec<T, N>
ISR safetyCritical sectionsMutex<RefCell<T>>
Hardware ownershipSingletontake().unwrap()
no_stdCore-only#![no_std], #![no_main]

Related Skills

WhenSee
Static memorym02-resource
Interior mutabilitym03-mutability
Interrupt patternsm07-concurrency
Unsafe for hardwareunsafe-checker