之前的几篇中,我编写rv32m1_ri5cy-pac“总线资源库(PAC)”定义了寄存器,然后开发了基于这个库的rv32m1_ri5cy-example v0.1.2“应用程序”。部分关键代码如下(从v0.1.2源码摘录):
loop {
peripherals.GPIOA.psor.write(|w| unsafe { w.ptso().bits(1u32 << BOARD_LED_GPIO_PIN) });
delay(DELAY_CYCLES);
peripherals.GPIOA.pcor.write(|w| unsafe { w.ptco().bits(1u32 << BOARD_LED_GPIO_PIN) });
delay(DELAY_CYCLES);
}
通过可以看到,这个与C语言中直接驱动寄存器的写法是一样的,属于比较低级的一种驱动方法。我们使用的Rust是一门抽象程度相对较高的语言,因此我们应当考虑对这些操作做进一步的封装。
根据官方Rust工作组的建议(来源),一个Rust嵌入式工程的结构应当是:
- 总线资源库 (Peripheral Access Crate, PAC)
位于底层,只规定寄存器的地址和访问方法。
- 硬件抽象层 (Hardware Abstraction Layer, HAL)
按照统一的接口约定,将芯片硬件资源,抽象成函数和方法。
- 板级支持库 (Board Support Crate)
将开发板的硬件资源,映射到芯片的硬件资源上。
- 应用程序层 (Application)
位于顶层,使用下边所有支持层提供的功能驱动硬件。
因此我编写了一个“硬件抽象层 (Hardware Abstraction Layer, HAL)”用于将寄存器操作封装起来,形成一般的函数调用。使用这个硬件抽象层可以让代码大体上变成这样:
let mut gpioa = peripherals.GPIOA.split();
loop {
gpioa.p24.set_high()?;
delay(DELAY_CYCLES);
gpioa.p24.set_low()?;
delay(DELAY_CYCLES);
}
硬件抽象层 rv32m1_ri5cy-hal 已经发布到GitHub和crates.io,对应的 rv32m1_ri5cy-example 示例也已更新了 v0.1.3 版本。
这个HAL库本身还是很初期的(0.0.1版本,原理验证性质)。只搭好了架构,并实际实现了一个gpio接口的一个pin的抽象,只算一个草稿,而并不适合实用。需要补充所有周边硬件的具体实现。求pull request合作开发。
附:现在已经实现的整体架构如下(红色字为我原创编写的部分)