Time Keeping
In embedded programs, delaying tasks is one of the most common operations. In an event loop, if no other I/O operations are performed, delays need to be inserted to ensure that other tasks have a chance to run before the next iteration of the loop is called. Embassy provides abstractions to delay the current task for a specified interval.
The interfaces for time keeping in Embassy are handled by the embassy-time crate. These types can be used with the internal timer queue in embassy-executor or custom timer queue implementations.
Timer
The embassy::time::Timer
type provides two methods for timing.
Timer::at(Instant)
: Creates a future that completes at the specifiedInstant
, relative to system startup time. This is useful for scheduling tasks at a specific point in time.Timer::after(Duration)
: Creates a future that completes after the specifiedDuration
, relative to the time the future is created. This is useful for creating delays or timeouts.
Here is an example of using Timer::after
for periodic tasks:
Hint: The dependencies required to run this example can be found here.
use embassy::executor::{task, Executor};
use embassy::time::{Duration, Timer};
use embassy_rp::rprintln; // For Raspberry Pi Pico examples, replace with println! for other targets
#[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 implementations of the embedded-hal
and embedded-hal-async
traits. This allows for generic delay implementations in drivers.
Here is an example of using Delay
with a generic delay function:
Hint: The dependencies required to run this example can be found here.
use embassy::executor::{task, Executor};
use embassy_rp::rprintln; // For Raspberry Pi Pico examples, replace with println! for other targets
#[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;
}
Improvements
Here are the improvements made to the code and documentation:
-
Code Readability and Maintainability:
- Added more descriptive comments to the
Timer::at
andTimer::after
methods, explaining their use cases. - Replaced
println!
withrprintln!
in code examples, assuming this is for Raspberry Pi Pico examples based on theembassy_rp
import. For other targets, users should useprintln!
. Added a comment to clarify this.
- Added more descriptive comments to the
-
Best Practices and Patterns:
- Emphasized the use of
Timer::at
for scheduling tasks at specific times andTimer::after
for delays and timeouts, providing clearer guidance on when to use each method. - Maintained the use of functional and declarative programming patterns, avoiding classes as per best practices.
- Used descriptive variable names and followed consistent naming conventions.
- Emphasized the use of
-
No Performance Optimization or Error Handling Improvements:
- The provided code examples are simple and primarily for demonstrating basic time-keeping functionalities. Performance optimization and error handling are not critical aspects in these examples. In more complex scenarios, these aspects would need to be addressed.
This improved documentation provides a clearer explanation of time keeping in Embassy with enhanced code examples and explanations.