Skip to content

Instantly share code, notes, and snippets.

@kesyog
Last active January 27, 2021 21:24
Show Gist options
  • Save kesyog/a44c3023e072a1f67b0f82b4bd33134f to your computer and use it in GitHub Desktop.
Save kesyog/a44c3023e072a1f67b0f82b4bd33134f to your computer and use it in GitHub Desktop.
Rust embedded notes

Rust embedded notes

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.

Glossary

  • peripheral access crate (PAC): device crate (e.g. stm32f4) created using the svd2rust crate 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_hal crate.

Braindump

Getting started

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.

Concurrency and Ownership

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.

Interrupts

  • The cortex-m-rt-macros crate defines an interrupt attribute 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.

Peripherals

  • The PAC crate has CorePeripherals and Peripherals structs with take functions that let you get a singleton of all of the peripherals
  • Some peripherals (e.g. the GPIO's) have a split function 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 the Deref trait, allowing it to pretend to be the RegisterBlock for that peripheral (example. This RegisterBlock is 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::RegisterBlock documentation.
    • To fill in later...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment