A place to jot down useful notes. Most if not all of this was lifted from the linked references, but I'm copying some of the highlights down here for my own reference.
- peripheral access crate (PAC): device crate (e.g. stm32f4) created using the
svd2rustcrate that presents an API to access a particular microcontroller's registers - hardware abstraction library (HAL) crate: higher-level abstraction on top of the PAC. This follows
the generic framework laid out by the
embedded_halcrate.
The easiest way to get started on a ARM Cortex-M processor is to use the cortex-m-quickstart template project. This provides a linker script template and various other boilerplate.
The svd2rust/PAC/HAL API represents peripherals as singletons and takes advantage of Rust's ownership rules to protect access to them. It can be bypassed using unsafe. See svd2rust's Peripheral API notes.
Passing these singletons around and/or sharing them can be a pain, but on the plus side, Rust is forcing you to think about concurrency and making it harder to shoot yourself in the foot. There's a great writeup on various techniques here.
| Technique | Multiple functions within one thread | Multiple threads | Thread and interrupt |
|---|---|---|---|
| Pass singleton by value | ✅ | ✅ (can move into thread at thread creation) | n/a |
| Unsafe code (e.g. direct register access, global mutable state) | ⚠ (bypasses safety checks. should stick to safe code if possible) | ⚠ (bypasses safety checks) | ⚠ (bypasses safety checks) |
Global Cell/RefCell protected by mutex (need a mutex implementation) |
✅ (but adds unnecessary overhead) | ✅ | ⛔ (shouldn't lock in an interrupt) |
Global Cell/RefCell protected by critical section (e.g. via cortex_m::interrupt). This masks all interrupts so should be used carefully. |
✅ | ✅ | ✅ |
Global atomic cell (e.g. crossbeam AtomicCell) |
✅ | ✅ | ✅ |
| cmim or irq crate | n/a | n/a | ✅ (for moving, not sharing) |
The RTIC concurrency framework provides its own solutions, but forces you to use its program model.
- The cortex-m-rt-macros
crate defines an
interruptattribute macro that can be applied to a function to override the default interrupt handler. The macro is re-exported by the PAC and HAL crates. These crates should have an enum defining what the valid interrupt handler names are e.g.stm32f4xx_hal::interrupt.
- The PAC crate has
CorePeripheralsandPeripheralsstructs withtakefunctions that let you get a singleton of all of the peripherals - Some peripherals (e.g. the GPIO's) have a
splitfunction defined by the hal crate that lets you split the entire peripheral into smaller singleton parts. For example: https://docs.rs/stm32f3xx-hal/0.6.1/stm32f3xx_hal/gpio/trait.GpioExt.html#tymethod.split* Each peripheral implements theDereftrait, allowing it to pretend to be theRegisterBlockfor that peripheral (example. ThisRegisterBlockis an svd2rust-compatible representation of the underlying registers for that peripheral. - To figure out how to read/write/modify these registers, first read the svd2rust peripheral API doc. Example of how to modify TIM2 registers:
- Open the
tim2::RegisterBlockdocumentation. - To fill in later...
- Open the