@@ -37,31 +37,50 @@ impl Rtc {
3737 ) -> Self {
3838 let mut result = Self { regs } ;
3939
40- enable_lse ( bdcr, bypass) ;
40+ // Steps:
41+ // Enable PWR and DBP
42+ // Enable LSE (if needed)
43+ // Enable RTC Clock
44+ // Disable Write Protect
45+ // Enter Init
46+ // Configure 24 hour format
47+ // Set prescalers
48+ // Exit Init
49+ // Enable write protect
50+
51+ // As per the sample code, unlock comes first. (Enable PWR and DBP)
4152 unlock ( apb1, pwr) ;
53+ // If necessary, enable the LSE.
54+ if bdcr. bdcr ( ) . read ( ) . lserdy ( ) . bit_is_clear ( ) {
55+ enable_lse ( bdcr, bypass) ;
56+ }
4257 enable ( bdcr) ;
43- result. set_24h_fmt ( ) ;
4458
45- result. regs . prer . modify ( |_, w| unsafe {
46- w. prediv_s ( ) . bits ( prediv_s) ;
47- w. prediv_a ( ) . bits ( prediv_a)
59+ result. modify ( |regs| {
60+ // Set 24 Hour
61+ regs. cr . modify ( |_, w| w. fmt ( ) . clear_bit ( ) ) ;
62+ // Set prescalers
63+ regs. prer . modify ( |_, w| unsafe {
64+ w. prediv_s ( ) . bits ( prediv_s) ;
65+ w. prediv_a ( ) . bits ( prediv_a)
66+ } )
4867 } ) ;
4968
5069 result
5170 }
5271
5372 /// Sets calendar clock to 24 hr format
5473 pub fn set_24h_fmt ( & mut self ) {
55- self . regs . cr . modify ( |_, w| w. fmt ( ) . set_bit ( ) ) ;
74+ self . regs . cr . modify ( |_, w| w. fmt ( ) . clear_bit ( ) ) ;
5675 }
5776 /// Sets calendar clock to 12 hr format
5877 pub fn set_12h_fmt ( & mut self ) {
59- self . regs . cr . modify ( |_, w| w. fmt ( ) . clear_bit ( ) ) ;
78+ self . regs . cr . modify ( |_, w| w. fmt ( ) . set_bit ( ) ) ;
6079 }
6180
6281 /// Reads current hour format selection
6382 pub fn is_24h_fmt ( & self ) -> bool {
64- self . regs . cr . read ( ) . fmt ( ) . bit ( )
83+ ! self . regs . cr . read ( ) . fmt ( ) . bit ( )
6584 }
6685
6786 /// As described in Section 27.3.7 in RM0316,
@@ -86,10 +105,14 @@ impl Rtc {
86105 self . regs . isr . modify ( |_, w| w. init ( ) . clear_bit ( ) ) ;
87106 // wait for last write to be done
88107 while !self . regs . isr . read ( ) . initf ( ) . bit_is_clear ( ) { }
108+
109+ // Enable write protection
110+ self . regs . wpr . write ( |w| unsafe { w. bits ( 0xFF ) } ) ;
89111 }
90112}
91113
92114impl Rtcc for Rtc {
115+ // ** Assumes 1970-01-01 00:00:00 Epoch **
93116 type Error = Error ;
94117
95118 /// set time using NaiveTime (ISO 8601 time without timezone)
@@ -99,14 +122,16 @@ impl Rtcc for Rtc {
99122 let ( ht, hu) = bcd2_encode ( time. hour ( ) ) ?;
100123 let ( mnt, mnu) = bcd2_encode ( time. minute ( ) ) ?;
101124 let ( st, su) = bcd2_encode ( time. second ( ) ) ?;
102- self . regs . tr . write ( |w| unsafe {
103- w. ht ( ) . bits ( ht) ;
104- w. hu ( ) . bits ( hu) ;
105- w. mnt ( ) . bits ( mnt) ;
106- w. mnu ( ) . bits ( mnu) ;
107- w. st ( ) . bits ( st) ;
108- w. su ( ) . bits ( su) ;
109- w. pm ( ) . clear_bit ( )
125+ self . modify ( |regs| {
126+ regs. tr . write ( |w| unsafe {
127+ w. ht ( ) . bits ( ht) ;
128+ w. hu ( ) . bits ( hu) ;
129+ w. mnt ( ) . bits ( mnt) ;
130+ w. mnu ( ) . bits ( mnu) ;
131+ w. st ( ) . bits ( st) ;
132+ w. su ( ) . bits ( su) ;
133+ w. pm ( ) . clear_bit ( )
134+ } )
110135 } ) ;
111136
112137 Ok ( ( ) )
@@ -145,9 +170,10 @@ impl Rtcc for Rtc {
145170 Hours :: AM ( _h) | Hours :: PM ( _h) => self . set_12h_fmt ( ) ,
146171 }
147172
148- self . regs
149- . tr
150- . modify ( |_, w| unsafe { w. ht ( ) . bits ( ht) . hu ( ) . bits ( hu) } ) ;
173+ self . modify ( |regs| {
174+ regs. tr
175+ . modify ( |_, w| unsafe { w. ht ( ) . bits ( ht) . hu ( ) . bits ( hu) } )
176+ } ) ;
151177
152178 Ok ( ( ) )
153179 }
@@ -191,7 +217,7 @@ impl Rtcc for Rtc {
191217 if ( year < 1970 ) || ( year > 2038 ) {
192218 return Err ( Error :: InvalidInputData ) ;
193219 }
194- let ( yt, yu) = bcd2_encode ( year as u32 ) ?;
220+ let ( yt, yu) = bcd2_encode ( year as u32 - 1970 ) ?;
195221 self . modify ( |regs| {
196222 regs. dr
197223 . modify ( |_, w| unsafe { w. yt ( ) . bits ( yt) . yu ( ) . bits ( yu) } )
@@ -211,13 +237,15 @@ impl Rtcc for Rtc {
211237 let ( mt, mu) = bcd2_encode ( date. month ( ) ) ?;
212238 let ( dt, du) = bcd2_encode ( date. day ( ) ) ?;
213239
214- self . regs . dr . write ( |w| unsafe {
215- w. dt ( ) . bits ( dt) ;
216- w. du ( ) . bits ( du) ;
217- w. mt ( ) . bit ( mt > 0 ) ;
218- w. mu ( ) . bits ( mu) ;
219- w. yt ( ) . bits ( yt) ;
220- w. yu ( ) . bits ( yu)
240+ self . modify ( |regs| {
241+ regs. dr . write ( |w| unsafe {
242+ w. dt ( ) . bits ( dt) ;
243+ w. du ( ) . bits ( du) ;
244+ w. mt ( ) . bit ( mt > 0 ) ;
245+ w. mu ( ) . bits ( mu) ;
246+ w. yt ( ) . bits ( yt) ;
247+ w. yu ( ) . bits ( yu)
248+ } )
221249 } ) ;
222250
223251 Ok ( ( ) )
@@ -237,23 +265,24 @@ impl Rtcc for Rtc {
237265 let ( mnt, mnu) = bcd2_encode ( date. minute ( ) ) ?;
238266 let ( st, su) = bcd2_encode ( date. second ( ) ) ?;
239267
240- self . regs . dr . write ( |w| unsafe {
241- w. dt ( ) . bits ( dt) ;
242- w. du ( ) . bits ( du) ;
243- w. mt ( ) . bit ( mt > 0 ) ;
244- w. mu ( ) . bits ( mu) ;
245- w. yt ( ) . bits ( yt) ;
246- w. yu ( ) . bits ( yu)
247- } ) ;
248-
249- self . regs . tr . write ( |w| unsafe {
250- w. ht ( ) . bits ( ht) ;
251- w. hu ( ) . bits ( hu) ;
252- w. mnt ( ) . bits ( mnt) ;
253- w. mnu ( ) . bits ( mnu) ;
254- w. st ( ) . bits ( st) ;
255- w. su ( ) . bits ( su) ;
256- w. pm ( ) . clear_bit ( )
268+ self . modify ( |regs| {
269+ regs. dr . write ( |w| unsafe {
270+ w. dt ( ) . bits ( dt) ;
271+ w. du ( ) . bits ( du) ;
272+ w. mt ( ) . bit ( mt > 0 ) ;
273+ w. mu ( ) . bits ( mu) ;
274+ w. yt ( ) . bits ( yt) ;
275+ w. yu ( ) . bits ( yu)
276+ } ) ;
277+ regs. tr . write ( |w| unsafe {
278+ w. ht ( ) . bits ( ht) ;
279+ w. hu ( ) . bits ( hu) ;
280+ w. mnt ( ) . bits ( mnt) ;
281+ w. mnu ( ) . bits ( mnu) ;
282+ w. st ( ) . bits ( st) ;
283+ w. su ( ) . bits ( su) ;
284+ w. pm ( ) . clear_bit ( )
285+ } )
257286 } ) ;
258287
259288 Ok ( ( ) )
@@ -262,24 +291,34 @@ impl Rtcc for Rtc {
262291 fn get_seconds ( & mut self ) -> Result < u8 , Self :: Error > {
263292 let tr = self . regs . tr . read ( ) ;
264293 let seconds = bcd2_decode ( tr. st ( ) . bits ( ) , tr. su ( ) . bits ( ) ) ;
294+ // Reading TR locks DR until read.
295+ let _day = self . get_day ( ) ;
296+
265297 Ok ( seconds as u8 )
266298 }
267299
268300 fn get_minutes ( & mut self ) -> Result < u8 , Self :: Error > {
269301 let tr = self . regs . tr . read ( ) ;
270302 let minutes = bcd2_decode ( tr. mnt ( ) . bits ( ) , tr. mnu ( ) . bits ( ) ) ;
303+ // Reading TR locks DR until read.
304+ let _day = self . get_day ( ) ;
305+
271306 Ok ( minutes as u8 )
272307 }
273308
274309 fn get_hours ( & mut self ) -> Result < Hours , Self :: Error > {
275310 let tr = self . regs . tr . read ( ) ;
276311 let hours = bcd2_decode ( tr. ht ( ) . bits ( ) , tr. hu ( ) . bits ( ) ) ;
312+ // Reading TR locks DR until read.
313+ let _day = self . get_day ( ) ;
314+
277315 if self . is_24h_fmt ( ) {
278316 return Ok ( Hours :: H24 ( hours as u8 ) ) ;
279317 }
280318 if !tr. pm ( ) . bit ( ) {
281319 return Ok ( Hours :: AM ( hours as u8 ) ) ;
282320 }
321+
283322 Ok ( Hours :: PM ( hours as u8 ) )
284323 }
285324
@@ -298,7 +337,8 @@ impl Rtcc for Rtc {
298337
299338 fn get_weekday ( & mut self ) -> Result < u8 , Self :: Error > {
300339 let dr = self . regs . dr . read ( ) ;
301- let weekday = bcd2_decode ( dr. wdu ( ) . bits ( ) , 0x00 ) ;
340+ // As per ARM RM0090 1-7 for Monday - Sunday
341+ let weekday: u8 = dr. wdu ( ) . bits ( ) ;
302342 Ok ( weekday as u8 )
303343 }
304344
@@ -317,7 +357,7 @@ impl Rtcc for Rtc {
317357
318358 fn get_year ( & mut self ) -> Result < u16 , Self :: Error > {
319359 let dr = self . regs . dr . read ( ) ;
320- let year = bcd2_decode ( dr. yt ( ) . bits ( ) , dr. yu ( ) . bits ( ) ) ;
360+ let year = bcd2_decode ( dr. yt ( ) . bits ( ) , dr. yu ( ) . bits ( ) ) + 1970 ; // 1970-01-01 is the epoch begin.
321361 Ok ( year as u16 )
322362 }
323363
@@ -331,15 +371,16 @@ impl Rtcc for Rtc {
331371
332372 fn get_datetime ( & mut self ) -> Result < NaiveDateTime , Self :: Error > {
333373 self . set_24h_fmt ( ) ;
374+ // If the time register is read, the upper bits are frozen until the date is read.
375+ // Thus, read the time first, then the date.
376+ let seconds = self . get_seconds ( ) . unwrap ( ) ;
377+ let minutes = self . get_minutes ( ) . unwrap ( ) ;
378+ let hours = hours_to_u8 ( self . get_hours ( ) ?) ?;
334379
335380 let day = self . get_day ( ) . unwrap ( ) ;
336381 let month = self . get_month ( ) . unwrap ( ) ;
337382 let year = self . get_year ( ) . unwrap ( ) ;
338383
339- let seconds = self . get_seconds ( ) . unwrap ( ) ;
340- let minutes = self . get_minutes ( ) . unwrap ( ) ;
341- let hours = hours_to_u8 ( self . get_hours ( ) ?) ?;
342-
343384 Ok (
344385 NaiveDate :: from_ymd ( year. into ( ) , month. into ( ) , day. into ( ) ) . and_hms (
345386 hours. into ( ) ,
@@ -396,9 +437,15 @@ fn hours_to_u8(hours: Hours) -> Result<u8, Error> {
396437/// Enable the low frequency external oscillator. This is the only mode currently
397438/// supported, to avoid exposing the `CR` and `CRS` registers.
398439fn enable_lse ( bdcr : & mut BDCR , bypass : bool ) {
440+ // Force a reset of the backup domain.
441+ bdcr. bdcr ( ) . modify ( |_, w| w. bdrst ( ) . enabled ( ) ) ;
442+ bdcr. bdcr ( ) . modify ( |_, w| w. bdrst ( ) . disabled ( ) ) ;
443+ // Enable the LSE.
399444 bdcr. bdcr ( )
400445 . modify ( |_, w| w. lseon ( ) . set_bit ( ) . lsebyp ( ) . bit ( bypass) ) ;
401446 while bdcr. bdcr ( ) . read ( ) . lserdy ( ) . bit_is_clear ( ) { }
447+ // Set clock source to LSE.
448+ bdcr. bdcr ( ) . modify ( |_, w| w. rtcsel ( ) . lse ( ) ) ;
402449}
403450
404451fn unlock ( apb1 : & mut APB1 , pwr : & mut PWR ) {
@@ -414,15 +461,9 @@ fn unlock(apb1: &mut APB1, pwr: &mut PWR) {
414461 . dbp ( )
415462 . set_bit ( )
416463 } ) ;
417-
418- while pwr. cr . read ( ) . dbp ( ) . bit_is_clear ( ) { }
419464}
420465
421466fn enable ( bdcr : & mut BDCR ) {
422- bdcr. bdcr ( ) . modify ( |_, w| w. bdrst ( ) . enabled ( ) ) ;
423- bdcr. bdcr ( ) . modify ( |_, w| {
424- w. rtcsel ( ) . lse ( ) ;
425- w. rtcen ( ) . enabled ( ) ;
426- w. bdrst ( ) . disabled ( )
427- } ) ;
467+ // Start the actual RTC.
468+ bdcr. bdcr ( ) . modify ( |_, w| w. rtcen ( ) . enabled ( ) ) ;
428469}
0 commit comments