embassy_stm32/rtc/
v2.rs

1use stm32_metapac::rtc::vals::{Osel, Pol};
2
3use super::SealedInstance;
4use crate::pac::rtc::Rtc;
5use crate::peripherals::RTC;
6
7#[allow(dead_code)]
8impl super::Rtc {
9    /// Applies the RTC config
10    /// It this changes the RTC clock source the time will be reset
11    pub(super) fn configure(&mut self, async_psc: u8, sync_psc: u16) {
12        self.write(true, |rtc| {
13            rtc.cr().modify(|w| {
14                #[cfg(not(rtc_v2f2))]
15                w.set_bypshad(true);
16                #[cfg(rtc_v2f2)]
17                w.set_fmt(false);
18                #[cfg(not(rtc_v2f2))]
19                w.set_fmt(stm32_metapac::rtc::vals::Fmt::TWENTY_FOUR_HOUR);
20                w.set_osel(Osel::DISABLED);
21                w.set_pol(Pol::HIGH);
22            });
23
24            rtc.prer().modify(|w| {
25                w.set_prediv_s(sync_psc);
26                w.set_prediv_a(async_psc);
27            });
28        });
29    }
30
31    /// Calibrate the clock drift.
32    ///
33    /// `clock_drift` can be adjusted from -487.1 ppm to 488.5 ppm and is clamped to this range.
34    ///
35    /// ### Note
36    ///
37    /// To perform a calibration when `async_prescaler` is less then 3, `sync_prescaler`
38    /// has to be reduced accordingly (see RM0351 Rev 9, sec 38.3.12).
39    #[cfg(not(rtc_v2f2))]
40    pub fn calibrate(&mut self, mut clock_drift: f32, period: super::RtcCalibrationCyclePeriod) {
41        const RTC_CALR_MIN_PPM: f32 = -487.1;
42        const RTC_CALR_MAX_PPM: f32 = 488.5;
43        const RTC_CALR_RESOLUTION_PPM: f32 = 0.9537;
44
45        if clock_drift < RTC_CALR_MIN_PPM {
46            clock_drift = RTC_CALR_MIN_PPM;
47        } else if clock_drift > RTC_CALR_MAX_PPM {
48            clock_drift = RTC_CALR_MAX_PPM;
49        }
50
51        clock_drift /= RTC_CALR_RESOLUTION_PPM;
52
53        self.write(false, |rtc| {
54            rtc.calr().write(|w| {
55                match period {
56                    super::RtcCalibrationCyclePeriod::Seconds8 => {
57                        w.set_calw8(stm32_metapac::rtc::vals::Calw8::EIGHT_SECOND);
58                    }
59                    super::RtcCalibrationCyclePeriod::Seconds16 => {
60                        w.set_calw16(stm32_metapac::rtc::vals::Calw16::SIXTEEN_SECOND);
61                    }
62                    super::RtcCalibrationCyclePeriod::Seconds32 => {
63                        // Set neither `calw8` nor `calw16` to use 32 seconds
64                    }
65                }
66
67                // Extra pulses during calibration cycle period: CALP * 512 - CALM
68                //
69                // CALP sets whether pulses are added or omitted.
70                //
71                // CALM contains how many pulses (out of 512) are masked in a
72                // given calibration cycle period.
73                if clock_drift > 0.0 {
74                    // Maximum (about 512.2) rounds to 512.
75                    clock_drift += 0.5;
76
77                    // When the offset is positive (0 to 512), the opposite of
78                    // the offset (512 - offset) is masked, i.e. for the
79                    // maximum offset (512), 0 pulses are masked.
80                    w.set_calp(stm32_metapac::rtc::vals::Calp::INCREASE_FREQ);
81                    w.set_calm(512 - clock_drift as u16);
82                } else {
83                    // Minimum (about -510.7) rounds to -511.
84                    clock_drift -= 0.5;
85
86                    // When the offset is negative or zero (-511 to 0),
87                    // the absolute offset is masked, i.e. for the minimum
88                    // offset (-511), 511 pulses are masked.
89                    w.set_calp(stm32_metapac::rtc::vals::Calp::NO_CHANGE);
90                    w.set_calm((clock_drift * -1.0) as u16);
91                }
92            });
93        })
94    }
95
96    pub(super) fn write<F, R>(&self, init_mode: bool, f: F) -> R
97    where
98        F: FnOnce(crate::pac::rtc::Rtc) -> R,
99    {
100        let r = RTC::regs();
101        // Disable write protection.
102        // This is safe, as we're only writin the correct and expected values.
103        r.wpr().write(|w| w.set_key(0xca));
104        r.wpr().write(|w| w.set_key(0x53));
105
106        // true if initf bit indicates RTC peripheral is in init mode
107        if init_mode && !r.isr().read().initf() {
108            // to update calendar date/time, time format, and prescaler configuration, RTC must be in init mode
109            r.isr().modify(|w| w.set_init(true));
110            // wait till init state entered
111            // ~2 RTCCLK cycles
112            while !r.isr().read().initf() {}
113        }
114
115        let result = f(r);
116
117        if init_mode {
118            r.isr().modify(|w| w.set_init(false)); // Exits init mode
119        }
120
121        // Re-enable write protection.
122        // This is safe, as the field accepts the full range of 8-bit values.
123        r.wpr().write(|w| w.set_key(0xff));
124        result
125    }
126}
127
128impl SealedInstance for crate::peripherals::RTC {
129    const BACKUP_REGISTER_COUNT: usize = 20;
130
131    #[cfg(all(feature = "low-power", stm32f4))]
132    const EXTI_WAKEUP_LINE: usize = 22;
133
134    #[cfg(all(feature = "low-power", stm32l4))]
135    const EXTI_WAKEUP_LINE: usize = 20;
136
137    #[cfg(all(feature = "low-power", stm32l0))]
138    const EXTI_WAKEUP_LINE: usize = 20;
139
140    #[cfg(all(feature = "low-power", any(stm32f4, stm32l4)))]
141    type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP;
142
143    #[cfg(all(feature = "low-power", stm32l0))]
144    type WakeupInterrupt = crate::interrupt::typelevel::RTC;
145
146    fn read_backup_register(rtc: Rtc, register: usize) -> Option<u32> {
147        if register < Self::BACKUP_REGISTER_COUNT {
148            Some(rtc.bkpr(register).read().bkp())
149        } else {
150            None
151        }
152    }
153
154    fn write_backup_register(rtc: Rtc, register: usize, value: u32) {
155        if register < Self::BACKUP_REGISTER_COUNT {
156            rtc.bkpr(register).write(|w| w.set_bkp(value));
157        }
158    }
159}