Fix C2 delays (#1981)

* Re-enable delay tests on S2 and C2

* Systimer: use fn instead of constant to retrieve tick freq

* Reformulate delay using current_time

* Take actual XTAL into account

* Re-enable tests

* Fix changelog

* Disable defmt

* Remove unused esp32 code

* Update esp-hal/src/delay.rs

Co-authored-by: Jesse Braham <jessebraham@users.noreply.github.com>

---------

Co-authored-by: Jesse Braham <jessebraham@users.noreply.github.com>
This commit is contained in:
Dániel Buga 2024-08-21 19:33:46 +02:00 committed by GitHub
parent 69cf454a5a
commit f829c8f2ac
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 119 additions and 110 deletions

View File

@ -287,6 +287,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Auto detect crystal frequency based on `RtcClock::estimate_xtal_frequency()` (#1165) - Auto detect crystal frequency based on `RtcClock::estimate_xtal_frequency()` (#1165)
- ESP32-S3: Configure 32k ICACHE (#1169) - ESP32-S3: Configure 32k ICACHE (#1169)
- Lift the minimal buffer size requirement for I2S (#1189) - Lift the minimal buffer size requirement for I2S (#1189)
- Replaced `SystemTimer::TICKS_PER_SEC` with `SystemTimer::ticks_per_sec()` (#1981)
### Removed ### Removed

View File

@ -71,6 +71,8 @@
//! ``` //! ```
use fugit::HertzU32; use fugit::HertzU32;
#[cfg(esp32c2)]
use portable_atomic::{AtomicU32, Ordering};
#[cfg(any(esp32, esp32c2))] #[cfg(any(esp32, esp32c2))]
use crate::rtc_cntl::RtcClock; use crate::rtc_cntl::RtcClock;
@ -333,6 +335,26 @@ pub struct RawClocks {
pub pll_96m_clock: HertzU32, pub pll_96m_clock: HertzU32,
} }
cfg_if::cfg_if! {
if #[cfg(esp32c2)] {
static XTAL_FREQ_MHZ: AtomicU32 = AtomicU32::new(40);
pub(crate) fn xtal_freq_mhz() -> u32 {
XTAL_FREQ_MHZ.load(Ordering::Relaxed)
}
} else if #[cfg(esp32h2)] {
pub(crate) fn xtal_freq_mhz() -> u32 {
32
}
} else if #[cfg(any(esp32, esp32s2))] {
// Function would be unused
} else {
pub(crate) fn xtal_freq_mhz() -> u32 {
40
}
}
}
/// Used to configure the frequencies of the clocks present in the chip. /// Used to configure the frequencies of the clocks present in the chip.
/// ///
/// After setting all frequencies, call the freeze function to apply the /// After setting all frequencies, call the freeze function to apply the
@ -429,6 +451,7 @@ impl<'d> ClockControl<'d> {
} else { } else {
26 26
}; };
XTAL_FREQ_MHZ.store(xtal_freq, Ordering::Relaxed);
ClockControl { ClockControl {
_private: clock_control.into_ref(), _private: clock_control.into_ref(),
@ -452,6 +475,7 @@ impl<'d> ClockControl<'d> {
} else { } else {
XtalClock::RtcXtalFreq26M XtalClock::RtcXtalFreq26M
}; };
XTAL_FREQ_MHZ.store(xtal_freq.mhz(), Ordering::Relaxed);
let pll_freq = PllClock::Pll480MHz; let pll_freq = PllClock::Pll480MHz;

View File

@ -30,26 +30,17 @@
//! [DelayUs]: embedded_hal_02::blocking::delay::DelayUs //! [DelayUs]: embedded_hal_02::blocking::delay::DelayUs
//! [embedded-hal]: https://docs.rs/embedded-hal/1.0.0/embedded_hal/delay/index.html //! [embedded-hal]: https://docs.rs/embedded-hal/1.0.0/embedded_hal/delay/index.html
use fugit::HertzU64;
pub use fugit::MicrosDurationU64; pub use fugit::MicrosDurationU64;
use crate::clock::Clocks;
/// Delay driver /// Delay driver
/// ///
/// Uses the `SYSTIMER` peripheral internally for RISC-V devices, and the /// Uses the `SYSTIMER` peripheral internally for RISC-V devices, and the
/// built-in Xtensa timer for Xtensa devices. /// built-in Xtensa timer for Xtensa devices.
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct Delay { #[non_exhaustive]
freq: HertzU64, pub struct Delay;
}
impl Delay {
/// Delay for the specified number of milliseconds
pub fn delay_millis(&self, ms: u32) {
for _ in 0..ms {
self.delay_micros(1000);
}
}
}
#[cfg(feature = "embedded-hal-02")] #[cfg(feature = "embedded-hal-02")]
impl<T> embedded_hal_02::blocking::delay::DelayMs<T> for Delay impl<T> embedded_hal_02::blocking::delay::DelayMs<T> for Delay
@ -57,9 +48,7 @@ where
T: Into<u32>, T: Into<u32>,
{ {
fn delay_ms(&mut self, ms: T) { fn delay_ms(&mut self, ms: T) {
for _ in 0..ms.into() { self.delay_millis(ms.into());
self.delay_micros(1000);
}
} }
} }
@ -80,83 +69,48 @@ impl embedded_hal::delay::DelayNs for Delay {
} }
} }
#[cfg(riscv)]
mod implementation {
use super::*;
use crate::{clock::Clocks, timer::systimer::SystemTimer};
impl Delay { impl Delay {
/// Create a new `Delay` instance /// Creates a new `Delay` instance.
pub fn new(clocks: &Clocks<'_>) -> Self { // Do not remove the argument, it makes sure that the clocks are initialized.
// The counters and comparators are driven using `XTAL_CLK`. pub fn new(_clocks: &Clocks<'_>) -> Self {
// The average clock frequency is fXTAL_CLK/2.5, which is 16 MHz. Self {}
// The timer counting is incremented by 1/16 μs on each `CNT_CLK` cycle.
Self {
#[cfg(not(esp32h2))]
freq: HertzU64::MHz(clocks.xtal_clock.to_MHz() as u64 * 10 / 25),
#[cfg(esp32h2)]
// esp32h2 TRM, section 11.2 Clock Source Selection
freq: HertzU64::MHz(clocks.xtal_clock.to_MHz() as u64 * 10 / 20),
}
} }
/// Delay for the specified time /// Delay for the specified time
pub fn delay(&self, time: MicrosDurationU64) { pub fn delay(&self, delay: MicrosDurationU64) {
let t0 = SystemTimer::now(); let start = crate::time::current_time();
let rate: HertzU64 = MicrosDurationU64::from_ticks(1).into_rate();
let clocks = time.ticks() * (self.freq / rate);
while SystemTimer::now().wrapping_sub(t0) & SystemTimer::BIT_MASK <= clocks {} while elapsed_since(start) < delay {}
}
/// Delay for the specified number of milliseconds
pub fn delay_millis(&self, ms: u32) {
for _ in 0..ms {
self.delay_micros(1000);
}
} }
/// Delay for the specified number of microseconds /// Delay for the specified number of microseconds
pub fn delay_micros(&self, us: u32) { pub fn delay_micros(&self, us: u32) {
let t0 = SystemTimer::now(); let delay = MicrosDurationU64::micros(us as u64);
let clocks = us as u64 * (self.freq / HertzU64::MHz(1)); self.delay(delay);
while SystemTimer::now().wrapping_sub(t0) & SystemTimer::BIT_MASK <= clocks {}
} }
/// Delay for the specified number of nanoseconds /// Delay for the specified number of nanoseconds
pub fn delay_nanos(&self, ns: u32) { pub fn delay_nanos(&self, ns: u32) {
let t0 = SystemTimer::now(); let delay = MicrosDurationU64::nanos(ns as u64);
let clocks = ns as u64 * (self.freq / HertzU64::MHz(1)) / 1000; self.delay(delay);
while SystemTimer::now().wrapping_sub(t0) & SystemTimer::BIT_MASK <= clocks {}
}
}
}
#[cfg(xtensa)]
mod implementation {
use super::*;
use crate::clock::Clocks;
impl Delay {
/// Create a new `Delay` instance
pub fn new(clocks: &Clocks<'_>) -> Self {
Self {
freq: clocks.cpu_clock.into(),
} }
} }
/// Delay for the specified time fn elapsed_since(start: fugit::Instant<u64, 1, 1_000_000>) -> MicrosDurationU64 {
pub fn delay(&self, time: MicrosDurationU64) { let now = crate::time::current_time();
let rate: HertzU64 = MicrosDurationU64::from_ticks(1).into_rate();
let clocks = time.ticks() * (self.freq / rate);
xtensa_lx::timer::delay(clocks as u32);
}
/// Delay for the specified number of microseconds if start.ticks() <= now.ticks() {
pub fn delay_micros(&self, us: u32) { now - start
let clocks = us as u64 * (self.freq / HertzU64::MHz(1)); } else {
xtensa_lx::timer::delay(clocks as u32); // current_time specifies at least 7 happy years, let's ignore this issue for
} // now.
panic!("Time has wrapped around, which we currently don't handle");
/// Delay for the specified number of nanoseconds
pub fn delay_nanos(&self, ns: u32) {
let clocks = ns as u64 * (self.freq / HertzU64::MHz(1)) / 1000;
xtensa_lx::timer::delay(clocks as u32);
}
} }
} }

