stm32/rtc: autocompute prescalers

This commit is contained in:
xoviat 2023-08-29 19:41:03 -05:00
parent fdb2c4946a
commit 989c98f316
5 changed files with 41 additions and 50 deletions

View File

@ -499,6 +499,7 @@ pub(crate) unsafe fn init(config: Config) {
pllsai: None, pllsai: None,
rtc: rtc, rtc: rtc,
rtc_hse: None,
}); });
} }

View File

@ -78,8 +78,12 @@ pub struct Clocks {
pub adc: Option<Hertz>, pub adc: Option<Hertz>,
#[cfg(any(rcc_wb, rcc_f4, rcc_f410))] #[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<Hertz>, pub rtc: Option<Hertz>,
#[cfg(any(rcc_f4, rcc_f410))]
/// Set if the hse is configured, indicates stop is not supported
pub rtc_hse: Option<Hertz>,
} }
#[cfg(feature = "low-power")] #[cfg(feature = "low-power")]

View File

@ -12,6 +12,7 @@ use embassy_sync::blocking_mutex::Mutex;
pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError};
use crate::rcc::bd::BackupDomain; use crate::rcc::bd::BackupDomain;
pub use crate::rcc::RtcClockSource; pub use crate::rcc::RtcClockSource;
use crate::time::Hertz;
/// refer to AN4759 to compare features of RTC2 and RTC3 /// refer to AN4759 to compare features of RTC2 and RTC3
#[cfg_attr(any(rtc_v1), path = "v1.rs")] #[cfg_attr(any(rtc_v1), path = "v1.rs")]
@ -84,47 +85,23 @@ impl core::ops::Sub for RtcInstant {
/// RTC Abstraction /// RTC Abstraction
pub struct Rtc { pub struct Rtc {
rtc_config: RtcConfig,
#[cfg(feature = "low-power")] #[cfg(feature = "low-power")]
stop_time: Mutex<CriticalSectionRawMutex, Cell<Option<RtcInstant>>>, stop_time: Mutex<CriticalSectionRawMutex, Cell<Option<RtcInstant>>>,
} }
#[derive(Copy, Clone, PartialEq)] #[derive(Copy, Clone, PartialEq)]
pub struct RtcConfig { pub struct RtcConfig {
/// Asynchronous prescaler factor /// The subsecond counter frequency; default is 256
/// This is the asynchronous division factor: ///
/// ck_apre frequency = RTCCLK frequency/(PREDIV_A+1) /// A high counter frequency may impact stop power consumption
/// ck_apre drives the subsecond register pub frequency: Hertz,
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,
} }
impl Default for RtcConfig { impl Default for RtcConfig {
/// LSI with prescalers assuming 32.768 kHz. /// LSI with prescalers assuming 32.768 kHz.
/// Raw sub-seconds in 1/256. /// Raw sub-seconds in 1/256.
fn default() -> Self { fn default() -> Self {
RtcConfig { RtcConfig { frequency: Hertz(256) }
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
} }
} }
@ -147,23 +124,36 @@ impl Default for RtcCalibrationCyclePeriod {
impl Rtc { impl Rtc {
pub fn new(_rtc: impl Peripheral<P = RTC>, rtc_config: RtcConfig) -> Self { pub fn new(_rtc: impl Peripheral<P = RTC>, rtc_config: RtcConfig) -> Self {
use crate::rcc::get_freqs;
RTC::enable_peripheral_clk(); RTC::enable_peripheral_clk();
BackupDomain::enable_rtc();
#[cfg(not(feature = "low-power"))] let mut this = Self {
let mut rtc_struct = Self { rtc_config };
#[cfg(feature = "low-power")] #[cfg(feature = "low-power")]
let mut rtc_struct = Self {
rtc_config,
stop_time: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), 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); // Load the clock frequency from the rcc mod, if supported
rtc_struct.rtc_config = rtc_config; #[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. /// 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; pub const BACKUP_REGISTER_COUNT: usize = RTC::BACKUP_REGISTER_COUNT;
/// Read content of the backup register. /// Read content of the backup register.

View File

@ -154,7 +154,7 @@ impl super::Rtc {
/// Applies the RTC config /// Applies the RTC config
/// It this changes the RTC clock source the time will be reset /// 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| { self.write(true, |rtc| {
rtc.cr().modify(|w| { rtc.cr().modify(|w| {
#[cfg(rtc_v2f2)] #[cfg(rtc_v2f2)]
@ -166,8 +166,8 @@ impl super::Rtc {
}); });
rtc.prer().modify(|w| { rtc.prer().modify(|w| {
w.set_prediv_s(rtc_config.sync_prescaler); w.set_prediv_s(sync_psc);
w.set_prediv_a(rtc_config.async_prescaler); w.set_prediv_a(async_psc);
}); });
}); });
} }

View File

@ -8,7 +8,7 @@ use crate::rtc::sealed::Instance;
impl super::Rtc { impl super::Rtc {
/// Applies the RTC config /// Applies the RTC config
/// It this changes the RTC clock source the time will be reset /// 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| { self.write(true, |rtc| {
rtc.cr().modify(|w| { rtc.cr().modify(|w| {
w.set_fmt(Fmt::TWENTYFOURHOUR); w.set_fmt(Fmt::TWENTYFOURHOUR);
@ -17,8 +17,8 @@ impl super::Rtc {
}); });
rtc.prer().modify(|w| { rtc.prer().modify(|w| {
w.set_prediv_s(rtc_config.sync_prescaler); w.set_prediv_s(sync_psc);
w.set_prediv_a(rtc_config.async_prescaler); w.set_prediv_a(async_psc);
}); });
// TODO: configuration for output pins // TODO: configuration for output pins