Time-keeping

In an embedded program, delaying a task is one of the most common actions taken. In an event loop, delays will need to be inserted to ensure that other tasks have a chance to run before the next iteration of the loop is called, if no other I/O is performed. Embassy provides abstractions to delay the current task for a specified interval of time.

The interface for time-keeping in Embassy is handled by the embassy-time crate. The types can be used with the internal timer queue in embassy-executor or a custom timer queue implementation.

Timer

The embassy::time::Timer type provides two timing methods.

Timer::at creates a future that completes at the specified Instant, relative to the system boot time. Timer::after creates a future that completes after the specified Duration, relative to when the future was created.

An example of a delay is provided as follows:

use embassy::executor::{task, Executor};
use embassy::time::{Duration, Timer};

#[task]
/// Task that ticks periodically
async fn tick_periodic() -> ! {
    loop {
        rprintln!("tick!");
        // async sleep primitive, suspends the task for 500ms.
        Timer::after(Duration::from_millis(500)).await;
    }
}

Delay

The embassy::time::Delay type provides an implementation of the embedded-hal and embedded-hal-async traits. This can be used for drivers that expect a generic delay implementation to be provided.

An example of how this can be used:

use embassy::executor::{task, Executor};

#[task]
/// Task that ticks periodically
async fn tick_periodic() -> ! {
    loop {
        rprintln!("tick!");
        // async sleep primitive, suspends the task for 500ms.
        generic_delay(embassy::time::Delay).await
    }
}

async fn generic_delay<D: embedded_hal_async::delay::DelayNs>(delay: D) {
      delay.delay_ms(500).await;
}