Raw MMIO
Most microcontrollers access peripherals via memory-mapped IO. Let’s try turning on an LED on our micro:bit:
#![no_main]#![no_std]extern crate panic_halt as _;mod interrupts;use core::mem::size_of;use cortex_m_rt::entry;/// GPIO port 0 peripheral addressconst GPIO_P0: usize = 0x5000_0000;// GPIO peripheral offsetsconst PIN_CNF: usize = 0x700;const OUTSET: usize = 0x508;const OUTCLR: usize = 0x50c;// PIN_CNF fieldsconst DIR_OUTPUT: u32 = 0x1;const INPUT_DISCONNECT: u32 = 0x1 << 1;const PULL_DISABLED: u32 = 0x0 << 2;const DRIVE_S0S1: u32 = 0x0 << 8;const SENSE_DISABLED: u32 = 0x0 << 16;#[entry]fn main() -> ! {// Configure GPIO 0 pins 21 and 28 as push-pull outputs.let pin_cnf_21 = (GPIO_P0 + PIN_CNF + 21 * size_of::<u32>()) as *mut u32;let pin_cnf_28 = (GPIO_P0 + PIN_CNF + 28 * size_of::<u32>()) as *mut u32;// SAFETY: The pointers are to valid peripheral control registers, and no// aliases exist.unsafe {pin_cnf_21.write_volatile(DIR_OUTPUT| INPUT_DISCONNECT| PULL_DISABLED| DRIVE_S0S1| SENSE_DISABLED,);pin_cnf_28.write_volatile(DIR_OUTPUT| INPUT_DISCONNECT| PULL_DISABLED| DRIVE_S0S1| SENSE_DISABLED,);}// Set pin 28 low and pin 21 high to turn the LED on.let gpio0_outset = (GPIO_P0 + OUTSET) as *mut u32;let gpio0_outclr = (GPIO_P0 + OUTCLR) as *mut u32;// SAFETY: The pointers are to valid peripheral control registers, and no// aliases exist.unsafe {gpio0_outclr.write_volatile(1 << 28);gpio0_outset.write_volatile(1 << 21);}loop {}}
- 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:
cargo embed --bin mmio