Raw MMIO

Most microcontrollers access peripherals via memory-mapped IO. Let’s try turning on an LED on our micro:bit:

  1. #![no_main]
  2. #![no_std]
  3. extern crate panic_halt as _;
  4. mod interrupts;
  5. use core::mem::size_of;
  6. use cortex_m_rt::entry;
  7. /// GPIO port 0 peripheral address
  8. const GPIO_P0: usize = 0x5000_0000;
  9. // GPIO peripheral offsets
  10. const PIN_CNF: usize = 0x700;
  11. const OUTSET: usize = 0x508;
  12. const OUTCLR: usize = 0x50c;
  13. // PIN_CNF fields
  14. const DIR_OUTPUT: u32 = 0x1;
  15. const INPUT_DISCONNECT: u32 = 0x1 << 1;
  16. const PULL_DISABLED: u32 = 0x0 << 2;
  17. const DRIVE_S0S1: u32 = 0x0 << 8;
  18. const SENSE_DISABLED: u32 = 0x0 << 16;
  19. #[entry]
  20. fn main() -> ! {
  21.     // Configure GPIO 0 pins 21 and 28 as push-pull outputs.
  22.     let pin_cnf_21 = (GPIO_P0 + PIN_CNF + 21 * size_of::<u32>()) as *mut u32;
  23.     let pin_cnf_28 = (GPIO_P0 + PIN_CNF + 28 * size_of::<u32>()) as *mut u32;
  24.     // SAFETY: The pointers are to valid peripheral control registers, and no
  25.     // aliases exist.
  26.     unsafe {
  27.         pin_cnf_21.write_volatile(
  28.             DIR_OUTPUT
  29.                 | INPUT_DISCONNECT
  30.                 | PULL_DISABLED
  31.                 | DRIVE_S0S1
  32.                 | SENSE_DISABLED,
  33.         );
  34.         pin_cnf_28.write_volatile(
  35.             DIR_OUTPUT
  36.                 | INPUT_DISCONNECT
  37.                 | PULL_DISABLED
  38.                 | DRIVE_S0S1
  39.                 | SENSE_DISABLED,
  40.         );
  41.     }
  42.     // Set pin 28 low and pin 21 high to turn the LED on.
  43.     let gpio0_outset = (GPIO_P0 + OUTSET) as *mut u32;
  44.     let gpio0_outclr = (GPIO_P0 + OUTCLR) as *mut u32;
  45.     // SAFETY: The pointers are to valid peripheral control registers, and no
  46.     // aliases exist.
  47.     unsafe {
  48.         gpio0_outclr.write_volatile(1 << 28);
  49.         gpio0_outset.write_volatile(1 << 21);
  50.     }
  51.     loop {}
  52. }
  • GPIO 0 pin 21 is connected to the first column of the LED matrix, and pin 28 to the first row.

Run the example with:

  1. cargo embed --bin mmio