From ef763f441da77bb6fad809428d26bfc007b858d3 Mon Sep 17 00:00:00 2001 From: Ben PHL Date: Thu, 23 May 2024 19:33:23 +0200 Subject: [PATCH] Impl the getting of systime as a clock count impl --- esp-hal/Cargo.toml | 1 + esp-hal/src/soc/esp32/mod.rs | 2 +- esp-hal/src/time.rs | 139 +++++++++++++++++++++-------------- 3 files changed, 86 insertions(+), 56 deletions(-) diff --git a/esp-hal/Cargo.toml b/esp-hal/Cargo.toml index 930bda96a5b..188cb7fe7e8 100644 --- a/esp-hal/Cargo.toml +++ b/esp-hal/Cargo.toml @@ -51,6 +51,7 @@ usb-device = { version = "0.3.2", optional = true } rand_core = "0.6.4" ufmt-write = { version = "0.1.0", optional = true } xtensa-lx = { version = "0.9.0", optional = true } +counters = {git = "https://github.com/Ben-PH/counter-proposal.git", rev = "07d19fe62c36219663c3917bb8cf1fe5eb752eaa"} # IMPORTANT: # Each supported device MUST have its PAC included below along with a diff --git a/esp-hal/src/soc/esp32/mod.rs b/esp-hal/src/soc/esp32/mod.rs index 6806e65e0c2..5e1261e1780 100644 --- a/esp-hal/src/soc/esp32/mod.rs +++ b/esp-hal/src/soc/esp32/mod.rs @@ -85,7 +85,7 @@ pub unsafe extern "C" fn ESP32Reset() -> ! { } crate::interrupt::setup_interrupts(); - crate::time::time_init(); + let _ = crate::time::SysUptime::time_init(); // continue with default reset handler xtensa_lx_rt::Reset(); diff --git a/esp-hal/src/time.rs b/esp-hal/src/time.rs index 034e7acd228..037a804f47c 100644 --- a/esp-hal/src/time.rs +++ b/esp-hal/src/time.rs @@ -1,12 +1,17 @@ -//! The `time` module offers a way to get the system uptime. +//! `SysUptime` implements proposed embedded-hal `TimeCount` trait to get system uptime //! //! ### Example //! ```no_run //! let time = time::current_time(); //! ``` #![warn(missing_docs)] +use counters::TimeCount; -/// Provides time since system start in microseconds precision +/// Provides an interface by which to access the platforms clock. Can be used where +/// (proposed) embedded-hal `TimeCount` implementor is expected. +pub struct SysUptime; + +/// Provides time since system start /// /// The counter won’t measure time in sleep-mode. /// @@ -14,63 +19,87 @@ #[cfg_attr(esp32, doc = "36_558 years")] #[cfg_attr(esp32s2, doc = "7_311 years")] #[cfg_attr(not(any(esp32, esp32s2)), doc = "more than 7 years")] -pub fn current_time() -> fugit::Instant { +impl counters::TimeCount for SysUptime { + type RawData = u64; + + + + /// Defines granularity of the timer. Combines with the raw tick count to derive an instant + #[cfg(not(esp32))] + type TickMeasure = fugit::Instant; #[cfg(esp32)] - let (ticks, div) = { - // on ESP32 use LACT - let tg0 = unsafe { crate::peripherals::TIMG0::steal() }; - tg0.lactupdate().write(|w| unsafe { w.update().bits(1) }); - - // The peripheral doesn't have a bit to indicate that the update is done, so we - // poll the lower 32 bit part of the counter until it changes, or a timeout - // expires. - let lo_initial = tg0.lactlo().read().bits(); - let mut div = tg0.lactconfig().read().divider().bits(); - let lo = loop { - let lo = tg0.lactlo().read().bits(); - if lo != lo_initial || div == 0 { - break lo; - } - div -= 1; + type TickMeasure = fugit::Duration; + + type Error = (); + + fn try_now_raw(&self) -> Result { + #[cfg(esp32)] + let ticks = { + // on ESP32 use LACT + let tg0 = unsafe { crate::peripherals::TIMG0::steal() }; + tg0.lactupdate().write(|w| unsafe { w.update().bits(1) }); + + // The peripheral doesn't have a bit to indicate that the update is done, so we + // poll the lower 32 bit part of the counter until it changes, or a timeout + // expires. + let lo_initial = tg0.lactlo().read().bits(); + let mut div = tg0.lactconfig().read().divider().bits(); + let lo = loop { + let lo = tg0.lactlo().read().bits(); + if lo != lo_initial || div == 0 { + break lo; + } + div -= 1; + }; + let hi = tg0.lacthi().read().bits(); + + let ticks = (hi as u64) << 32u64 | lo as u64; + ticks }; - let hi = tg0.lacthi().read().bits(); - let ticks = (hi as u64) << 32u64 | lo as u64; - (ticks, 16) - }; + #[cfg(not(esp32))] + let ticks = { + // otherwise use SYSTIMER + crate::timer::systimer::SystemTimer::now() + }; - #[cfg(not(esp32))] - let (ticks, div) = { - // otherwise use SYSTIMER - let ticks = crate::timer::systimer::SystemTimer::now(); - ( - ticks, - (crate::timer::systimer::SystemTimer::TICKS_PER_SECOND / 1_000_000), - ) - }; - - fugit::Instant::::from_ticks(ticks / div) + Ok(ticks) + } + + fn try_now(&self) -> Result { + let ticks = self.try_now_raw()?; + Ok(Self::TickMeasure::from_ticks(ticks)) + + } } -#[cfg(esp32)] -pub(crate) fn time_init() { - // we assume 80MHz APB clock source - there is no way to configure it in a - // different way currently - const APB_FREQUENCY: u32 = 80_000_000u32; - - let tg0 = unsafe { crate::peripherals::TIMG0::steal() }; - - tg0.lactconfig().write(|w| unsafe { w.bits(0) }); - tg0.lactalarmhi().write(|w| unsafe { w.bits(u32::MAX) }); - tg0.lactalarmlo().write(|w| unsafe { w.bits(u32::MAX) }); - tg0.lactload().write(|w| unsafe { w.load().bits(1) }); - - // 16 MHz counter - tg0.lactconfig() - .modify(|_, w| unsafe { w.divider().bits((APB_FREQUENCY / 16_000_000u32) as u16) }); - tg0.lactconfig().modify(|_, w| { - w.increase().bit(true); - w.autoreload().bit(true); - w.en().bit(true) - }); +impl SysUptime { + #[cfg(esp32)] + pub(crate) fn time_init() -> Self { + // we assume 80MHz APB clock source - there is no way to configure it in a + // different way currently + const APB_FREQUENCY: u32 = 80_000_000u32; + + let tg0 = unsafe { crate::peripherals::TIMG0::steal() }; + + tg0.lactconfig().write(|w| unsafe { w.bits(0) }); + tg0.lactalarmhi().write(|w| unsafe { w.bits(u32::MAX) }); + tg0.lactalarmlo().write(|w| unsafe { w.bits(u32::MAX) }); + tg0.lactload().write(|w| unsafe { w.load().bits(1) }); + + // 16 MHz counter + tg0.lactconfig() + .modify(|_, w| unsafe { w.divider().bits((APB_FREQUENCY / 16_000_000u32) as u16) }); + tg0.lactconfig().modify(|_, w| { + w.increase().bit(true); + w.autoreload().bit(true); + w.en().bit(true) + }); + Self + } + #[deprecated(note = "Use SysUptime::try_now() instead")] + #[allow(missing_docs)] + pub fn current_time(&self) -> ::TickMeasure { + self.try_now().unwrap() + } }