Прямой доступ к MMIO
Большинство микроконтроллеров обращаются к периферии через ввод-вывод, отображённый в память (memory-mapped IO). Попробуем включить светодиод на нашем micro:bit:
// Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0
#![no_main]
#![no_std]
extern crate panic_halt as _;
mod interrupts;
use core::mem::size_of;
use cortex_m_rt::entry;
/// Адрес периферии GPIO порта 0
const GPIO_P0: usize = 0x5000_0000;
// Смещения периферии GPIO
const PIN_CNF: usize = 0x700;
const OUTSET: usize = 0x508;
const OUTCLR: usize = 0x50c;
// Поля PIN_CNF
const 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() -> ! {
// Настраиваем выводы 21 и 28 GPIO 0 как выходы push-pull.
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: Указатели ведут на допустимые управляющие регистры периферии, и
// никаких алиасов не существует.
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,
);
}
// Установите вывод 28 в низкий уровень, а вывод 21 --- в высокий, чтобы включить светодиод.
let gpio0_outset = (GPIO_P0 + OUTSET) as *mut u32;
let gpio0_outclr = (GPIO_P0 + OUTCLR) as *mut u32;
// SAFETY: Указатели ведут на допустимые управляющие регистры периферии, и
// никаких алиасов не существует.
unsafe {
gpio0_outclr.write_volatile(1 << 28);
gpio0_outset.write_volatile(1 << 21);
}
loop {}
}
- Вывод 21 GPIO 0 подключён к первому столбцу матрицы светодиодов, а вывод 28 — к первой строке.
Запустите пример командой:
cargo embed --bin mmio