Embedded Development
Domain Constraints
Domain Rule Design Constraint Rust Implication
No heap Stack allocation heapless, no Box/Vec
No std Core only #![no_std]
Real-time Predictable timing No dynamic alloc
Resource limited Minimal memory Static buffers
Hardware safety Safe peripheral access HAL + ownership
Interrupt safe No blocking in ISR Atomic, critical sections
Critical Rules
-
Cannot use heap (no allocator) — use heapless::Vec<T, N> and arrays for deterministic memory.
-
Shared state must be interrupt-safe — ISR can preempt at any time. Use Mutex<RefCell<T>>
- critical section.
- Peripherals must have clear ownership — HAL takes ownership via singletons to prevent conflicting access.
Layer Stack
Layer Examples Purpose
PAC stm32f4, esp32c3 Register access
HAL stm32f4xx-hal Hardware abstraction
Framework RTIC, Embassy Concurrency
Traits embedded-hal Portable drivers
Framework Comparison
Framework Style Best For
RTIC Priority-based Interrupt-driven apps
Embassy Async Complex state machines
Bare metal Manual Simple apps
Key Crates
Purpose Crate
Runtime (ARM) cortex-m-rt
Panic handler panic-halt, panic-probe
Collections heapless
HAL traits embedded-hal
Logging defmt
Flash/debug probe-run
Static Peripheral Pattern
#![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
Mistake Domain Violation Fix
Using Vec Heap allocation heapless::Vec
No critical section Race with ISR Mutex + interrupt::free
Blocking in ISR Missed interrupts Defer to main loop
Unsafe peripheral Hardware conflict HAL ownership