From 612a47ef4d09da3553145d77bf1750314bbb7b16 Mon Sep 17 00:00:00 2001 From: Finomnis Date: Fri, 1 Dec 2023 08:59:22 +0100 Subject: 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 --- rtic-time/src/lib.rs | 22 +++++-- rtic-time/src/monotonic.rs | 153 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 171 insertions(+), 4 deletions(-) (limited to 'rtic-time/src') diff --git a/rtic-time/src/lib.rs b/rtic-time/src/lib.rs index 0c3e349..4c89d52 100644 --- a/rtic-time/src/lib.rs +++ b/rtic-time/src/lib.rs @@ -181,22 +181,36 @@ impl TimerQueue { } } - /// Timeout after a specific duration. + /// Timeout after at least a specific duration. #[inline] pub async fn timeout_after( &self, duration: Mono::Duration, future: F, ) -> Result { - 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. diff --git a/rtic-time/src/monotonic.rs b/rtic-time/src/monotonic.rs index ad79bf2..0c0d6f3 100644 --- a/rtic-time/src/monotonic.rs +++ b/rtic-time/src/monotonic.rs @@ -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; + } + } + }; +} -- cgit v1.2.3