Skip to content

Commit

Permalink
Impl the getting of systime as a clock count impl
Browse files Browse the repository at this point in the history
  • Loading branch information
Ben-PH committed May 23, 2024
1 parent a0a02ce commit ef763f4
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 56 deletions.
1 change: 1 addition & 0 deletions esp-hal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion esp-hal/src/soc/esp32/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
139 changes: 84 additions & 55 deletions esp-hal/src/time.rs
Original file line number Diff line number Diff line change
@@ -1,76 +1,105 @@
//! 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.
///
/// The timer will wrap after
#[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<u64, 1, 1_000_000> {
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<Self::RawData, 1, {crate::timer::systimer::TICKS_PER_SECOND}>;
#[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<Self::RawData, 1, 16_000_000>;

type Error = ();

fn try_now_raw(&self) -> Result<Self::RawData, Self::Error> {
#[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::<u64, 1, 1_000_000>::from_ticks(ticks / div)
Ok(ticks)
}

fn try_now(&self) -> Result<Self::TickMeasure, Self::Error> {
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) -> <Self as counters::TimeCount>::TickMeasure {
self.try_now().unwrap()
}
}

0 comments on commit ef763f4

Please sign in to comment.