From 989c98f316df3cde4512066e3682debb47d48161 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 29 Aug 2023 19:41:03 -0500 Subject: [PATCH] stm32/rtc: autocompute prescalers --- embassy-stm32/src/rcc/f4.rs | 1 + embassy-stm32/src/rcc/mod.rs | 6 ++- embassy-stm32/src/rtc/mod.rs | 72 +++++++++++++++--------------------- embassy-stm32/src/rtc/v2.rs | 6 +-- embassy-stm32/src/rtc/v3.rs | 6 +-- 5 files changed, 41 insertions(+), 50 deletions(-) diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs index 10d3322aa..c2c78a45e 100644 --- a/embassy-stm32/src/rcc/f4.rs +++ b/embassy-stm32/src/rcc/f4.rs @@ -499,6 +499,7 @@ pub(crate) unsafe fn init(config: Config) { pllsai: None, rtc: rtc, + rtc_hse: None, }); } diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 9f1b3b663..1ead60b18 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -78,8 +78,12 @@ pub struct Clocks { pub adc: Option, #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] - /// Set only if the lsi or lse is configured + /// Set only if the lsi or lse is configured, indicates stop is supported pub rtc: Option, + + #[cfg(any(rcc_f4, rcc_f410))] + /// Set if the hse is configured, indicates stop is not supported + pub rtc_hse: Option, } #[cfg(feature = "low-power")] diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 796fd7d96..3704e4464 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -12,6 +12,7 @@ use embassy_sync::blocking_mutex::Mutex; pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; use crate::rcc::bd::BackupDomain; pub use crate::rcc::RtcClockSource; +use crate::time::Hertz; /// refer to AN4759 to compare features of RTC2 and RTC3 #[cfg_attr(any(rtc_v1), path = "v1.rs")] @@ -84,47 +85,23 @@ impl core::ops::Sub for RtcInstant { /// RTC Abstraction pub struct Rtc { - rtc_config: RtcConfig, #[cfg(feature = "low-power")] stop_time: Mutex>>, } #[derive(Copy, Clone, PartialEq)] pub struct RtcConfig { - /// Asynchronous prescaler factor - /// This is the asynchronous division factor: - /// ck_apre frequency = RTCCLK frequency/(PREDIV_A+1) - /// ck_apre drives the subsecond register - async_prescaler: u8, - /// Synchronous prescaler factor - /// This is the synchronous division factor: - /// ck_spre frequency = ck_apre frequency/(PREDIV_S+1) - /// ck_spre must be 1Hz - sync_prescaler: u16, + /// The subsecond counter frequency; default is 256 + /// + /// A high counter frequency may impact stop power consumption + pub frequency: Hertz, } impl Default for RtcConfig { /// LSI with prescalers assuming 32.768 kHz. /// Raw sub-seconds in 1/256. fn default() -> Self { - RtcConfig { - async_prescaler: 127, - sync_prescaler: 255, - } - } -} - -impl RtcConfig { - /// Set the asynchronous prescaler of RTC config - pub fn async_prescaler(mut self, prescaler: u8) -> Self { - self.async_prescaler = prescaler; - self - } - - /// Set the synchronous prescaler of RTC config - pub fn sync_prescaler(mut self, prescaler: u16) -> Self { - self.sync_prescaler = prescaler; - self + RtcConfig { frequency: Hertz(256) } } } @@ -147,23 +124,36 @@ impl Default for RtcCalibrationCyclePeriod { impl Rtc { pub fn new(_rtc: impl Peripheral

, rtc_config: RtcConfig) -> Self { + use crate::rcc::get_freqs; + RTC::enable_peripheral_clk(); + BackupDomain::enable_rtc(); - #[cfg(not(feature = "low-power"))] - let mut rtc_struct = Self { rtc_config }; - - #[cfg(feature = "low-power")] - let mut rtc_struct = Self { - rtc_config, + let mut this = Self { + #[cfg(feature = "low-power")] stop_time: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), }; - BackupDomain::enable_rtc(); + #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] + let freqs = unsafe { get_freqs() }; - rtc_struct.configure(rtc_config); - rtc_struct.rtc_config = rtc_config; + // Load the clock frequency from the rcc mod, if supported + #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] + let frequency = match freqs.rtc { + Some(hertz) => hertz, + None => freqs.rtc_hse.unwrap(), + }; - rtc_struct + // Assume the default value, if not supported + #[cfg(not(any(rcc_wb, rcc_f4, rcc_f410)))] + let frequency = Hertz(32_768); + + let async_psc = ((frequency.0 / rtc_config.frequency.0) - 1) as u8; + let sync_psc = (rtc_config.frequency.0 - 1) as u16; + + this.configure(async_psc, sync_psc); + + this } /// Set the datetime to a new value. @@ -228,10 +218,6 @@ impl Rtc { }) } - pub fn get_config(&self) -> RtcConfig { - self.rtc_config - } - pub const BACKUP_REGISTER_COUNT: usize = RTC::BACKUP_REGISTER_COUNT; /// Read content of the backup register. diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 49f66e957..63d9f09e7 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -154,7 +154,7 @@ impl super::Rtc { /// Applies the RTC config /// It this changes the RTC clock source the time will be reset - pub(super) fn configure(&mut self, rtc_config: RtcConfig) { + pub(super) fn configure(&mut self, async_psc: u8, sync_psc: u16) { self.write(true, |rtc| { rtc.cr().modify(|w| { #[cfg(rtc_v2f2)] @@ -166,8 +166,8 @@ impl super::Rtc { }); rtc.prer().modify(|w| { - w.set_prediv_s(rtc_config.sync_prescaler); - w.set_prediv_a(rtc_config.async_prescaler); + w.set_prediv_s(sync_psc); + w.set_prediv_a(async_psc); }); }); } diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs index 12952b15a..c03b1071d 100644 --- a/embassy-stm32/src/rtc/v3.rs +++ b/embassy-stm32/src/rtc/v3.rs @@ -8,7 +8,7 @@ use crate::rtc::sealed::Instance; impl super::Rtc { /// Applies the RTC config /// It this changes the RTC clock source the time will be reset - pub(super) fn configure(&mut self, rtc_config: RtcConfig) { + pub(super) fn configure(&mut self, async_psc: u8, sync_psc: u16) { self.write(true, |rtc| { rtc.cr().modify(|w| { w.set_fmt(Fmt::TWENTYFOURHOUR); @@ -17,8 +17,8 @@ impl super::Rtc { }); rtc.prer().modify(|w| { - w.set_prediv_s(rtc_config.sync_prescaler); - w.set_prediv_a(rtc_config.async_prescaler); + w.set_prediv_s(sync_psc); + w.set_prediv_a(async_psc); }); // TODO: configuration for output pins