View File

@ -50,7 +50,7 @@ pub fn current_time() -> fugit::Instant<u64, 1, 1_000_000> {
let ticks = crate::timer::systimer::SystemTimer::now(); let ticks = crate::timer::systimer::SystemTimer::now();
( (
ticks, ticks,
(crate::timer::systimer::SystemTimer::TICKS_PER_SECOND / 1_000_000), (crate::timer::systimer::SystemTimer::ticks_per_second() / 1_000_000),
) )
}; };

View File

@ -112,20 +112,37 @@ impl<'d> SystemTimer<'d> {
if #[cfg(esp32s2)] { if #[cfg(esp32s2)] {
/// Bitmask to be applied to the raw register value. /// Bitmask to be applied to the raw register value.
pub const BIT_MASK: u64 = u64::MAX; pub const BIT_MASK: u64 = u64::MAX;
/// The ticks per second the underlying peripheral uses.
pub const TICKS_PER_SECOND: u64 = 80_000_000;
// Bitmask to be applied to the raw period register value. // Bitmask to be applied to the raw period register value.
const PERIOD_MASK: u64 = 0x1FFF_FFFF; const PERIOD_MASK: u64 = 0x1FFF_FFFF;
} else { } else {
/// Bitmask to be applied to the raw register value. /// Bitmask to be applied to the raw register value.
pub const BIT_MASK: u64 = 0xF_FFFF_FFFF_FFFF; pub const BIT_MASK: u64 = 0xF_FFFF_FFFF_FFFF;
/// The ticks per second the underlying peripheral uses.
pub const TICKS_PER_SECOND: u64 = 16_000_000;
// Bitmask to be applied to the raw period register value. // Bitmask to be applied to the raw period register value.
const PERIOD_MASK: u64 = 0x3FF_FFFF; const PERIOD_MASK: u64 = 0x3FF_FFFF;
} }
} }
/// Returns the tick frequency of the underlying timer unit.
pub fn ticks_per_second() -> u64 {
cfg_if::cfg_if! {
if #[cfg(esp32s2)] {
80_000_000
} else if #[cfg(esp32h2)] {
// The counters and comparators are driven using `XTAL_CLK`.
// The average clock frequency is fXTAL_CLK/2, which is 16 MHz.
// The timer counting is incremented by 1/16 μs on each `CNT_CLK` cycle.
const MULTIPLIER: u64 = 10_000_000 / 20;
crate::clock::xtal_freq_mhz() as u64 * MULTIPLIER
} else {
// The counters and comparators are driven using `XTAL_CLK`.
// The average clock frequency is fXTAL_CLK/2.5, which is 16 MHz.
// The timer counting is incremented by 1/16 μs on each `CNT_CLK` cycle.
const MULTIPLIER: u64 = 10_000_000 / 25;
crate::clock::xtal_freq_mhz() as u64 * MULTIPLIER
}
}
}
/// Create a new instance. /// Create a new instance.
pub fn new(_systimer: impl Peripheral<P = SYSTIMER> + 'd) -> Self { pub fn new(_systimer: impl Peripheral<P = SYSTIMER> + 'd) -> Self {
#[cfg(soc_etm)] #[cfg(soc_etm)]
@ -810,7 +827,7 @@ where
} }
let us = period.ticks(); let us = period.ticks();
let ticks = us * (SystemTimer::TICKS_PER_SECOND / 1_000_000) as u32; let ticks = us * (SystemTimer::ticks_per_second() / 1_000_000) as u32;
self.comparator.set_mode(ComparatorMode::Period); self.comparator.set_mode(ComparatorMode::Period);
self.comparator.set_period(ticks); self.comparator.set_period(ticks);
@ -879,7 +896,7 @@ where
} }
}; };
let us = ticks / (SystemTimer::TICKS_PER_SECOND / 1_000_000); let us = ticks / (SystemTimer::ticks_per_second() / 1_000_000);
Instant::<u64, 1, 1_000_000>::from_ticks(us) Instant::<u64, 1, 1_000_000>::from_ticks(us)
} }
@ -888,7 +905,7 @@ where
let mode = self.comparator.get_mode(); let mode = self.comparator.get_mode();
let us = value.ticks(); let us = value.ticks();
let ticks = us * (SystemTimer::TICKS_PER_SECOND / 1_000_000); let ticks = us * (SystemTimer::ticks_per_second() / 1_000_000);
if matches!(mode, ComparatorMode::Period) { if matches!(mode, ComparatorMode::Period) {
// Period mode // Period mode

View File

@ -74,11 +74,11 @@ fn main() -> ! {
alarm0.enable_interrupt(true); alarm0.enable_interrupt(true);
alarm1.set_interrupt_handler(systimer_target1); alarm1.set_interrupt_handler(systimer_target1);
alarm1.set_target(SystemTimer::now() + (SystemTimer::TICKS_PER_SECOND * 2)); alarm1.set_target(SystemTimer::now() + (SystemTimer::ticks_per_second() * 2));
alarm1.enable_interrupt(true); alarm1.enable_interrupt(true);
alarm2.set_interrupt_handler(systimer_target2); alarm2.set_interrupt_handler(systimer_target2);
alarm2.set_target(SystemTimer::now() + (SystemTimer::TICKS_PER_SECOND * 3)); alarm2.set_target(SystemTimer::now() + (SystemTimer::ticks_per_second() * 3));
alarm2.enable_interrupt(true); alarm2.enable_interrupt(true);
ALARM0.borrow_ref_mut(cs).replace(alarm0); ALARM0.borrow_ref_mut(cs).replace(alarm0);

View File

@ -1,7 +1,6 @@
//! Delay Test //! Delay Test
// esp32c2 is disabled currently as it fails //% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32s2 esp32s3
//% CHIPS: esp32 esp32c3 esp32c6 esp32s3
#![no_std] #![no_std]
#![no_main] #![no_main]
@ -37,25 +36,33 @@ mod tests {
} }
#[test] #[test]
#[timeout(1)] #[timeout(2)]
fn delay_ns(mut ctx: Context) { fn delay_ns(mut ctx: Context) {
let t1 = esp_hal::time::current_time(); let t1 = esp_hal::time::current_time();
ctx.delay.delay_ns(600_000_000); ctx.delay.delay_ns(600_000_000);
let t2 = esp_hal::time::current_time(); let t2 = esp_hal::time::current_time();
assert!(t2 > t1); assert!(t2 > t1);
assert!((t2 - t1).to_nanos() >= 600_000_000u64); assert!(
(t2 - t1).to_nanos() >= 600_000_000u64,
"diff: {:?}",
(t2 - t1).to_nanos()
);
} }
#[test] #[test]
#[timeout(1)] #[timeout(2)]
fn delay_700millis(ctx: Context) { fn delay_700millis(ctx: Context) {
let t1 = esp_hal::time::current_time(); let t1 = esp_hal::time::current_time();
ctx.delay.delay_millis(700); ctx.delay.delay_millis(700);
let t2 = esp_hal::time::current_time(); let t2 = esp_hal::time::current_time();
assert!(t2 > t1); assert!(t2 > t1);
assert!((t2 - t1).to_millis() >= 700u64); assert!(
(t2 - t1).to_millis() >= 700u64,
"diff: {:?}",
(t2 - t1).to_millis()
);
} }
#[test] #[test]
@ -66,7 +73,11 @@ mod tests {
let t2 = esp_hal::time::current_time(); let t2 = esp_hal::time::current_time();
assert!(t2 > t1); assert!(t2 > t1);
assert!((t2 - t1).to_micros() >= 1_500_000u64); assert!(
(t2 - t1).to_micros() >= 1_500_000u64,
"diff: {:?}",
(t2 - t1).to_micros()
);
} }
#[test] #[test]
@ -77,6 +88,10 @@ mod tests {
let t2 = esp_hal::time::current_time(); let t2 = esp_hal::time::current_time();
assert!(t2 > t1); assert!(t2 > t1);
assert!((t2 - t1).to_millis() >= 3000u64); assert!(
(t2 - t1).to_millis() >= 3000u64,
"diff: {:?}",
(t2 - t1).to_millis()
);
} }
} }

