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