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 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 Constraints
No Dynamic Allocation
RULE: Cannot use heap (no allocator)
WHY: Deterministic memory, no OOM
RUST: heapless::Vec
Interrupt Safety
RULE: Shared state must be interrupt-safe
WHY: ISR can preempt at any time
RUST: Mutex
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
"Need interrupt-safe state"
↓ m03-mutability: Mutex
"Need peripheral ownership" ↓ m01-ownership: Singleton pattern ↓ m12-lifecycle: RAII for hardware
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
Design Patterns
Pattern Purpose Implementation
no_std setup Bare metal #![no_std] + #![no_main]
Entry point Startup #[entry] or embassy
Static state ISR access Mutex
![no_std]
![no_main]
use cortex_m::interrupt::{self, Mutex}; use core::cell::RefCell;
static LED: Mutex
[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
Trace to Layer 1
Constraint Layer 2 Pattern Layer 1 Implementation
No heap Static collections heapless::Vec