stm32f4xx_hal/
rtc.rs

1//! Interface to the real time clock. See STM32F303 reference manual, section 27.
2//! For more details, see
3//! [ST AN4759](https:/www.st.com%2Fresource%2Fen%2Fapplication_note%2Fdm00226326-using-the-hardware-realtime-clock-rtc-and-the-tamper-management-unit-tamp-with-stm32-microcontrollers-stmicroelectronics.pdf&usg=AOvVaw3PzvL2TfYtwS32fw-Uv37h)
4
5use crate::bb;
6use crate::pac::rtc::{dr, tr};
7use crate::pac::{self, PWR, RCC, RTC};
8use crate::rcc::Enable;
9use core::fmt;
10use fugit::RateExtU32;
11use time::{Date, PrimitiveDateTime, Time, Weekday};
12
13/// Invalid input error
14#[cfg_attr(feature = "defmt", derive(defmt::Format))]
15#[derive(Debug, Eq, PartialEq, Copy, Clone)]
16pub enum Error {
17    InvalidInputData,
18}
19
20#[cfg_attr(feature = "defmt", derive(defmt::Format))]
21#[derive(Debug, Eq, PartialEq, Copy, Clone)]
22pub enum Event {
23    AlarmA,
24    AlarmB,
25    Wakeup,
26    Timestamp,
27}
28
29#[cfg_attr(feature = "defmt", derive(defmt::Format))]
30#[derive(Debug, Eq, PartialEq, Copy, Clone)]
31pub enum Alarm {
32    AlarmA = 0,
33    AlarmB = 1,
34}
35
36impl From<Alarm> for Event {
37    fn from(a: Alarm) -> Self {
38        match a {
39            Alarm::AlarmA => Event::AlarmA,
40            Alarm::AlarmB => Event::AlarmB,
41        }
42    }
43}
44
45#[derive(Debug, Eq, PartialEq, Copy, Clone)]
46pub enum AlarmDay {
47    Date(Date),
48    Weekday(Weekday),
49    EveryDay,
50}
51
52impl From<Date> for AlarmDay {
53    fn from(date: Date) -> Self {
54        Self::Date(date)
55    }
56}
57
58impl From<Weekday> for AlarmDay {
59    fn from(day: Weekday) -> Self {
60        Self::Weekday(day)
61    }
62}
63
64/// RTC clock source LSE oscillator clock (type state)
65pub struct Lse;
66/// RTC clock source LSI oscillator clock (type state)
67pub struct Lsi;
68
69#[cfg_attr(feature = "defmt", derive(defmt::Format))]
70#[derive(Clone, Copy, Debug, PartialEq, Eq)]
71pub enum ClockSource {
72    Lse(LSEClockMode),
73    Lsi,
74}
75
76impl From<LSEClockMode> for ClockSource {
77    fn from(value: LSEClockMode) -> Self {
78        Self::Lse(value)
79    }
80}
81
82impl ClockSource {
83    pub fn frequency(self) -> fugit::Hertz<u32> {
84        match self {
85            Self::Lse(_) => 32_768_u32.Hz(),
86            Self::Lsi => 32.kHz(),
87        }
88    }
89}
90
91/// Real Time Clock peripheral
92pub struct Rtc {
93    /// RTC Peripheral register
94    pub regs: RTC,
95    clock_source: ClockSource,
96}
97
98#[cfg(feature = "defmt")]
99impl defmt::Format for Rtc {
100    fn format(&self, f: defmt::Formatter) {
101        defmt::write!(f, "Rtc");
102    }
103}
104
105impl fmt::Debug for Rtc {
106    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107        f.write_str("Rtc")
108    }
109}
110
111/// LSE clock mode.
112#[cfg_attr(feature = "defmt", derive(defmt::Format))]
113#[derive(Clone, Copy, Debug, PartialEq, Eq)]
114pub enum LSEClockMode {
115    /// Enable LSE oscillator to use external crystal or ceramic resonator.
116    Oscillator,
117    /// Bypass LSE oscillator to use external clock source.
118    /// Use this if an external oscillator is used which is not connected to `OSC32_IN` such as a MEMS resonator.
119    Bypass,
120}
121
122impl Rtc {
123    /// Create and enable a new RTC with external crystal or ceramic resonator and default prescalers.
124    pub fn new(regs: RTC, rcc: &mut RCC, pwr: &mut PWR) -> Self {
125        Self::with_config(regs, rcc, pwr, LSEClockMode::Oscillator, 255, 127)
126    }
127    /// Create and enable a new RTC, and configure its clock source and prescalers.
128    ///
129    /// From AN3371, Table 3,
130    /// set `prediv_s` to 255 (249 for LSI), and `prediv_a` to 127 to get a calendar clock of 1Hz.
131    pub fn with_config(
132        regs: RTC,
133        rcc: &mut RCC,
134        pwr: &mut PWR,
135        clock_source: impl Into<ClockSource>,
136        prediv_s: u16,
137        prediv_a: u8,
138    ) -> Self {
139        let mut result = Self {
140            regs,
141            clock_source: clock_source.into(),
142        };
143
144        // Steps:
145        // Enable PWR and DBP
146        // Enable LSE/LSI (if needed)
147        // Enable RTC Clock
148        // Disable Write Protect
149        // Enter Init
150        // Configure 24 hour format
151        // Set prescalers
152        // Exit Init
153        // Enable write protect
154
155        // As per the sample code, unlock comes first. (Enable PWR and DBP)
156        result.unlock(rcc, pwr);
157        match result.clock_source {
158            ClockSource::Lse(mode) => {
159                // If necessary, enable the LSE.
160                if rcc.bdcr().read().lserdy().bit_is_clear() {
161                    result.enable_lse(rcc, mode);
162                }
163                // Set clock source to LSE.
164                rcc.bdcr().modify(|_, w| w.rtcsel().lse());
165            }
166            ClockSource::Lsi => {
167                // If necessary, enable the LSE.
168                if rcc.csr().read().lsirdy().bit_is_clear() {
169                    result.enable_lsi(rcc);
170                }
171                // Set clock source to LSI.
172                rcc.bdcr().modify(|_, w| w.rtcsel().lsi());
173            }
174        }
175        result.enable(rcc);
176
177        result.modify(true, |regs| {
178            // Set 24 Hour
179            regs.cr().modify(|_, w| w.fmt().clear_bit());
180            // Set prescalers
181            regs.prer().modify(|_, w| {
182                w.prediv_s().set(prediv_s);
183                w.prediv_a().set(prediv_a)
184            });
185        });
186
187        result
188    }
189
190    /// Enable the low frequency external oscillator. This is the only mode currently
191    /// supported, to avoid exposing the `CR` and `CRS` registers.
192    fn enable_lse(&mut self, rcc: &mut RCC, mode: LSEClockMode) {
193        unsafe {
194            // Force a reset of the backup domain.
195            self.backup_reset(rcc);
196            // Enable the LSE.
197            // Set BDCR - Bit 0 (LSEON)
198            bb::set(rcc.bdcr(), 0);
199            match mode {
200                // Set BDCR - Bit 2 (LSEBYP)
201                LSEClockMode::Bypass => bb::set(rcc.bdcr(), 2),
202                // Clear BDCR - Bit 2 (LSEBYP)
203                LSEClockMode::Oscillator => bb::clear(rcc.bdcr(), 2),
204            }
205            while rcc.bdcr().read().lserdy().bit_is_clear() {}
206        }
207    }
208
209    /// Create and enable a new RTC with internal crystal and default prescalers.
210    pub fn new_lsi(regs: RTC, rcc: &mut RCC, pwr: &mut PWR) -> Self {
211        Self::with_config(regs, rcc, pwr, ClockSource::Lsi, 249, 127)
212    }
213
214    /// Create and enable a new RTC, and configure its clock source and prescalers.
215    ///
216    /// From AN3371, Table 3, when using the LSI,
217    /// set `prediv_s` to 249, and `prediv_a` to 127 to get a calendar clock of 1Hz.
218    pub fn lsi_with_config(
219        regs: RTC,
220        rcc: &mut RCC,
221        pwr: &mut PWR,
222        prediv_s: u16,
223        prediv_a: u8,
224    ) -> Self {
225        Self::with_config(regs, rcc, pwr, ClockSource::Lsi, prediv_s, prediv_a)
226    }
227
228    fn enable_lsi(&mut self, rcc: &mut RCC) {
229        // Force a reset of the backup domain.
230        self.backup_reset(rcc);
231        // Enable the LSI.
232        rcc.csr().modify(|_, w| w.lsion().on());
233        while rcc.csr().read().lsirdy().is_not_ready() {}
234    }
235
236    fn unlock(&mut self, rcc: &mut RCC, pwr: &mut PWR) {
237        // Enable the backup interface
238        // Set APB1 - Bit 28 (PWREN)
239        PWR::enable(rcc);
240
241        // Enable access to the backup registers
242        pwr.cr().modify(|_, w| w.dbp().set_bit());
243    }
244
245    fn backup_reset(&mut self, rcc: &mut RCC) {
246        unsafe {
247            // Set BDCR - Bit 16 (BDRST)
248            bb::set(rcc.bdcr(), 16);
249            // Clear BDCR - Bit 16 (BDRST)
250            bb::clear(rcc.bdcr(), 16);
251        }
252    }
253
254    fn enable(&mut self, rcc: &mut RCC) {
255        // Start the actual RTC.
256        // Set BDCR - Bit 15 (RTCEN)
257        unsafe {
258            bb::set(rcc.bdcr(), 15);
259        }
260    }
261
262    pub fn set_prescalers(&mut self, prediv_s: u16, prediv_a: u8) {
263        self.modify(true, |regs| {
264            // Set prescalers
265            regs.prer().modify(|_, w| {
266                w.prediv_s().set(prediv_s);
267                w.prediv_a().set(prediv_a)
268            });
269        });
270    }
271
272    /// As described in Section 27.3.7 in RM0316,
273    /// this function is used to disable write protection
274    /// when modifying an RTC register
275    fn modify<F>(&mut self, init_mode: bool, mut closure: F)
276    where
277        F: FnMut(&mut RTC),
278    {
279        // Disable write protection
280        // This is safe, as we're only writin the correct and expected values.
281        self.regs.wpr().write(|w| unsafe { w.bits(0xCA) });
282        self.regs.wpr().write(|w| unsafe { w.bits(0x53) });
283        // Enter init mode
284        if init_mode && self.regs.isr().read().initf().bit_is_clear() {
285            self.regs.isr().modify(|_, w| w.init().set_bit());
286            // wait till init state entered
287            // ~2 RTCCLK cycles
288            while self.regs.isr().read().initf().bit_is_clear() {}
289        }
290        // Invoke closure
291        closure(&mut self.regs);
292        // Exit init mode
293        if init_mode {
294            self.regs.isr().modify(|_, w| w.init().clear_bit());
295        }
296        // wait for last write to be done
297        while !self.regs.isr().read().initf().bit_is_clear() {}
298
299        // Re-enable write protection.
300        // This is safe, as the field accepts the full range of 8-bit values.
301        self.regs.wpr().write(|w| unsafe { w.bits(0xFF) });
302    }
303
304    /// Set the time using time::Time.
305    pub fn set_time(&mut self, time: &Time) -> Result<(), Error> {
306        let (ht, hu) = bcd2_encode(time.hour().into())?;
307        let (mnt, mnu) = bcd2_encode(time.minute().into())?;
308        let (st, su) = bcd2_encode(time.second().into())?;
309        self.modify(true, |regs| {
310            regs.tr().write(|w| {
311                w.ht().set(ht);
312                w.hu().set(hu);
313                w.mnt().set(mnt);
314                w.mnu().set(mnu);
315                w.st().set(st);
316                w.su().set(su);
317                w.pm().clear_bit()
318            });
319        });
320
321        Ok(())
322    }
323
324    /// Set the seconds [0-59].
325    pub fn set_seconds(&mut self, seconds: u8) -> Result<(), Error> {
326        if seconds > 59 {
327            return Err(Error::InvalidInputData);
328        }
329        let (st, su) = bcd2_encode(seconds.into())?;
330        self.modify(true, |regs| {
331            regs.tr().modify(|_, w| w.st().set(st).su().set(su));
332        });
333
334        Ok(())
335    }
336
337    /// Set the minutes [0-59].
338    pub fn set_minutes(&mut self, minutes: u8) -> Result<(), Error> {
339        if minutes > 59 {
340            return Err(Error::InvalidInputData);
341        }
342        let (mnt, mnu) = bcd2_encode(minutes.into())?;
343        self.modify(true, |regs| {
344            regs.tr().modify(|_, w| w.mnt().set(mnt).mnu().set(mnu));
345        });
346
347        Ok(())
348    }
349
350    /// Set the hours [0-23].
351    pub fn set_hours(&mut self, hours: u8) -> Result<(), Error> {
352        if hours > 23 {
353            return Err(Error::InvalidInputData);
354        }
355        let (ht, hu) = bcd2_encode(hours.into())?;
356
357        self.modify(true, |regs| {
358            regs.tr().modify(|_, w| w.ht().set(ht).hu().set(hu));
359        });
360
361        Ok(())
362    }
363
364    /// Set the day of week [1-7].
365    pub fn set_weekday(&mut self, weekday: u8) -> Result<(), Error> {
366        if !(1..=7).contains(&weekday) {
367            return Err(Error::InvalidInputData);
368        }
369        self.modify(true, |regs| {
370            regs.dr().modify(|_, w| unsafe { w.wdu().bits(weekday) });
371        });
372
373        Ok(())
374    }
375
376    /// Set the day of month [1-31].
377    pub fn set_day(&mut self, day: u8) -> Result<(), Error> {
378        if !(1..=31).contains(&day) {
379            return Err(Error::InvalidInputData);
380        }
381        let (dt, du) = bcd2_encode(day as u32)?;
382        self.modify(true, |regs| {
383            regs.dr().modify(|_, w| w.dt().set(dt).du().set(du));
384        });
385
386        Ok(())
387    }
388
389    /// Set the month [1-12].
390    pub fn set_month(&mut self, month: u8) -> Result<(), Error> {
391        if !(1..=12).contains(&month) {
392            return Err(Error::InvalidInputData);
393        }
394        let (mt, mu) = bcd2_encode(month as u32)?;
395        self.modify(true, |regs| {
396            regs.dr().modify(|_, w| w.mt().bit(mt > 0).mu().set(mu));
397        });
398
399        Ok(())
400    }
401
402    /// Set the year [1970-2069].
403    ///
404    /// The year cannot be less than 1970, since the Unix epoch is assumed (1970-01-01 00:00:00).
405    /// Also, the year cannot be greater than 2069 since the RTC range is 0 - 99.
406    pub fn set_year(&mut self, year: u16) -> Result<(), Error> {
407        if !(1970..=2069).contains(&year) {
408            return Err(Error::InvalidInputData);
409        }
410        let (yt, yu) = bcd2_encode(year as u32 - 1970)?;
411        self.modify(true, |regs| {
412            regs.dr().modify(|_, w| w.yt().set(yt).yu().set(yu));
413        });
414
415        Ok(())
416    }
417
418    /// Set the date.
419    ///
420    /// The year cannot be less than 1970, since the Unix epoch is assumed (1970-01-01 00:00:00).
421    /// Also, the year cannot be greater than 2069 since the RTC range is 0 - 99.
422    pub fn set_date(&mut self, date: &Date) -> Result<(), Error> {
423        if !(1970..=2069).contains(&date.year()) {
424            return Err(Error::InvalidInputData);
425        }
426
427        let (yt, yu) = bcd2_encode((date.year() - 1970) as u32)?;
428        let (mt, mu) = bcd2_encode(u8::from(date.month()).into())?;
429        let (dt, du) = bcd2_encode(date.day().into())?;
430        let wdu = date.weekday().number_from_monday();
431
432        self.modify(true, |regs| {
433            regs.dr().write(|w| {
434                w.dt().set(dt);
435                w.du().set(du);
436                w.mt().bit(mt > 0);
437                w.mu().set(mu);
438                w.yt().set(yt);
439                w.yu().set(yu);
440                unsafe { w.wdu().bits(wdu) }
441            });
442        });
443
444        Ok(())
445    }
446
447    /// Set the date and time.
448    ///
449    /// The year cannot be less than 1970, since the Unix epoch is assumed (1970-01-01 00:00:00).
450    /// Also, the year cannot be greater than 2069 since the RTC range is 0 - 99.
451    pub fn set_datetime(&mut self, date: &PrimitiveDateTime) -> Result<(), Error> {
452        if !(1970..=2069).contains(&date.year()) {
453            return Err(Error::InvalidInputData);
454        }
455
456        let (yt, yu) = bcd2_encode((date.year() - 1970) as u32)?;
457        let (mt, mu) = bcd2_encode(u8::from(date.month()).into())?;
458        let (dt, du) = bcd2_encode(date.day().into())?;
459        let wdu = date.weekday().number_from_monday();
460
461        let (ht, hu) = bcd2_encode(date.hour().into())?;
462        let (mnt, mnu) = bcd2_encode(date.minute().into())?;
463        let (st, su) = bcd2_encode(date.second().into())?;
464
465        self.modify(true, |regs| {
466            regs.dr().write(|w| {
467                w.dt().set(dt);
468                w.du().set(du);
469                w.mt().bit(mt > 0);
470                w.mu().set(mu);
471                w.yt().set(yt);
472                w.yu().set(yu);
473                unsafe { w.wdu().bits(wdu) }
474            });
475            regs.tr().write(|w| {
476                w.ht().set(ht);
477                w.hu().set(hu);
478                w.mnt().set(mnt);
479                w.mnu().set(mnu);
480                w.st().set(st);
481                w.su().set(su);
482                w.pm().clear_bit()
483            });
484        });
485
486        Ok(())
487    }
488
489    pub fn get_datetime(&mut self) -> PrimitiveDateTime {
490        // Wait for Registers synchronization flag,  to ensure consistency between the RTC_SSR, RTC_TR and RTC_DR shadow registers.
491        while self.regs.isr().read().rsf().bit_is_clear() {}
492
493        // Reading either RTC_SSR or RTC_TR locks the values in the higher-order calendar shadow registers until RTC_DR is read.
494        // So it is important to always read SSR, TR and then DR or TR and then DR.
495        let ss = self.regs.ssr().read().ss().bits();
496        let tr = self.regs.tr().read();
497        let dr = self.regs.dr().read();
498        // In case the software makes read accesses to the calendar in a time interval smaller
499        // than 2 RTCCLK periods: RSF must be cleared by software after the first calendar read.
500        self.regs.isr().modify(|_, w| w.rsf().clear_bit());
501
502        let seconds = decode_seconds(&tr);
503        let minutes = decode_minutes(&tr);
504        let hours = decode_hours(&tr);
505        let day = decode_day(&dr);
506        let month = decode_month(&dr);
507        let year = decode_year(&dr);
508        let prediv_s = self.regs.prer().read().prediv_s().bits();
509        let nano = ss_to_nano(ss, prediv_s);
510
511        PrimitiveDateTime::new(
512            Date::from_calendar_date(year.into(), month.try_into().unwrap(), day).unwrap(),
513            Time::from_hms_nano(hours, minutes, seconds, nano).unwrap(),
514        )
515    }
516
517    /// Configures the wakeup timer to trigger periodically every `interval` duration
518    ///
519    /// # Panics
520    ///
521    /// Panics if interval is greater than 2¹⁷-1 seconds.
522    pub fn enable_wakeup(&mut self, interval: fugit::MicrosDurationU64) {
523        let clock_source = self.clock_source;
524        self.modify(false, |regs| {
525            regs.cr().modify(|_, w| w.wute().clear_bit());
526            regs.isr().modify(|_, w| w.wutf().clear_bit());
527            while regs.isr().read().wutwf().bit_is_clear() {}
528
529            use crate::pac::rtc::cr::WUCKSEL;
530            if interval < fugit::MicrosDurationU64::secs(32) {
531                // Use RTCCLK as the wakeup timer clock source
532                let frequency: fugit::Hertz<u64> = (clock_source.frequency() / 2).into();
533                let freq_duration: fugit::MicrosDurationU64 = frequency.into_duration();
534                let ticks_per_interval = interval / freq_duration;
535
536                let mut prescaler = 0;
537                while ticks_per_interval >> prescaler > 1 << 16 {
538                    prescaler += 1;
539                }
540
541                let wucksel = match prescaler {
542                    0 => WUCKSEL::Div2,
543                    1 => WUCKSEL::Div4,
544                    2 => WUCKSEL::Div8,
545                    3 => WUCKSEL::Div16,
546                    _ => unreachable!("Longer durations should use ck_spre"),
547                };
548
549                let interval = u16::try_from((ticks_per_interval >> prescaler) - 1).unwrap();
550
551                regs.cr().modify(|_, w| w.wucksel().variant(wucksel));
552                regs.wutr().write(|w| w.wut().set(interval));
553            } else {
554                // Use ck_spre (1Hz) as the wakeup timer clock source
555                let interval = interval.to_secs();
556                if interval > 1 << 16 {
557                    regs.cr()
558                        .modify(|_, w| w.wucksel().variant(WUCKSEL::ClockSpareWithOffset));
559                    let interval = u16::try_from(interval - (1 << 16) - 1)
560                        .expect("Interval was too large for wakeup timer");
561                    regs.wutr().write(|w| w.wut().set(interval));
562                } else {
563                    regs.cr()
564                        .modify(|_, w| w.wucksel().variant(WUCKSEL::ClockSpare));
565                    let interval = u16::try_from(interval - 1)
566                        .expect("Interval was too large for wakeup timer");
567                    regs.wutr().write(|w| w.wut().set(interval));
568                }
569            }
570
571            regs.cr().modify(|_, w| w.wute().set_bit());
572        });
573    }
574
575    /// Disables the wakeup timer
576    pub fn disable_wakeup(&mut self) {
577        self.modify(false, |regs| {
578            regs.cr().modify(|_, w| w.wute().clear_bit());
579            regs.isr().modify(|_, w| w.wutf().clear_bit());
580        });
581    }
582
583    /// Configures the timestamp to be captured when the RTC switches to Vbat power
584    pub fn enable_vbat_timestamp(&mut self) {
585        self.modify(false, |regs| {
586            regs.cr().modify(|_, w| w.tse().clear_bit());
587            regs.isr().modify(|_, w| w.tsf().clear_bit());
588            regs.cr().modify(|_, w| w.tse().set_bit());
589        });
590    }
591
592    /// Disables the timestamp
593    pub fn disable_timestamp(&mut self) {
594        self.modify(false, |regs| {
595            regs.cr().modify(|_, w| w.tse().clear_bit());
596            regs.isr().modify(|_, w| w.tsf().clear_bit());
597        });
598    }
599
600    /// Reads the stored value of the timestamp if present
601    ///
602    /// Clears the timestamp interrupt flags.
603    pub fn read_timestamp(&self) -> PrimitiveDateTime {
604        while self.regs.isr().read().rsf().bit_is_clear() {}
605
606        // Timestamp doesn't include year, get it from the main calendar
607        let ss = self.regs.tsssr().read().ss().bits();
608
609        // TODO: remove unsafe after PAC update
610        let tr = self.regs.tstr().read();
611        let dr = self.regs.tsdr().read();
612        let dry = self.regs.dr().read();
613        let seconds = decode_seconds(&tr);
614        let minutes = decode_minutes(&tr);
615        let hours = decode_hours(&tr);
616        let day = decode_day(&dr);
617        let month = decode_month(&dr);
618        let year = decode_year(&dry);
619        let prediv_s = self.regs.prer().read().prediv_s().bits();
620        let nano = ss_to_nano(ss, prediv_s);
621
622        PrimitiveDateTime::new(
623            Date::from_calendar_date(year.into(), month.try_into().unwrap(), day).unwrap(),
624            Time::from_hms_nano(hours, minutes, seconds, nano).unwrap(),
625        )
626    }
627
628    /// Sets the time at which an alarm will be triggered
629    /// This also clears the alarm flag if it is set
630    pub fn set_alarm(
631        &mut self,
632        alarm: Alarm,
633        date: impl Into<AlarmDay>,
634        time: Time,
635    ) -> Result<(), Error> {
636        let date = date.into();
637        let (daymask, wdsel, (dt, du)) = match date {
638            AlarmDay::Date(date) => (false, false, bcd2_encode(date.day().into())?),
639            AlarmDay::Weekday(weekday) => (false, true, (0, weekday.number_days_from_monday())),
640            AlarmDay::EveryDay => (true, false, (0, 0)),
641        };
642        let (ht, hu) = bcd2_encode(time.hour().into())?;
643        let (mnt, mnu) = bcd2_encode(time.minute().into())?;
644        let (st, su) = bcd2_encode(time.second().into())?;
645
646        self.modify(false, |rtc| {
647            unsafe {
648                bb::clear(rtc.cr(), 8 + (alarm as u8));
649                bb::clear(rtc.isr(), 8 + (alarm as u8));
650            }
651            while rtc.isr().read().bits() & (1 << (alarm as u32)) == 0 {}
652            let reg = rtc.alrmr(alarm as usize);
653            reg.modify(|_, w| {
654                w.dt().set(dt);
655                w.du().set(du);
656                w.ht().set(ht);
657                w.hu().set(hu);
658                w.mnt().set(mnt);
659                w.mnu().set(mnu);
660                w.st().set(st);
661                w.su().set(su);
662                w.pm().clear_bit();
663                w.wdsel().bit(wdsel);
664                w.msk4().bit(daymask)
665            });
666            // subsecond alarm not implemented
667            // would need a conversion method between `time.micros` and RTC ticks
668            // write the SS value and mask to `rtc.alrmssr[alarm]`
669
670            // enable alarm and reenable interrupt if it was enabled
671            unsafe {
672                bb::set(rtc.cr(), 8 + (alarm as u8));
673            }
674        });
675        Ok(())
676    }
677
678    /// Start listening for `event`
679    pub fn listen(&mut self, exti: &mut pac::EXTI, event: Event) {
680        // Input Mapping:
681        // EXTI 17 = RTC Alarms
682        // EXTI 21 = RTC Tamper, RTC Timestamp
683        // EXTI 22 = RTC Wakeup Timer
684        self.modify(false, |regs| match event {
685            Event::AlarmA => {
686                exti.rtsr().modify(|_, w| w.tr17().enabled());
687                exti.imr().modify(|_, w| w.mr17().set_bit());
688                regs.cr().modify(|_, w| w.alraie().set_bit());
689            }
690            Event::AlarmB => {
691                exti.rtsr().modify(|_, w| w.tr17().enabled());
692                exti.imr().modify(|_, w| w.mr17().set_bit());
693                regs.cr().modify(|_, w| w.alrbie().set_bit());
694            }
695            Event::Wakeup => {
696                exti.rtsr().modify(|_, w| w.tr22().enabled());
697                exti.imr().modify(|_, w| w.mr22().set_bit());
698                regs.cr().modify(|_, w| w.wutie().set_bit());
699            }
700            Event::Timestamp => {
701                exti.rtsr().modify(|_, w| w.tr21().enabled());
702                exti.imr().modify(|_, w| w.mr21().set_bit());
703                regs.cr().modify(|_, w| w.tsie().set_bit());
704            }
705        });
706    }
707
708    /// Stop listening for `event`
709    pub fn unlisten(&mut self, exti: &mut pac::EXTI, event: Event) {
710        // See the note in listen() about EXTI
711        self.modify(false, |regs| match event {
712            Event::AlarmA => {
713                regs.cr().modify(|_, w| w.alraie().clear_bit());
714                exti.imr().modify(|_, w| w.mr17().clear_bit());
715                exti.rtsr().modify(|_, w| w.tr17().disabled());
716            }
717            Event::AlarmB => {
718                regs.cr().modify(|_, w| w.alrbie().clear_bit());
719                exti.imr().modify(|_, w| w.mr17().clear_bit());
720                exti.rtsr().modify(|_, w| w.tr17().disabled());
721            }
722            Event::Wakeup => {
723                regs.cr().modify(|_, w| w.wutie().clear_bit());
724                exti.imr().modify(|_, w| w.mr22().clear_bit());
725                exti.rtsr().modify(|_, w| w.tr22().disabled());
726            }
727            Event::Timestamp => {
728                regs.cr().modify(|_, w| w.tsie().clear_bit());
729                exti.imr().modify(|_, w| w.mr21().clear_bit());
730                exti.rtsr().modify(|_, w| w.tr21().disabled());
731            }
732        });
733    }
734
735    /// Returns `true` if `event` is pending
736    pub fn is_pending(&self, event: Event) -> bool {
737        match event {
738            Event::AlarmA => self.regs.isr().read().alraf().bit_is_set(),
739            Event::AlarmB => self.regs.isr().read().alrbf().bit_is_set(),
740            Event::Wakeup => self.regs.isr().read().wutf().bit_is_set(),
741            Event::Timestamp => self.regs.isr().read().tsf().bit_is_set(),
742        }
743    }
744
745    /// Clears the interrupt flag for `event`
746    pub fn clear_interrupt(&mut self, event: Event) {
747        match event {
748            Event::AlarmA => {
749                self.regs.isr().modify(|_, w| w.alraf().clear_bit());
750                unsafe {
751                    (*pac::EXTI::ptr())
752                        .pr()
753                        .write(|w| w.pr17().clear_bit_by_one())
754                };
755            }
756            Event::AlarmB => {
757                self.regs.isr().modify(|_, w| w.alrbf().clear_bit());
758                unsafe {
759                    (*pac::EXTI::ptr())
760                        .pr()
761                        .write(|w| w.pr17().clear_bit_by_one())
762                };
763            }
764            Event::Wakeup => {
765                self.regs.isr().modify(|_, w| w.wutf().clear_bit());
766                unsafe {
767                    (*pac::EXTI::ptr())
768                        .pr()
769                        .write(|w| w.pr22().clear_bit_by_one())
770                };
771            }
772            Event::Timestamp => {
773                self.regs.isr().modify(|_, w| w.tsf().clear_bit());
774                unsafe {
775                    (*pac::EXTI::ptr())
776                        .pr()
777                        .write(|w| w.pr21().clear_bit_by_one())
778                };
779            }
780        }
781    }
782}
783
784// Two 32-bit registers (RTC_TR and RTC_DR) contain the seconds, minutes, hours (12- or 24-hour format), day (day
785// of week), date (day of month), month, and year, expressed in binary coded decimal format
786// (BCD). The sub-seconds value is also available in binary format.
787//
788// The following helper functions encode into BCD format from integer and
789// decode to an integer from a BCD value respectively.
790fn bcd2_encode(word: u32) -> Result<(u8, u8), Error> {
791    let l = match (word / 10).try_into() {
792        Ok(v) => v,
793        Err(_) => {
794            return Err(Error::InvalidInputData);
795        }
796    };
797    let r = match (word % 10).try_into() {
798        Ok(v) => v,
799        Err(_) => {
800            return Err(Error::InvalidInputData);
801        }
802    };
803
804    Ok((l, r))
805}
806
807const fn bcd2_decode(fst: u8, snd: u8) -> u8 {
808    fst * 10 + snd
809}
810
811#[inline(always)]
812fn decode_seconds(tr: &tr::R) -> u8 {
813    bcd2_decode(tr.st().bits(), tr.su().bits())
814}
815
816#[inline(always)]
817fn decode_minutes(tr: &tr::R) -> u8 {
818    bcd2_decode(tr.mnt().bits(), tr.mnu().bits())
819}
820
821#[inline(always)]
822fn decode_hours(tr: &tr::R) -> u8 {
823    bcd2_decode(tr.ht().bits(), tr.hu().bits())
824}
825
826#[inline(always)]
827fn decode_day(dr: &dr::R) -> u8 {
828    bcd2_decode(dr.dt().bits(), dr.du().bits())
829}
830
831#[inline(always)]
832fn decode_month(dr: &dr::R) -> u8 {
833    let mt = u8::from(dr.mt().bit());
834    bcd2_decode(mt, dr.mu().bits())
835}
836
837#[inline(always)]
838fn decode_year(dr: &dr::R) -> u16 {
839    let year = (bcd2_decode(dr.yt().bits(), dr.yu().bits()) as u32) + 1970; // 1970-01-01 is the epoch begin.
840    year as u16
841}
842
843const fn ss_to_nano(ss: u16, prediv_s: u16) -> u32 {
844    let ss = ss as u32;
845    let prediv_s = prediv_s as u32;
846    assert!(ss <= prediv_s);
847
848    (((prediv_s - ss) * 100_000) / (prediv_s + 1)) * 10_000
849}