View File

@ -1,7 +1,6 @@
//! Embassy timer and executor Test //! Embassy timer and executor Test
// esp32c2 is disabled currently as it fails //% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
//% CHIPS: esp32 esp32c3 esp32c6 esp32h2 esp32s3
#![no_std] #![no_std]
#![no_main] #![no_main]

View File

@ -1,7 +1,6 @@
//! current_time Test //! current_time Test
// esp32c2 is disabled currently as it fails //% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
//% CHIPS: esp32 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
#![no_std] #![no_std]
#![no_main] #![no_main]

View File

@ -137,7 +137,7 @@ mod tests {
critical_section::with(|cs| { critical_section::with(|cs| {
alarm0.set_interrupt_handler(pass_test_if_called); alarm0.set_interrupt_handler(pass_test_if_called);
alarm0.set_target(SystemTimer::now() + SystemTimer::TICKS_PER_SECOND / 10); alarm0.set_target(SystemTimer::now() + SystemTimer::ticks_per_second() / 10);
alarm0.enable_interrupt(true); alarm0.enable_interrupt(true);
ALARM_TARGET.borrow_ref_mut(cs).replace(alarm0); ALARM_TARGET.borrow_ref_mut(cs).replace(alarm0);
@ -157,7 +157,7 @@ mod tests {
critical_section::with(|cs| { critical_section::with(|cs| {
alarm0.set_interrupt_handler(target_fail_test_if_called_twice); alarm0.set_interrupt_handler(target_fail_test_if_called_twice);
alarm0.set_target(SystemTimer::now() + SystemTimer::TICKS_PER_SECOND / 10); alarm0.set_target(SystemTimer::now() + SystemTimer::ticks_per_second() / 10);
alarm0.enable_interrupt(true); alarm0.enable_interrupt(true);
let alarm1 = alarm1.into_periodic(); let alarm1 = alarm1.into_periodic();