1use stm32_metapac::rtc::vals::{Calp, Calw16, Calw8, Fmt, Key, Osel, Pol, TampalrmType};
2
3use super::RtcCalibrationCyclePeriod;
4use crate::pac::rtc::Rtc;
5use crate::peripherals::RTC;
6use crate::rtc::SealedInstance;
7
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 w.set_bypshad(true);
15 w.set_fmt(Fmt::TWENTY_FOUR_HOUR);
16 w.set_osel(Osel::DISABLED);
17 w.set_pol(Pol::HIGH);
18 });
19
20 rtc.prer().modify(|w| {
21 w.set_prediv_s(sync_psc);
22 w.set_prediv_a(async_psc);
23 });
24
25 // TODO: configuration for output pins
26 rtc.cr().modify(|w| {
27 w.set_out2en(false);
28 w.set_tampalrm_type(TampalrmType::PUSH_PULL);
29 w.set_tampalrm_pu(false);
30 });
31 });
32 }
33
34 const RTC_CALR_MIN_PPM: f32 = -487.1;
35 const RTC_CALR_MAX_PPM: f32 = 488.5;
36 const RTC_CALR_RESOLUTION_PPM: f32 = 0.9537;
37
38 /// Calibrate the clock drift.
39 ///
40 /// `clock_drift` can be adjusted from -487.1 ppm to 488.5 ppm and is clamped to this range.
41 ///
42 /// ### Note
43 ///
44 /// To perform a calibration when `async_prescaler` is less then 3, `sync_prescaler`
45 /// has to be reduced accordingly (see RM0351 Rev 9, sec 38.3.12).
46 pub fn calibrate(&mut self, mut clock_drift: f32, period: RtcCalibrationCyclePeriod) {
47 if clock_drift < Self::RTC_CALR_MIN_PPM {
48 clock_drift = Self::RTC_CALR_MIN_PPM;
49 } else if clock_drift > Self::RTC_CALR_MAX_PPM {
50 clock_drift = Self::RTC_CALR_MAX_PPM;
51 }
52
53 clock_drift /= Self::RTC_CALR_RESOLUTION_PPM;
54
55 self.write(false, |rtc| {
56 rtc.calr().write(|w| {
57 match period {
58 RtcCalibrationCyclePeriod::Seconds8 => {
59 w.set_calw8(Calw8::EIGHT_SECONDS);
60 }
61 RtcCalibrationCyclePeriod::Seconds16 => {
62 w.set_calw16(Calw16::SIXTEEN_SECONDS);
63 }
64 RtcCalibrationCyclePeriod::Seconds32 => {
65 // Set neither `calw8` nor `calw16` to use 32 seconds
66 }
67 }
68
69 // Extra pulses during calibration cycle period: CALP * 512 - CALM
70 //
71 // CALP sets whether pulses are added or omitted.
72 //
73 // CALM contains how many pulses (out of 512) are masked in a
74 // given calibration cycle period.
75 if clock_drift > 0.0 {
76 // Maximum (about 512.2) rounds to 512.
77 clock_drift += 0.5;
78
79 // When the offset is positive (0 to 512), the opposite of
80 // the offset (512 - offset) is masked, i.e. for the
81 // maximum offset (512), 0 pulses are masked.
82 w.set_calp(Calp::INCREASE_FREQ);
83 w.set_calm(512 - clock_drift as u16);
84 } else {
85 // Minimum (about -510.7) rounds to -511.
86 clock_drift -= 0.5;
87
88 // When the offset is negative or zero (-511 to 0),
89 // the absolute offset is masked, i.e. for the minimum
90 // offset (-511), 511 pulses are masked.
91 w.set_calp(Calp::NO_CHANGE);
92 w.set_calm((clock_drift * -1.0) as u16);
93 }
94 });
95 })
96 }
97
98 pub(super) fn write<F, R>(&self, init_mode: bool, f: F) -> R
99 where
100 F: FnOnce(crate::pac::rtc::Rtc) -> R,
101 {
102 let r = RTC::regs();
103 // Disable write protection.
104 // This is safe, as we're only writin the correct and expected values.
105 r.wpr().write(|w| w.set_key(Key::DEACTIVATE1));
106 r.wpr().write(|w| w.set_key(Key::DEACTIVATE2));
107
108 if init_mode && !r.icsr().read().initf() {
109 r.icsr().modify(|w| w.set_init(true));
110 // wait till init state entered
111 // ~2 RTCCLK cycles
112 while !r.icsr().read().initf() {}
113 }
114
115 let result = f(r);
116
117 if init_mode {
118 r.icsr().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(Key::ACTIVATE));
124
125 result
126 }
127}
128
129impl SealedInstance for crate::peripherals::RTC {
130 const BACKUP_REGISTER_COUNT: usize = 32;
131
132 #[cfg(feature = "low-power")]
133 cfg_if::cfg_if!(
134 if #[cfg(stm32g4)] {
135 const EXTI_WAKEUP_LINE: usize = 20;
136 } else if #[cfg(stm32g0)] {
137 const EXTI_WAKEUP_LINE: usize = 19;
138 } else if #[cfg(any(stm32l5, stm32h5))] {
139 const EXTI_WAKEUP_LINE: usize = 17;
140 }
141 );
142
143 #[cfg(feature = "low-power")]
144 cfg_if::cfg_if!(
145 if #[cfg(stm32g4)] {
146 type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP;
147 } else if #[cfg(any(stm32g0, stm32u0))] {
148 type WakeupInterrupt = crate::interrupt::typelevel::RTC_TAMP;
149 } else if #[cfg(any(stm32l5, stm32h5, stm32u5))] {
150 type WakeupInterrupt = crate::interrupt::typelevel::RTC;
151 }
152 );
153
154 fn read_backup_register(_rtc: Rtc, register: usize) -> Option<u32> {
155 #[allow(clippy::if_same_then_else)]
156 if register < Self::BACKUP_REGISTER_COUNT {
157 //Some(rtc.bkpr()[register].read().bits())
158 None // RTC3 backup registers come from the TAMP peripheral, not RTC. Not() even in the L412 PAC
159 } else {
160 None
161 }
162 }
163
164 fn write_backup_register(_rtc: Rtc, register: usize, _value: u32) {
165 if register < Self::BACKUP_REGISTER_COUNT {
166 // RTC3 backup registers come from the TAMP peripheral, not RTC. Not() even in the L412 PAC
167 //self.rtc.bkpr()[register].write(|w| w.bits(value))
168 }
169 }
170}
171