Skip to content

Commit 364869d

Browse files
committed
RTC: Wrap the following items in the modify function: set time, date, hours, minutes, seconds. Structure code closer to ST example.
RTC: Ensure DR register is read after reading TR register, as per ST. RTC: Set Epoch to 1970-01-01. RTC: Fix 12/24 hour flag, previous example had logic flipped. RTC: Add CHANGELOG entry.
1 parent 2a786ea commit 364869d

3 files changed

Lines changed: 100 additions & 63 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
3939
- Added support for hardware-based CRC32 functionality
4040
- Add `MonoTimer` and `Instant` structs for basic time measurement.
4141
- Added support for I2S and SAI clocks
42+
- Added support for the Real Time Clock (RTC)
4243

4344
### Fixed
4445

src/rcc/mod.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -253,11 +253,6 @@ impl APB1 {
253253
// NOTE(unsafe) this proxy grants exclusive access to this register
254254
unsafe { &(*RCC::ptr()).apb1enr }
255255
}
256-
257-
pub(crate) fn rstr(&mut self) -> &rcc::APB1RSTR {
258-
// NOTE(unsafe) this proxy grants exclusive access to this register
259-
unsafe { &(*RCC::ptr()).apb1rstr }
260-
}
261256
}
262257

263258
impl APB1 {

src/rtc.rs

Lines changed: 99 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -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

92114
impl 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.
398439
fn 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

404451
fn 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

421466
fn 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

Comments
 (0)