4个版本
0.1.3 | 2019年7月30日 |
---|---|
0.1.2 | 2019年7月29日 |
0.1.1 | 2019年7月29日 |
0.1.0 | 2019年7月27日 |
1929 in 嵌入式开发
66KB
1K SLoC
LPC11xx Async HAL
使用async-await语法为NXP LPC111x/LPC11Cxx/LPC11xxL/LPC11xxXL系列Cortex-M0微控制器提供的异步HAL。
示例
以下是一个使用UART驱动器的最小echo服务器示例。微控制器仅在UART中断中发送/接收数据以及从async fn
中的PendSV
发出附加UART命令时从睡眠状态唤醒,其余时间处于睡眠状态。
use lpc11xx_async_hal::uart;
// Initialize the UART driver ahead of time, e.g. 9600 baud at 12MHz
// The UART peripheral must have power, a clock, configured pins etc
let uart = uart::Driver::initialize(
device.UART, // < lpc11xx::UART
uart::Options {
clock_divisor: 71,
fractional_div: 0,
fractional_mul: 1,
flow_control: false,
rx_threshold: uart::RxThreshold::default(),
},
);
// The actual logic, to be polled from the PendSV interrupt handler
async fn echo_server(mut uart: uart::Driver) -> ! {
let (mut sender, mut receiver) = uart.split();
sender.write(b"Type some text: ").await;
loop {
let mut buffer = [0; 20];
let bytes_read = receiver.read(&mut buffer).await;
sender.write(&buffer[..bytes_read]).await;
}
}
状态
以下外设的异步驱动程序目前可用
外设 | 缺失的功能 | 不会实现 |
---|---|---|
UART | 自动波特率,RS-485 | |
I2C | 从模式 | 监视模式 |
ADC | 定时器匹配 | |
SysTick |
更多功能正在开发中,欢迎贡献和建议。
注意事项
由于Rust的async-await特性仍在积极开发中,更不用说其#![no_std]
集成,因此此crate应被视为一个证明概念和持续实验,用于在LPC11xx设备上编写自动生成的异步状态机。尽管如此,它确实工作良好并做了有用的事情。
无std支持
在使用#![no_std]
crate中的async-await时,会产生一个额外的问题;基本上,它不起作用,因为生成结果的future所需的编译器机制依赖于线程局部存储,而线程局部存储位于std
中。您可以通过使用core-futures-stateless
辅助crate来解决此问题,该crate将修补libcore以使#![feature(async_await)]
工作
[dependencies.core]
package = "core-futures-stateless"
version = "0.1.0"
这将在libcore修复后删除。请注意,这将在编译器消息中更改core
crate中所有类型的crate名称。
未来行为
此crate专门针对Cortex-M处理器中的PendSV
功能构建。也就是说,所有未来都依赖于在PendSV
异常处理程序中进行轮询,所有外设中断处理程序都会引发PendSV
以推进未来。因此,与您的main异步任务关联的task::Context
是无关紧要的,您应该创建一个什么也不做的虚拟Waker
。The core-futures-stateless
crate提供了一个方便的方法task::stateless_waker()
,它正是这样做的。
use core::future::Future;
use core::task::{stateless_waker, Context};
// your executor somewhere inside the PendSV exception handler
match Future::poll(your_pinned_future, &mut Context::from_waker(stateless_waker())) {
Poll::Ready(x) => { /* future resolved */ },
Poll::Pending => { /* go back to sleep */ },
}
未来,这个crate可能会变得具有上下文感知能力,但与此同时,这是出于简化和因为使用PendSV
是轮询未来的相当自然的方法。
内存安全
目前,在这个crate中存在一个小的健全性问题,即中断处理程序从当前运行的未来引用类似于堆栈的内存,这意味着Future类型的Drop
实现必须运行以确保内存安全。我不确定如何在不牺牲性能或易用性的情况下解决这个问题,并且并不认为这是一个从实用主义角度来看的重大问题。泄露未来自负其责。
依赖关系
~3MB
~75K SLoC