Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Embedded Rust: A Primer on MMIO

Avatar for Liam Kinne Liam Kinne
February 29, 2024

Embedded Rust: A Primer on MMIO

Avatar for Liam Kinne

Liam Kinne

February 29, 2024
Tweet

Other Decks in Programming

Transcript

  1. Universal Machine Intelligence Embedded devices for automation. Firmware and tooling

    written in Rust. Doing more with less. Shipping March 2024.
  2. Memory Mapped IO: Essential to Microcontrollers Memory Mapped I/O •

    How we interact with the real world • No special CPU instructions to control peripherals • Harvard architecture maximalism • General-purpose I/O and more advanced peripherals 0x0000 0000 Program Text 0x2000 0000 RAM 0x4000 0000 Peripherals 0x4000 0100 GPIO A 0x4000 0200 GPIO B
  3. Modifying Memory The C way GPIOA_ODR |= (1 << 5);

    GPIOA_ODR &= ~(1 << 5); The Rust way GPIOA.modify(|r,w| w .odr5() .set_bit() ); GPIOA.modify(|r,w| w .odr5() .clear_bit() ); // API generated by svd2rust
  4. Modifying Memory The C way PWR_CR1 |= (1 << PWR_CSR1_PVDO);

    The Rust way PWR_CR1.modify(|r,w| w .pvdo() .set_bit() ); // Error: method `.pvdo()` does not exist for PWR_CR1
  5. Modifying Memory: Real World Example The C way temp =

    GPIOA->OSPEEDR; temp &= ~(GPIO_OSPEEDER_OSPEEDR0 << (position * 2U)); temp |= (GPIO_Init->Speed << (position * 2U)); GPIOA->OSPEEDR = temp; The Rust way GPIOA.ospeedr.modify(|_, w| w .ospeedr0 .high_speed() );
  6. Memory Ownership and MMIO How does the borrow checker work

    with MMIO? Bytes have a memory address… bits don’t. PhantomData to the rescue!
  7. From Singletons to Partial Moves let peripherals = cortex_m::Peripherals::take().unwrap(); let

    gpioa = peripherals.GPIOA.split(...); let gpiob = peripherals.GPIOB.split(...); // Compile-time error! (GPIOB already moved) let gpiob = peripherals.GPIOB.split(...);
  8. Typestate Programming // Pin<GPIOA, 5, Analog> ← Default state let

    led = gpioa.pa5; // Pin<GPIOA, 5, Output<PushPull>> let led = led.into_push_pull_output(); led.set_high(); // Pin<GPIOA, 5, Analog> let led = led.into_analog();
  9. Type Erasure // Pin<GPIOA, 5, Input> let button = gpioa.pa5.into_input();

    // ErasedPin<Input> let button = button.erase();