#嵌入式时间 #cortex-m #无std

无std drogue-embedded-timer

宏函数,用于将异构的HAL定时器适配到嵌入式时间

3个不稳定版本

0.2.1 2020年10月7日
0.2.0 2020年10月5日
0.1.0 2020年9月29日

#1501嵌入式开发


3 个软件包 使用

Apache-2.0

16KB
315

drogue-embedded-timer

crates.io docs.rs Matrix

在针对 embedded-hal 编写设备驱动程序时,由于与 Time 关联类型相关,尝试使用 CountDown 定时器时会遇到障碍。

embedded-time 软件包试图统一时间、时钟、持续时间和速率的概念。到目前为止,各个 HAL 还未采用 embedded-time,因此这个软件包提供了一个简单的宏来帮助适配需要一致视图的驱动程序。

将 HAL CountDown 转换为 embedded-time

泛型驱动程序应以 CountDown 的形式编写,它使用 embedded-time 的时间版本。

尝试配置上述驱动程序具体实例的应用程序编写者可以使用此宏将他们的 HAL 定时器转换为以 embedded-time 为中心的 CountDown

示例

使用 embedded_countdown!(...) 宏定义一个新结构体,它可以消费特定的 HAL 定时器,并将其包装成一个 embedded-time 定时器。

该宏接受几个参数

  1. 要创建的结构体的名称。
  2. 驱动程序期望的暴露单位(通常是 embedded-time 持续时间)。
  3. 被包装的内置 CountDown 结构体期望的 HAL 的单位。
  4. 处理转换的 1-参数转换例程。
embedded_countdown!(MsToHertzCountDown,
                embedded_time::duration::Milliseconds,
                stm32l4xx_hal::time::Hertz
                 => (ms) {
                        let hz: embedded_time::rate::Hertz = ms.to_rate().unwrap();
                        stm32l4xx_hal::time::Hertz(hz.0)
                } );

定义一个结构体后,您就可以使用它了

let mut hal_hz_timer = Timer::tim16(device.TIM16, 1, clocks, &mut rcc.apb2);
let mut embedded_ms_timer = MsToHertzCountDown::from(hal_hz_timer);

现在 embedded_ms_timer 是一个 CountDown<Time=embedded_time::duration::Milliseconds>,不再与特定的 HAL 实现绑定。

直接使用 embedded-time 时钟和定时器

此软件包提供机制,以使 embedded-time 中心的 Clock 能够创建 embedded-time 定时器。

首先,您决定想要使用的时钟精度。

可用的精度如下

  • 1 微秒
  • 2 微秒
  • 5 微秒
  • 10 微秒
  • 25 微秒
  • 50 微秒
  • 100 微秒
  • 200 微秒
  • 250 微秒
  • 500 微秒
  • 1 毫秒
  • 2 毫秒
  • 5 毫秒
  • 10 毫秒
  • 25 毫秒
  • 50 毫秒
  • 100 毫秒
  • 200 毫秒
  • 250 毫秒
  • 500 毫秒
  • 1 秒
  • 30 秒
  • 60 秒

每种时钟类型都有一个相关的 计时器 类型,也必须使用


use drogue_embedded_timer::{
  MillisecondsClock100,
  MillisecondsTicker100,
}

将时钟定义为静态变量

static CLOCK: MillisecondsClock100 = MillisecondsClock100::new();

配置您的芯片定时器以匹配所选的 CLOCK

// STM32L4xx configuration, yours may vary:
let mut tim15 = Timer::tim15(device.TIM15, 100, clocks, &mut rcc.apb2);

将定时器配置为中断源

tim15.listen(Event::TimeOut);

CLOCK 获取一个 计时器 用于在 ISR 中使用。The ticker(...) 方法接受两个参数

  1. 您可以使用的一些对象来清除超时(否则不受限制)。
  2. 一个类似函数的对象,可以使用(1)上面的对象来清除超时。
let ticker = CLOCK.ticker(
               tim15, 
               (|t| { t.clear_interrupt(Event::TimeOut); }) as fn(&mut Timer<TIM15>));

使用 RTIC,您可能希望将 计时器 分配到共享资源对象中

struct Resources {
    ticker: MillisecondsTicker100<'static, MillisecondsClock100, Timer<TIM15>, fn(&mut Timer<TIM15>)>,
    ...
}

在 ISR 触发时,在计时器上调用 tick()。在 RTIC 中,它可能看起来像这样

#[task(binds = TIM15, priority = 15, resources = [ticker])]
fn ticker(mut ctx: ticker::Context) {
    ctx.resources.ticker.tick();
}

ISR 应该具有相对较高的优先级,以确保时间流逝。

创建定时器

一旦您的时钟开始运行并滴答作响,您就可以创建尽可能多的定时器,使用正常的 embedded-time 功能性

// effectively a blocking Delay type of action:
let my_timer = embedded_time::Timer::new(&CLOCK, Seconds(10u32));
let my_timer = my_timer.start().unwrap();
my_timer.wait().unwrap();

可重用延迟

此包还提供了类似于 Embedded HAL 的 DelayMsDelayUs 对象的功能。延迟可以直接构造,或通过时钟的 delay() 工厂创建。

let delay = &CLOCK.delay();
delay.delay(Milliseconds(50u32));

一旦 Delay 过期,它就可以重新使用。

依赖关系

~1.5MB
~24K SLoC