From e981cd496827c01cba11fd6ba40b2b7ed482e49b Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 27 Aug 2023 21:15:57 -0500 Subject: [PATCH] stm32: fix rtc wakeup timing and add dbg --- embassy-stm32/Cargo.toml | 3 ++- embassy-stm32/src/low_power.rs | 7 ++++++ embassy-stm32/src/rcc/f4.rs | 2 +- embassy-stm32/src/rtc/mod.rs | 14 ++++++++++- embassy-stm32/src/rtc/v2.rs | 43 ++++++++++++++++++++++++-------- embassy-stm32/src/time_driver.rs | 2 ++ tests/stm32/src/bin/stop.rs | 6 +++-- 7 files changed, 62 insertions(+), 15 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index d0ada97a..ca421910 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" src_base = "https://github.com/embassy-rs/embassy/blob/embassy-stm32-v$VERSION/embassy-stm32/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-stm32/src/" -features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "exti", "time-driver-any", "time", "low-power"] +features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "exti", "time-driver-any", "time", "low-power", "rtc-debug"] flavors = [ { regex_feature = "stm32f0.*", target = "thumbv6m-none-eabi" }, { regex_feature = "stm32f1.*", target = "thumbv7m-none-eabi" }, @@ -90,6 +90,7 @@ defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-emb exti = [] low-power = [ "dep:embassy-executor", "embassy-executor/arch-cortex-m" ] +rtc-debug = [] embassy-executor = [] ## Automatically generate `memory.x` file using [`stm32-metapac`](https://docs.rs/stm32-metapac/) diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 65b93f8a..f9b5fde9 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -89,6 +89,9 @@ impl Executor { self.time_driver.resume_time(); trace!("low power: resume time"); + + #[cfg(feature = "rtc-debug")] + cortex_m::asm::bkpt(); } pub(self) fn stop_with_rtc(&mut self, rtc: &'static Rtc) { @@ -118,6 +121,7 @@ impl Executor { } trace!("low power: enter stop..."); + #[cfg(not(feature = "rtc-debug"))] self.scb.set_sleepdeep(); } @@ -140,6 +144,9 @@ impl Executor { /// /// This function never returns. pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { + #[cfg(feature = "rtc-debug")] + trace!("low power: rtc debug enabled"); + init(unsafe { EXECUTOR.as_mut().unwrap() }.inner.spawner()); loop { diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs index 10d3322a..d8b689e4 100644 --- a/embassy-stm32/src/rcc/f4.rs +++ b/embassy-stm32/src/rcc/f4.rs @@ -17,7 +17,7 @@ use crate::{peripherals, Peripheral}; pub const HSI_FREQ: Hertz = Hertz(16_000_000); /// LSI speed -pub const LSI_FREQ: Hertz = Hertz(32_000); +pub const LSI_FREQ: Hertz = Hertz(32_768); /// Clocks configuration #[non_exhaustive] diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 8bda0926..496ad5c1 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -47,6 +47,18 @@ struct RtcInstant { subsecond: u16, } +#[cfg(all(feature = "low-power", feature = "defmt"))] +impl defmt::Format for RtcInstant { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!( + fmt, + "{}:{}", + self.second, + RTC::regs().prer().read().prediv_s() - self.subsecond, + ) + } +} + #[cfg(feature = "low-power")] impl core::ops::Sub for RtcInstant { type Output = embassy_time::Duration; @@ -174,7 +186,7 @@ impl Rtc { let second = bcd2_to_byte((tr.st(), tr.su())); // Unlock the registers - r.dr(); + r.dr().read(); RtcInstant { second, subsecond } } diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 62b39868..7eb8a96c 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -1,7 +1,5 @@ use stm32_metapac::rtc::vals::{Init, Osel, Pol}; -#[cfg(feature = "low-power")] -use super::RtcInstant; use super::{sealed, RtcConfig}; use crate::pac::rtc::Rtc; use crate::peripherals::RTC; @@ -77,6 +75,21 @@ impl super::Rtc { /// start the wakeup alarm and wtih a duration that is as close to but less than /// the requested duration, and record the instant the wakeup alarm was started pub(crate) fn start_wakeup_alarm(&self, requested_duration: embassy_time::Duration) { + #[cfg(feature = "rtc-debug")] + if critical_section::with(|cs| { + if let Some(instant) = self.stop_time.borrow(cs).take() { + self.stop_time.borrow(cs).replace(Some(instant)); + + Some(()) + } else { + None + } + }) + .is_some() + { + return; + } + use embassy_time::{Duration, TICK_HZ}; use crate::rcc::get_freqs; @@ -86,17 +99,14 @@ impl super::Rtc { let rtc_ticks = requested_duration.as_ticks() * rtc_hz / TICK_HZ; let prescaler = WakeupPrescaler::compute_min((rtc_ticks / u16::MAX as u64) as u32); - // adjust the rtc ticks to the prescaler + // adjust the rtc ticks to the prescaler and subtract one rtc tick let rtc_ticks = rtc_ticks / (>::into(prescaler) as u64); let rtc_ticks = if rtc_ticks >= u16::MAX as u64 { u16::MAX - 1 } else { rtc_ticks as u16 - }; - - let duration = Duration::from_ticks( - rtc_ticks as u64 * TICK_HZ * (>::into(prescaler) as u64) / rtc_hz, - ); + } + .saturating_sub(1); self.write(false, |regs| { regs.cr().modify(|w| w.set_wute(false)); @@ -104,11 +114,21 @@ impl super::Rtc { while !regs.isr().read().wutwf() {} regs.cr().modify(|w| w.set_wucksel(prescaler.into())); + regs.wutr().write(|w| w.set_wut(rtc_ticks)); regs.cr().modify(|w| w.set_wute(true)); regs.cr().modify(|w| w.set_wutie(true)); }); - trace!("rtc: start wakeup alarm for {} ms", duration.as_millis()); + trace!( + "rtc: start wakeup alarm for {} ms (psc: {}, ticks: {}) at {}", + Duration::from_ticks( + rtc_ticks as u64 * TICK_HZ * (>::into(prescaler) as u64) / rtc_hz, + ) + .as_millis(), + >::into(prescaler), + rtc_ticks, + self.instant(), + ); critical_section::with(|cs| assert!(self.stop_time.borrow(cs).replace(Some(self.instant())).is_none())) } @@ -119,7 +139,10 @@ impl super::Rtc { pub(crate) fn stop_wakeup_alarm(&self) -> Option { use crate::interrupt::typelevel::Interrupt; - trace!("rtc: stop wakeup alarm..."); + trace!("rtc: stop wakeup alarm at {}", self.instant()); + + #[cfg(feature = "rtc-debug")] + return None; self.write(false, |regs| { regs.cr().modify(|w| w.set_wutie(false)); diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 99d423d0..d4442c23 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -363,6 +363,7 @@ impl RtcDriver { .start_wakeup_alarm(time_until_next_alarm); }); + #[cfg(not(feature = "rtc-debug"))] T::regs_gp16().cr1().modify(|w| w.set_cen(false)); Ok(()) @@ -374,6 +375,7 @@ impl RtcDriver { pub(crate) fn resume_time(&self) { self.stop_wakeup_alarm(); + #[cfg(not(feature = "rtc-debug"))] T::regs_gp16().cr1().modify(|w| w.set_cen(true)); } } diff --git a/tests/stm32/src/bin/stop.rs b/tests/stm32/src/bin/stop.rs index 0b3f4a30..a490d7b8 100644 --- a/tests/stm32/src/bin/stop.rs +++ b/tests/stm32/src/bin/stop.rs @@ -46,8 +46,10 @@ async fn async_main(_spawner: Spawner) { stop_with_rtc(rtc); - info!("Waiting 5 seconds"); - Timer::after(Duration::from_secs(5)).await; + info!("Waiting..."); + Timer::after(Duration::from_secs(2)).await; + info!("Waiting..."); + Timer::after(Duration::from_secs(3)).await; info!("Test OK"); cortex_m::asm::bkpt();