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<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
| 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<RefCell<Option<T>>> |
| Fixed buffers |
No heap |
heapless::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
| 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<T, N> |
| ISR safety |
Critical sections |
Mutex<RefCell> |
| Hardware ownership |
Singleton |
take().unwrap() |
| no_std |
Core-only |
#![no_std], #![no_main] |
Related Skills
| When |
See |
| Static memory |
m02-resource |
| Interior mutability |
m03-mutability |
| Interrupt patterns |
m07-concurrency |
| Unsafe for hardware |
unsafe-checker |