diff --git a/heterogeneous/src/lib.rs b/heterogeneous/src/lib.rs index 3288bfe012..95ff184d04 100644 --- a/heterogeneous/src/lib.rs +++ b/heterogeneous/src/lib.rs @@ -8,7 +8,7 @@ use core::{ }; use bare_metal::Nr; -use rtfm::{Monotonic, MultiCore}; +use rtfm::{Fraction, Monotonic, MultiCore}; // both cores have the exact same interrupts pub use Interrupt_0 as Interrupt_1; @@ -24,8 +24,11 @@ pub struct MT; impl Monotonic for MT { type Instant = Instant; - fn ratio() -> u32 { - 1 + fn ratio() -> Fraction { + Fraction { + numerator: 1, + denominator: 1, + } } unsafe fn reset() { diff --git a/homogeneous/src/lib.rs b/homogeneous/src/lib.rs index 3288bfe012..95ff184d04 100644 --- a/homogeneous/src/lib.rs +++ b/homogeneous/src/lib.rs @@ -8,7 +8,7 @@ use core::{ }; use bare_metal::Nr; -use rtfm::{Monotonic, MultiCore}; +use rtfm::{Fraction, Monotonic, MultiCore}; // both cores have the exact same interrupts pub use Interrupt_0 as Interrupt_1; @@ -24,8 +24,11 @@ pub struct MT; impl Monotonic for MT { type Instant = Instant; - fn ratio() -> u32 { - 1 + fn ratio() -> Fraction { + Fraction { + numerator: 1, + denominator: 1, + } } unsafe fn reset() { diff --git a/src/cyccnt.rs b/src/cyccnt.rs index 468aa712b6..c8a1b7ee61 100644 --- a/src/cyccnt.rs +++ b/src/cyccnt.rs @@ -10,9 +10,15 @@ use core::{ use cortex_m::peripheral::DWT; +use crate::Fraction; + /// A measurement of the CYCCNT. Opaque and useful only with `Duration` /// /// This data type is only available on ARMv7-M +/// +/// Note that this value is tied to the CYCCNT of one core and that sending it a different core +/// makes it lose its meaning -- each Cortex-M core has its own CYCCNT counter and these are usually +/// unsynchronized and they may even be running at different frequencies. #[derive(Clone, Copy, Eq, PartialEq)] pub struct Instant { inner: i32, @@ -21,7 +27,6 @@ pub struct Instant { unsafe impl Sync for Instant {} -#[cfg(not(feature = "heterogeneous"))] unsafe impl Send for Instant {} impl Instant { @@ -182,15 +187,16 @@ impl U32Ext for u32 { } /// Implementation of the `Monotonic` trait based on CYCle CouNTer -#[cfg(not(feature = "heterogeneous"))] pub struct CYCCNT; -#[cfg(not(feature = "heterogeneous"))] impl crate::Monotonic for CYCCNT { type Instant = Instant; - fn ratio() -> u32 { - 1 + fn ratio() -> Fraction { + Fraction { + numerator: 1, + denominator: 1, + } } unsafe fn reset() { diff --git a/src/lib.rs b/src/lib.rs index decd2da1b7..22eff5ac08 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -116,13 +116,25 @@ impl From for Peripherals { } } +/// A fraction +pub struct Fraction { + /// The numerator + pub numerator: u32, + + /// The denominator + pub denominator: u32, +} + /// A monotonic clock / counter pub trait Monotonic { /// A measurement of this clock type Instant: Copy + Ord + Sub; /// The ratio between the SysTick (system timer) frequency and this clock frequency - fn ratio() -> u32; + /// + /// The ratio must be expressed in *reduced* `Fraction` form to prevent overflows. That is + /// `2 / 3` instead of `4 / 6` + fn ratio() -> Fraction; /// Returns the current time fn now() -> Self::Instant; diff --git a/src/tq.rs b/src/tq.rs index 4f9b6e7e91..4edb40a7fe 100644 --- a/src/tq.rs +++ b/src/tq.rs @@ -62,11 +62,11 @@ where // set a new timeout const MAX: u32 = 0x00ffffff; - let dur = match (instant - now) - .try_into() - .ok() - .and_then(|x| x.checked_mul(M::ratio())) - { + let ratio = M::ratio(); + let dur = match (instant - now).try_into().ok().and_then(|x| { + x.checked_mul(ratio.numerator) + .map(|x| x / ratio.denominator) + }) { None => MAX, Some(x) => cmp::min(MAX, x), };