stm32g0xx_hal/
rtc.rs

1//! Real Time Clock
2use crate::gpio::*;
3use crate::rcc::{RTCSrc, Rcc};
4use crate::stm32::RTC;
5use crate::time::*;
6
7#[derive(Debug, PartialEq, Eq)]
8pub enum RtcHourFormat {
9    H24,
10    H12,
11}
12
13#[derive(Debug, PartialEq, Eq)]
14pub enum RtcCalibrationFrequency {
15    F1Hz,
16    F512Hz,
17}
18
19pub enum Event {
20    WakeupTimer,
21    AlarmA,
22    AlarmB,
23    Timestamp,
24}
25
26#[derive(Debug, Default, PartialEq, Eq)]
27pub struct Alarm {
28    day: Option<u32>,
29    hours: Option<u32>,
30    minutes: Option<u32>,
31    seconds: Option<u32>,
32    subseconds: u16,
33    subseconds_mask_bits: u8,
34    use_weekday: bool,
35}
36
37impl Alarm {
38    pub fn new() -> Self {
39        Self::default()
40    }
41
42    pub fn set_month_day(mut self, day: u32) -> Self {
43        self.use_weekday = false;
44        self.day = Some(day);
45        self
46    }
47
48    pub fn set_week_day(mut self, day: u32) -> Self {
49        self.use_weekday = true;
50        self.day = Some(day);
51        self
52    }
53
54    pub fn set_hours(mut self, val: u32) -> Self {
55        self.hours = Some(val);
56        self
57    }
58
59    pub fn set_minutes(mut self, val: u32) -> Self {
60        self.minutes = Some(val);
61        self
62    }
63
64    pub fn set_seconds(mut self, val: u32) -> Self {
65        self.seconds = Some(val);
66        self
67    }
68
69    pub fn set_subseconds(mut self, subseconds: u16, mask_bits: u8) -> Self {
70        self.subseconds_mask_bits = mask_bits;
71        self.subseconds = subseconds;
72        self
73    }
74
75    pub fn mask_day(mut self) -> Self {
76        self.day = None;
77        self
78    }
79
80    pub fn mask_hours(mut self) -> Self {
81        self.hours = None;
82        self
83    }
84
85    pub fn mask_minutes(mut self) -> Self {
86        self.minutes = None;
87        self
88    }
89
90    pub fn mask_seconds(mut self) -> Self {
91        self.seconds = None;
92        self
93    }
94}
95
96impl From<Time> for Alarm {
97    fn from(time: Time) -> Self {
98        Self::default()
99            .set_hours(time.hours)
100            .set_minutes(time.minutes)
101            .set_seconds(time.seconds)
102    }
103}
104
105pub struct Rtc {
106    rb: RTC,
107}
108
109impl Rtc {
110    pub fn new(rtc: RTC, src: RTCSrc, rcc: &mut Rcc) -> Self {
111        rcc.enable_rtc(src);
112        Rtc { rb: rtc }
113    }
114
115    pub fn set_hour_format(&mut self, fmt: RtcHourFormat) {
116        self.modify(|rb| {
117            rb.cr.modify(|_, w| w.fmt().bit(fmt == RtcHourFormat::H12));
118        });
119    }
120
121    pub fn set_date(&mut self, date: &Date) {
122        let (yt, yu) = bcd2_encode(date.year - 1970);
123        let (mt, mu) = bcd2_encode(date.month);
124        let (dt, du) = bcd2_encode(date.day);
125
126        self.modify(|rb| {
127            rb.dr.write(|w| unsafe {
128                w.dt()
129                    .bits(dt)
130                    .du()
131                    .bits(du)
132                    .mt()
133                    .bit(mt > 0)
134                    .mu()
135                    .bits(mu)
136                    .yt()
137                    .bits(yt)
138                    .yu()
139                    .bits(yu)
140                    .wdu()
141                    .bits(date.day as u8)
142            });
143        });
144    }
145
146    pub fn set_time(&mut self, time: &Time) {
147        let (ht, hu) = bcd2_encode(time.hours);
148        let (mnt, mnu) = bcd2_encode(time.minutes);
149        let (st, su) = bcd2_encode(time.seconds);
150        self.modify(|rb| {
151            rb.tr.write(|w| unsafe {
152                w.ht()
153                    .bits(ht)
154                    .hu()
155                    .bits(hu)
156                    .mnt()
157                    .bits(mnt)
158                    .mnu()
159                    .bits(mnu)
160                    .st()
161                    .bits(st)
162                    .su()
163                    .bits(su)
164                    .pm()
165                    .clear_bit()
166            });
167            rb.cr.modify(|_, w| w.fmt().bit(time.daylight_savings));
168        });
169    }
170
171    pub fn get_time(&self) -> Time {
172        let timer = self.rb.tr.read();
173        Time::new(
174            bcd2_decode(timer.ht().bits(), timer.hu().bits()).hours(),
175            bcd2_decode(timer.mnt().bits(), timer.mnu().bits()).minutes(),
176            bcd2_decode(timer.st().bits(), timer.su().bits()).secs(),
177            self.rb.cr.read().fmt().bit(),
178        )
179    }
180
181    pub fn get_date(&self) -> Date {
182        let date = self.rb.dr.read();
183        Date::new(
184            (bcd2_decode(date.yt().bits(), date.yu().bits()) + 1970).year(),
185            bcd2_decode(date.mt().bit() as u8, date.mu().bits()).month(),
186            bcd2_decode(date.dt().bits(), date.du().bits()).day(),
187        )
188    }
189
190    pub fn get_week_day(&self) -> u8 {
191        self.rb.dr.read().wdu().bits()
192    }
193
194    pub fn set_alarm_a(&mut self, alarm: impl Into<Alarm>) {
195        let alarm = alarm.into();
196        let (dt, du) = bcd2_encode(alarm.day.unwrap_or_default() as u32);
197        let (ht, hu) = bcd2_encode(alarm.hours.unwrap_or_default() as u32);
198        let (mt, mu) = bcd2_encode(alarm.minutes.unwrap_or_default() as u32);
199        let (st, su) = bcd2_encode(alarm.seconds.unwrap_or_default() as u32);
200
201        self.modify(|rb| {
202            rb.alrmassr.write(|w| unsafe {
203                w.maskss()
204                    .bits(alarm.subseconds_mask_bits)
205                    .ss()
206                    .bits(alarm.subseconds)
207            });
208            rb.alrmar.write(|w| unsafe {
209                w.wdsel().bit(alarm.use_weekday);
210                w.msk1().bit(alarm.seconds.is_none());
211                w.msk2().bit(alarm.minutes.is_none());
212                w.msk3().bit(alarm.hours.is_none());
213                w.msk4().bit(alarm.day.is_none());
214                w.dt().bits(dt);
215                w.du().bits(du);
216                w.ht().bits(ht);
217                w.hu().bits(hu);
218                w.mnt().bits(mt);
219                w.mnu().bits(mu);
220                w.st().bits(st);
221                w.su().bits(su)
222            });
223
224            rb.cr.modify(|_, w| w.alrae().set_bit());
225        });
226    }
227
228    pub fn set_alarm_b(&mut self, alarm: Alarm) {
229        let (dt, du) = bcd2_encode(alarm.day.unwrap_or_default() as u32);
230        let (ht, hu) = bcd2_encode(alarm.hours.unwrap_or_default() as u32);
231        let (mt, mu) = bcd2_encode(alarm.minutes.unwrap_or_default() as u32);
232        let (st, su) = bcd2_encode(alarm.seconds.unwrap_or_default() as u32);
233
234        self.modify(|rb| {
235            rb.alrmbssr.write(|w| unsafe {
236                w.maskss()
237                    .bits(alarm.subseconds_mask_bits)
238                    .ss()
239                    .bits(alarm.subseconds)
240            });
241            rb.alrmbr.write(|w| unsafe {
242                w.wdsel().bit(alarm.use_weekday);
243                w.msk1().bit(alarm.seconds.is_none());
244                w.msk2().bit(alarm.minutes.is_none());
245                w.msk3().bit(alarm.hours.is_none());
246                w.msk4().bit(alarm.day.is_none());
247                w.dt().bits(dt);
248                w.du().bits(du);
249                w.ht().bits(ht);
250                w.hu().bits(hu);
251                w.mnt().bits(mt);
252                w.mnu().bits(mu);
253                w.st().bits(st);
254                w.su().bits(su)
255            });
256
257            rb.cr.modify(|_, w| w.alrbe().set_bit());
258        });
259    }
260
261    pub fn listen(&mut self, ev: Event) {
262        self.modify(|rb| match ev {
263            Event::WakeupTimer => rb.cr.modify(|_, w| w.wutie().set_bit()),
264            Event::AlarmA => rb.cr.modify(|_, w| w.alraie().set_bit()),
265            Event::AlarmB => rb.cr.modify(|_, w| w.alrbie().set_bit()),
266            Event::Timestamp => rb.cr.modify(|_, w| w.tsie().set_bit()),
267        })
268    }
269
270    pub fn unlisten(&mut self, ev: Event) {
271        self.modify(|rb| match ev {
272            Event::WakeupTimer => rb.cr.modify(|_, w| w.wutie().clear_bit()),
273            Event::AlarmA => rb.cr.modify(|_, w| w.alraie().clear_bit()),
274            Event::AlarmB => rb.cr.modify(|_, w| w.alrbie().clear_bit()),
275            Event::Timestamp => rb.cr.modify(|_, w| w.tsie().clear_bit()),
276        })
277    }
278
279    pub fn is_pending(&self, ev: Event) -> bool {
280        match ev {
281            Event::WakeupTimer => self.rb.sr.read().wutf().bit_is_set(),
282            Event::AlarmA => self.rb.sr.read().alraf().bit_is_set(),
283            Event::AlarmB => self.rb.sr.read().alrbf().bit_is_set(),
284            Event::Timestamp => self.rb.sr.read().tsf().bit_is_set(),
285        }
286    }
287
288    pub fn unpend(&mut self, ev: Event) {
289        self.modify(|rb| match ev {
290            Event::WakeupTimer => rb.scr.modify(|_, w| w.cwutf().set_bit()),
291            Event::AlarmA => rb.scr.modify(|_, w| w.calraf().set_bit()),
292            Event::AlarmB => rb.scr.modify(|_, w| w.calrbf().set_bit()),
293            Event::Timestamp => rb.scr.modify(|_, w| w.ctsf().set_bit()),
294        });
295    }
296
297    pub fn enable_calibration_output<PIN: RtcOutputPin>(
298        &mut self,
299        pin: PIN,
300        freq: RtcCalibrationFrequency,
301    ) {
302        pin.setup();
303        self.modify(|rb| {
304            rb.cr.modify(|_, w| unsafe {
305                w.osel()
306                    .bits(0b0)
307                    .out2en()
308                    .bit(pin.channel())
309                    .cosel()
310                    .bit(freq == RtcCalibrationFrequency::F1Hz)
311                    .tampoe()
312                    .clear_bit()
313                    .coe()
314                    .set_bit()
315            });
316        });
317    }
318
319    fn modify<F>(&mut self, mut closure: F)
320    where
321        F: FnMut(&mut RTC),
322    {
323        // Disable write protection
324        self.rb.wpr.write(|w| unsafe { w.bits(0xCA) });
325        self.rb.wpr.write(|w| unsafe { w.bits(0x53) });
326        // Enter init mode
327        let isr = self.rb.icsr.read();
328        if isr.initf().bit_is_clear() {
329            self.rb.icsr.write(|w| w.init().set_bit());
330            self.rb.icsr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
331            while self.rb.icsr.read().initf().bit_is_clear() {}
332        }
333        // Invoke closure
334        closure(&mut self.rb);
335        // Exit init mode
336        self.rb.icsr.write(|w| w.init().clear_bit());
337        // Enable_write_protection
338        self.rb.wpr.write(|w| unsafe { w.bits(0xFF) });
339    }
340}
341
342pub trait RtcExt {
343    fn constrain(self, rcc: &mut Rcc) -> Rtc;
344}
345
346impl RtcExt for RTC {
347    fn constrain(self, rcc: &mut Rcc) -> Rtc {
348        Rtc::new(self, RTCSrc::LSI, rcc)
349    }
350}
351
352pub trait RtcOutputPin {
353    fn setup(&self);
354    fn channel(&self) -> bool;
355    fn release(self) -> Self;
356}
357
358macro_rules! rtc_out_pins {
359    ($($pin:ty: ($af_mode:expr, $ch:expr),)+) => {
360        $(
361            impl RtcOutputPin for $pin {
362                fn setup(&self) {
363                    self.set_alt_mode($af_mode);
364                }
365
366                fn channel(&self) -> bool {
367                    $ch
368                }
369
370                fn release(self) -> Self {
371                    self.into_analog()
372                }
373            }
374        )+
375    }
376}
377
378rtc_out_pins! {
379    PA4<DefaultMode>: (AltFunction::AF3, true),
380    PC13<DefaultMode>: (AltFunction::AF3, false),
381}
382
383fn bcd2_encode(word: u32) -> (u8, u8) {
384    let mut value = word as u8;
385    let mut bcd_high: u8 = 0;
386    while value >= 10 {
387        bcd_high += 1;
388        value -= 10;
389    }
390    let bcd_low = ((bcd_high << 4) | value) as u8;
391    (bcd_high, bcd_low)
392}
393
394fn bcd2_decode(fst: u8, snd: u8) -> u32 {
395    let value = snd | fst << 4;
396    let value = (value & 0x0F) + ((value & 0xF0) >> 4) * 10;
397    value as u32
398}