OS 简单教程番外2:简单的驱动,点亮LEDOS 简单教程番外2:简单的驱动,点亮LED
📻

OS 简单教程番外2:简单的驱动,点亮LED

启用了虚拟内存之后,访问 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)); }
  1. fpio 映射实际物理引脚(io::LED_B) 到 GPIOHS0(fpioa::function::GPIOHS0) ,也就是高速 GPIO 0 号
  1. 设置高速 GPIO 0 号输出
  1. 设置高速 GPIO 0 号低电平
notion imagenotion image

外部的 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)); }
  1. 分别映射 9 10 两个引脚到 0 1
  1. 0 1 设置为输出
  1. 0 1 分别设置为低电平和高电平
  1. 插入 led,注意正负极
notion imagenotion image

用 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 驱动
  1. 在 driver/gpio/driver.rs 中引入 k210_pac lib
  1. 模仿 gpiohs 操作数据结构中的 direction 和 data_output
  1. led_gpio.rs 参考 led.rs ,区别是不使用 gpiohs 而使用我们的 driver/gpio/driver.rs
代码请参考:https://github.com/buhe/bugu/tree/9