启用了虚拟内存之后,访问 MMIO 也需要建立映射,在 memory_sets.rs 中
for pair in MMIO { memory_set.push(MapArea::new( (*pair).0.into(), ((*pair).0 + (*pair).1).into(), MapType::Identical, MapPermission::R | MapPermission::W, ), None); }
实际的 pair 在 config.rs 中,pair.0 是开始地址,pair.1 是范围,可以在 k210_pac 中看到,地址相同
pub const MMIO: &[(usize, usize)] = &[ // we don't need clint in S priv when running // we only need claim/complete for target0 after initializing (0x0C00_0000, 0x3000), /* PLIC */ (0x0C20_0000, 0x1000), /* PLIC */ (0x3800_0000, 0x1000), /* UARTHS */ (0x3800_1000, 0x1000), /* GPIOHS */ (0x5020_0000, 0x1000), /* GPIO */ (0x5024_0000, 0x1000), /* SPI_SLAVE */ (0x502B_0000, 0x1000), /* FPIOA */ (0x502D_0000, 0x1000), /* TIMER0 */ (0x502E_0000, 0x1000), /* TIMER1 */ (0x502F_0000, 0x1000), /* TIMER2 */ (0x5044_0000, 0x1000), /* SYSCTL */ (0x5200_0000, 0x1000), /* SPI0 */ (0x5300_0000, 0x1000), /* SPI1 */ (0x5400_0000, 0x1000), /* SPI2 */ ];
板载 led
首先用高速 GPIO(GPIOHS) 点亮板载 led
use k210_soc::{ fpioa::{self, io}, gpio, gpiohs, }; pub fn init() { fpioa::set_function(io::LED_B, fpioa::function::GPIOHS0); gpiohs::set_direction(0, gpio::direction::OUTPUT); gpiohs::set_pin(0, false); println!("0 is {}", gpiohs::get_pin(0)); }
- fpio 映射实际物理引脚(io::LED_B) 到 GPIOHS0(fpioa::function::GPIOHS0) ,也就是高速 GPIO 0 号
- 设置高速 GPIO 0 号输出
- 设置高速 GPIO 0 号低电平
外部的 led
我们看看怎么点亮外部的 led ,led 点亮的原理就是正负极高低电平
// 外部的 led use k210_soc::{ fpioa::{self, io}, gpio, gpiohs, }; pub fn init() { // led b 映射到 gpiohs 0 // 9 fpioa::set_function(io::BPSK_P, fpioa::function::GPIOHS0); // 10 fpioa::set_function(io::BPSK_N, fpioa::function::GPIOHS1); // gpiohs 设置 0 为输出 gpiohs::set_direction(0, gpio::direction::OUTPUT); gpiohs::set_direction(1, gpio::direction::OUTPUT); gpiohs::set_pin(0, false); gpiohs::set_pin(1, true); println!("0 is {}", gpiohs::get_pin(0)); println!("1 is {}", gpiohs::get_pin(1)); }
- 分别映射 9 10 两个引脚到 0 1
- 0 1 设置为输出
- 0 1 分别设置为低电平和高电平
- 插入 led,注意正负极
用 GPIO 驱动 led
use k210_soc::{ fpioa::{self, io}, gpio }; use crate::driver::gpio::driver; pub fn init() { // led b 映射到 gpio 0 fpioa::set_function(io::LED_G, fpioa::function::GPIO0); // gpiohs 设置 0 为输出 driver::set_direction(0, gpio::direction::OUTPUT); // gpiohs 0 为 false , false 为点亮 driver::set_pin(0, false); }
#![allow(unused)] use k210_soc::gpio; use k210_soc::utils::{set_bit,get_bit}; /** Set input/output direction for a GPIOHS pin */ pub fn set_direction(pin: u8, direction: gpio::direction) { unsafe { let ptr = k210_pac::GPIO::ptr(); // 就是前面映射的地址 (*ptr) .direction .modify(|r, w| w.bits(set_bit(r.bits(), pin, direction == gpio::direction::OUTPUT))); } } /** Set output value for a GPIOHS pin */ pub fn set_pin(pin: u8, value: bool) { unsafe { let ptr = k210_pac::GPIO::ptr(); (*ptr) .data_output .modify(|r, w| w.bits(set_bit(r.bits(), pin, value))); } }
因为 k210_soc 项目缺少操作 GPIO 到驱动,我们正好练习写一个 GPIO 驱动
- 在 driver/gpio/driver.rs 中引入 k210_pac lib
- 模仿 gpiohs 操作数据结构中的 direction 和 data_output
- led_gpio.rs 参考 led.rs ,区别是不使用 gpiohs 而使用我们的 driver/gpio/driver.rs
代码请参考:https://github.com/buhe/bugu/tree/9