Add current_time (#1503)
* Add `current_time` * CHANGELOG.md * Add HIL test for `current_time` * Fix after rebase
This commit is contained in:
parent
ad1176865e
commit
373735f96a
@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Added
|
||||
|
||||
- ESP32-PICO-V3-02: Initial support (#1155)
|
||||
- `time::current_time` API (#1503)
|
||||
|
||||
### Fixed
|
||||
|
||||
|
||||
@ -153,6 +153,7 @@ pub mod spi;
|
||||
pub mod system;
|
||||
#[cfg(systimer)]
|
||||
pub mod systimer;
|
||||
pub mod time;
|
||||
#[cfg(any(timg0, timg1))]
|
||||
pub mod timer;
|
||||
#[cfg(trace0)]
|
||||
|
||||
@ -77,6 +77,7 @@ pub unsafe extern "C" fn ESP32Reset() -> ! {
|
||||
}
|
||||
|
||||
crate::interrupt::setup_interrupts();
|
||||
crate::time::time_init();
|
||||
|
||||
// continue with default reset handler
|
||||
xtensa_lx_rt::Reset();
|
||||
|
||||
76
esp-hal/src/time.rs
Normal file
76
esp-hal/src/time.rs
Normal file
@ -0,0 +1,76 @@
|
||||
//! The `time` module offers a way to get the system uptime.
|
||||
//!
|
||||
//! ### Example
|
||||
//! ```no_run
|
||||
//! let time = time::current_time();
|
||||
//! ```
|
||||
#![warn(missing_docs)]
|
||||
|
||||
/// Provides time since system start in microseconds precision
|
||||
///
|
||||
/// The counter won’t measure time in sleep-mode.
|
||||
///
|
||||
/// The timer will wrap after:
|
||||
/// - ESP32 = 36_558 years,
|
||||
/// - ESP32-S2 = 7_311 years,
|
||||
/// - others = > 7 years
|
||||
pub fn current_time() -> fugit::Instant<u64, 1, 1_000_000> {
|
||||
#[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;
|
||||
};
|
||||
let hi = tg0.lacthi().read().bits();
|
||||
|
||||
let ticks = (hi as u64) << 32u64 | lo as u64;
|
||||
(ticks, 16)
|
||||
};
|
||||
|
||||
#[cfg(not(esp32))]
|
||||
let (ticks, div) = {
|
||||
// otherwise use SYSTIMER
|
||||
let ticks = crate::systimer::SystemTimer::now();
|
||||
(
|
||||
ticks,
|
||||
(crate::systimer::SystemTimer::TICKS_PER_SECOND / 1_000_000),
|
||||
)
|
||||
};
|
||||
|
||||
fugit::Instant::<u64, 1, 1_000_000>::from_ticks(ticks / div)
|
||||
}
|
||||
|
||||
#[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)
|
||||
});
|
||||
}
|
||||
@ -53,7 +53,12 @@ fn main() -> ! {
|
||||
#[handler]
|
||||
fn tg0_t0_level() {
|
||||
critical_section::with(|cs| {
|
||||
esp_println::println!("Interrupt 1");
|
||||
esp_println::println!(
|
||||
"Interrupt at {} ms",
|
||||
esp_hal::time::current_time()
|
||||
.duration_since_epoch()
|
||||
.to_millis()
|
||||
);
|
||||
|
||||
let mut timer0 = TIMER0.borrow_ref_mut(cs);
|
||||
let timer0 = timer0.as_mut().unwrap();
|
||||
|
||||
@ -53,6 +53,10 @@ required-features = ["async", "embassy"]
|
||||
name = "ecc"
|
||||
harness = false
|
||||
|
||||
[[test]]
|
||||
name = "get_time"
|
||||
harness = false
|
||||
|
||||
[dependencies]
|
||||
cfg-if = "1.0.0"
|
||||
critical-section = "1.1.2"
|
||||
|
||||
47
hil-test/tests/get_time.rs
Normal file
47
hil-test/tests/get_time.rs
Normal file
@ -0,0 +1,47 @@
|
||||
//! current_time Test
|
||||
|
||||
//% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use defmt_rtt as _;
|
||||
use esp_backtrace as _;
|
||||
use esp_hal::{clock::ClockControl, delay::Delay, peripherals::Peripherals, system::SystemControl};
|
||||
|
||||
struct Context {
|
||||
delay: Delay,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
pub fn init() -> Self {
|
||||
let peripherals = Peripherals::take();
|
||||
let system = SystemControl::new(peripherals.SYSTEM);
|
||||
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
||||
|
||||
let delay = Delay::new(&clocks);
|
||||
|
||||
Context { delay }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[embedded_test::tests]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[init]
|
||||
fn init() -> Context {
|
||||
Context::init()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_current_time(ctx: Context) {
|
||||
let t1 = esp_hal::time::current_time();
|
||||
ctx.delay.delay_millis(500);
|
||||
let t2 = esp_hal::time::current_time();
|
||||
|
||||
assert!(t2 > t1);
|
||||
assert!((t2 - t1).to_millis() >= 500u64);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user