
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));
}
- 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