//! RTC peripheral abstraction use core::marker::PhantomData; mod datetime; pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; /// refer to AN4759 to compare features of RTC2 and RTC3 #[cfg_attr(any(rtc_v1), path = "v1.rs")] #[cfg_attr( any( rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb ), path = "v2.rs" )] #[cfg_attr(any(rtc_v3, rtc_v3u5), path = "v3.rs")] mod _version; pub use _version::*; use embassy_hal_internal::Peripheral; /// Errors that can occur on methods on [RtcClock] #[derive(Clone, Debug, PartialEq, Eq)] pub enum RtcError { /// An invalid DateTime was given or stored on the hardware. InvalidDateTime(DateTimeError), /// The RTC clock is not running NotRunning, } /// RTC Abstraction pub struct Rtc<'d, T: Instance> { phantom: PhantomData<&'d mut T>, rtc_config: RtcConfig, } pub(crate) fn enable_rtc(clock_source: RtcClockSource) { // TODO: rewrite the RTC module so that enable is separated from configure assert!(clock_source == RtcClockSource::LSI || clock_source == RtcClockSource::LSE); let _ = Rtc::new( unsafe { crate::Peripherals::steal().RTC }, RtcConfig { clock_config: clock_source, async_prescaler: 1, sync_prescaler: 1, }, ); } #[derive(Copy, Clone, Debug, PartialEq)] #[repr(u8)] pub enum RtcClockSource { /// 00: No clock NoClock = 0b00, /// 01: LSE oscillator clock used as RTC clock LSE = 0b01, /// 10: LSI oscillator clock used as RTC clock LSI = 0b10, /// 11: HSE oscillator clock divided by 32 used as RTC clock HSE = 0b11, } #[derive(Copy, Clone, PartialEq)] pub struct RtcConfig { /// RTC clock source clock_config: RtcClockSource, /// 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, } impl Default for RtcConfig { /// LSI with prescalers assuming 32.768 kHz. /// Raw sub-seconds in 1/256. fn default() -> Self { RtcConfig { clock_config: RtcClockSource::LSI, async_prescaler: 127, sync_prescaler: 255, } } } impl RtcConfig { /// Sets the clock source of RTC config pub fn clock_config(mut self, cfg: RtcClockSource) -> Self { self.clock_config = cfg; self } /// 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 } } #[derive(Copy, Clone, Debug, PartialEq)] #[repr(u8)] pub enum RtcCalibrationCyclePeriod { /// 8-second calibration period Seconds8, /// 16-second calibration period Seconds16, /// 32-second calibration period Seconds32, } impl Default for RtcCalibrationCyclePeriod { fn default() -> Self { RtcCalibrationCyclePeriod::Seconds32 } } impl<'d, T: Instance> Rtc<'d, T> { pub fn new(_rtc: impl Peripheral
+ 'd, rtc_config: RtcConfig) -> Self {
T::enable_peripheral_clk();
let mut rtc_struct = Self {
phantom: PhantomData,
rtc_config,
};
rtc_struct.apply_config(rtc_config);
rtc_struct
}
/// Set the datetime to a new value.
///
/// # Errors
///
/// Will return `RtcError::InvalidDateTime` if the datetime is not a valid range.
pub fn set_datetime(&mut self, t: DateTime) -> Result<(), RtcError> {
self::datetime::validate_datetime(&t).map_err(RtcError::InvalidDateTime)?;
self.write(true, |rtc| self::datetime::write_date_time(rtc, t));
Ok(())
}
/// Return the current datetime.
///
/// # Errors
///
/// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`].
pub fn now(&self) -> Result