Fix mono delay (#843)

* rtic-time: Compenstate for timer uncertainty

* Update changelog and incorrect cargo.lock in an example

* Fix Monotonic impls

* Fix tests

* Fix other monotonics, again

* Update changelog

* Fix example

* Fix DelayUs and DelayMs impls

* Minor coding style fix in u64 conversions

* Fix all changelogs

* Fix changelog

* Fix blocking DelayUs

* Minor monotonic rework

* Add delay precision test

* Add more tests

* Add rust-version tags to Cargo.toml

* Fix imxrt, rp2040 and systick timer

* Fix more monotonics

* Fix systick monotonic

* Some reverts

* Fix imxrt

* Fix nrf

* Fix rp2040

* Fix stm32

* Fix systick

* Fix rtic-time tests

* Bump to e-h.rc2

* Apply e-h.rc2 fixes to rtic-time

* Apply fixes from arbiter

* Fix clippy warning

* Minor beautification

* Revert previous changes

* Fix variable name

* Add blocking tests, but disable them by default
This commit is contained in:
Finomnis 2023-12-01 08:59:22 +01:00 committed by GitHub
parent 9f5820da1d
commit 612a47ef4d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 560 additions and 141 deletions

View file

@ -181,22 +181,36 @@ impl<Mono: Monotonic> TimerQueue<Mono> {
}
}
/// Timeout after a specific duration.
/// Timeout after at least a specific duration.
#[inline]
pub async fn timeout_after<F: Future>(
&self,
duration: Mono::Duration,
future: F,
) -> Result<F::Output, TimeoutError> {
self.timeout_at(Mono::now() + duration, future).await
let now = Mono::now();
let mut timeout = now + duration;
if now != timeout {
timeout = timeout + Mono::TICK_PERIOD;
}
// Wait for one period longer, because by definition timers have an uncertainty
// of one period, so waiting for 'at least' needs to compensate for that.
self.timeout_at(timeout, future).await
}
/// Delay for some duration of time.
/// Delay for at least some duration of time.
#[inline]
pub async fn delay(&self, duration: Mono::Duration) {
let now = Mono::now();
let mut timeout = now + duration;
if now != timeout {
timeout = timeout + Mono::TICK_PERIOD;
}
self.delay_until(now + duration).await;
// Wait for one period longer, because by definition timers have an uncertainty
// of one period, so waiting for 'at least' needs to compensate for that.
self.delay_until(timeout).await;
}
/// Delay to some specific time instant.

View file

@ -10,6 +10,9 @@ pub trait Monotonic {
/// The time at time zero.
const ZERO: Self::Instant;
/// The duration between two timer ticks.
const TICK_PERIOD: Self::Duration;
/// The type for instant, defining an instant in time.
///
/// **Note:** In all APIs in RTIC that use instants from this monotonic, this type will be used.
@ -65,3 +68,153 @@ pub trait Monotonic {
/// NOTE: This may be called more than once.
fn disable_timer() {}
}
/// Creates impl blocks for `embedded_hal::delay::DelayUs`,
/// based on `fugit::ExtU64Ceil`.
#[macro_export]
macro_rules! embedded_hal_delay_impl_fugit64 {
($t:ty) => {
impl ::embedded_hal::delay::DelayNs for $t {
fn delay_ns(&mut self, ns: u32) {
use ::fugit::ExtU64Ceil;
let now = Self::now();
let mut done = now + u64::from(ns).nanos_at_least();
if now != done {
// Compensate for sub-tick uncertainty
done += Self::TICK_PERIOD;
}
while Self::now() < done {}
}
fn delay_us(&mut self, us: u32) {
use ::fugit::ExtU64Ceil;
let now = Self::now();
let mut done = now + u64::from(us).micros_at_least();
if now != done {
// Compensate for sub-tick uncertainty
done += Self::TICK_PERIOD;
}
while Self::now() < done {}
}
fn delay_ms(&mut self, ms: u32) {
use ::fugit::ExtU64Ceil;
let now = Self::now();
let mut done = now + u64::from(ms).millis_at_least();
if now != done {
// Compensate for sub-tick uncertainty
done += Self::TICK_PERIOD;
}
while Self::now() < done {}
}
}
};
}
/// Creates impl blocks for `embedded_hal_async::delay::DelayUs`,
/// based on `fugit::ExtU64Ceil`.
#[macro_export]
macro_rules! embedded_hal_async_delay_impl_fugit64 {
($t:ty) => {
impl ::embedded_hal_async::delay::DelayNs for $t {
#[inline]
async fn delay_ns(&mut self, ns: u32) {
use ::fugit::ExtU64Ceil;
Self::delay(u64::from(ns).nanos_at_least()).await;
}
#[inline]
async fn delay_us(&mut self, us: u32) {
use ::fugit::ExtU64Ceil;
Self::delay(u64::from(us).micros_at_least()).await;
}
#[inline]
async fn delay_ms(&mut self, ms: u32) {
use ::fugit::ExtU64Ceil;
Self::delay(u64::from(ms).millis_at_least()).await;
}
}
};
}
/// Creates impl blocks for `embedded_hal::delay::DelayUs`,
/// based on `fugit::ExtU32Ceil`.
#[macro_export]
macro_rules! embedded_hal_delay_impl_fugit32 {
($t:ty) => {
impl ::embedded_hal::delay::DelayNs for $t {
fn delay_ns(&mut self, ns: u32) {
use ::fugit::ExtU32Ceil;
let now = Self::now();
let mut done = now + ns.nanos_at_least();
if now != done {
// Compensate for sub-tick uncertainty
done += Self::TICK_PERIOD;
}
while Self::now() < done {}
}
fn delay_us(&mut self, us: u32) {
use ::fugit::ExtU32Ceil;
let now = Self::now();
let mut done = now + us.micros_at_least();
if now != done {
// Compensate for sub-tick uncertainty
done += Self::TICK_PERIOD;
}
while Self::now() < done {}
}
fn delay_ms(&mut self, ms: u32) {
use ::fugit::ExtU32Ceil;
let now = Self::now();
let mut done = now + ms.millis_at_least();
if now != done {
// Compensate for sub-tick uncertainty
done += Self::TICK_PERIOD;
}
while Self::now() < done {}
}
}
};
}
/// Creates impl blocks for `embedded_hal_async::delay::DelayUs`,
/// based on `fugit::ExtU32Ceil`.
#[macro_export]
macro_rules! embedded_hal_async_delay_impl_fugit32 {
($t:ty) => {
impl ::embedded_hal_async::delay::DelayNs for $t {
#[inline]
async fn delay_ns(&mut self, ns: u32) {
use ::fugit::ExtU32Ceil;
Self::delay(ns.nanos_at_least()).await;
}
#[inline]
async fn delay_us(&mut self, us: u32) {
use ::fugit::ExtU32Ceil;
Self::delay(us.micros_at_least()).await;
}
#[inline]
async fn delay_ms(&mut self, ms: u32) {
use ::fugit::ExtU32Ceil;
Self::delay(ms.millis_at_least()).await;
}
}
};
}