Skip to content

Commit dddd787

Browse files
committed
more rtc features
1 parent 0654d98 commit dddd787

File tree

2 files changed

+219
-14
lines changed

2 files changed

+219
-14
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1818

1919
- Extended 64-bit monotonic timer [#640]
2020
- Basic blocking QSPI interface [#645]
21+
- Rtc: add subsecond reading, add interrupts [#446]
2122

2223
### Fixed
2324

2425
- map `$SpiSlave` into `SpiSlave` struct in `spi!` macro [#635]
2526

27+
[#446]: https://github.com/stm32-rs/stm32f4xx-hal/pull/446
2628
[#632]: https://github.com/stm32-rs/stm32f4xx-hal/pull/632
2729
[#635]: https://github.com/stm32-rs/stm32f4xx-hal/pull/635
2830
[#636]: https://github.com/stm32-rs/stm32f4xx-hal/pull/636

src/rtc.rs

Lines changed: 217 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
//! [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)
44
55
use crate::bb;
6-
use crate::pac::rtc::{dr, tr};
7-
use crate::pac::{rcc::RegisterBlock, PWR, RCC, RTC};
6+
use crate::pac::rtc::{dr, tr, tsdr, tstr};
7+
use crate::pac::{self, rcc::RegisterBlock, PWR, RCC, RTC};
88
use crate::rcc::Enable;
9-
use core::convert::TryInto;
9+
use core::convert::{TryFrom, TryInto};
1010
use core::fmt;
1111
use core::marker::PhantomData;
1212
use time::{Date, PrimitiveDateTime, Time};
@@ -18,6 +18,15 @@ pub enum Error {
1818
InvalidInputData,
1919
}
2020

21+
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
22+
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
23+
pub enum Event {
24+
AlarmA,
25+
AlarmB,
26+
Wakeup,
27+
Timestamp,
28+
}
29+
2130
/// RTC clock source LSE oscillator clock (type state)
2231
pub struct Lse;
2332
/// RTC clock source LSI oscillator clock (type state)
@@ -375,6 +384,7 @@ impl<CS> Rtc<CS> {
375384
let (yt, yu) = bcd2_encode((date.year() - 1970) as u32)?;
376385
let (mt, mu) = bcd2_encode(u8::from(date.month()).into())?;
377386
let (dt, du) = bcd2_encode(date.day().into())?;
387+
let wdu = date.weekday().number_from_monday();
378388

379389
self.modify(|regs| {
380390
regs.dr.write(|w| {
@@ -383,7 +393,8 @@ impl<CS> Rtc<CS> {
383393
w.mt().bit(mt > 0);
384394
w.mu().bits(mu);
385395
w.yt().bits(yt);
386-
w.yu().bits(yu)
396+
w.yu().bits(yu);
397+
unsafe { w.wdu().bits(wdu) }
387398
})
388399
});
389400

@@ -402,6 +413,7 @@ impl<CS> Rtc<CS> {
402413
let (yt, yu) = bcd2_encode((date.year() - 1970) as u32)?;
403414
let (mt, mu) = bcd2_encode(u8::from(date.month()).into())?;
404415
let (dt, du) = bcd2_encode(date.day().into())?;
416+
let wdu = date.weekday().number_from_monday();
405417

406418
let (ht, hu) = bcd2_encode(date.hour().into())?;
407419
let (mnt, mnu) = bcd2_encode(date.minute().into())?;
@@ -414,7 +426,8 @@ impl<CS> Rtc<CS> {
414426
w.mt().bit(mt > 0);
415427
w.mu().bits(mu);
416428
w.yt().bits(yt);
417-
w.yu().bits(yu)
429+
w.yu().bits(yu);
430+
unsafe { w.wdu().bits(wdu) }
418431
});
419432
regs.tr.write(|w| {
420433
w.ht().bits(ht);
@@ -436,6 +449,7 @@ impl<CS> Rtc<CS> {
436449

437450
// Reading either RTC_SSR or RTC_TR locks the values in the higher-order calendar shadow registers until RTC_DR is read.
438451
// So it is important to always read SSR, TR and then DR or TR and then DR.
452+
let ss = self.regs.ssr.read().ss().bits();
439453
let tr = self.regs.tr.read();
440454
let dr = self.regs.dr.read();
441455
// In case the software makes read accesses to the calendar in a time interval smaller
@@ -448,12 +462,172 @@ impl<CS> Rtc<CS> {
448462
let day = decode_day(&dr);
449463
let month = decode_month(&dr);
450464
let year = decode_year(&dr);
465+
let prediv_s = self.regs.prer.read().prediv_s().bits();
466+
let nano = ss_to_nano(ss, prediv_s);
467+
468+
PrimitiveDateTime::new(
469+
Date::from_calendar_date(year.into(), month.try_into().unwrap(), day).unwrap(),
470+
Time::from_hms_nano(hours, minutes, seconds, nano).unwrap(),
471+
)
472+
}
473+
474+
/// Configures the wakeup timer to trigger periodically every `interval` seconds
475+
///
476+
/// # Panics
477+
///
478+
/// Panics if interval is greater than 2¹⁷-1.
479+
pub fn enable_wakeup(&mut self, interval: u32) {
480+
self.modify(|regs| {
481+
regs.cr.modify(|_, w| w.wute().clear_bit());
482+
regs.isr.modify(|_, w| w.wutf().clear_bit());
483+
while regs.isr.read().wutwf().bit_is_clear() {}
484+
485+
if interval > 1 << 16 {
486+
regs.cr.modify(|_, w| unsafe { w.wucksel().bits(0b110) });
487+
let interval = u16::try_from(interval - (1 << 16) - 1)
488+
.expect("Interval was too large for wakeup timer");
489+
regs.wutr.write(|w| w.wut().bits(interval));
490+
} else {
491+
regs.cr.modify(|_, w| unsafe { w.wucksel().bits(0b100) });
492+
let interval =
493+
u16::try_from(interval - 1).expect("Interval was too large for wakeup timer");
494+
regs.wutr.write(|w| w.wut().bits(interval));
495+
}
496+
497+
regs.cr.modify(|_, w| w.wute().set_bit());
498+
});
499+
}
500+
501+
/// Disables the wakeup timer
502+
pub fn disable_wakeup(&mut self) {
503+
self.modify(|regs| {
504+
regs.cr.modify(|_, w| w.wute().clear_bit());
505+
regs.isr.modify(|_, w| w.wutf().clear_bit());
506+
});
507+
}
508+
509+
/// Configures the timestamp to be captured when the RTC switches to Vbat power
510+
pub fn enable_vbat_timestamp(&mut self) {
511+
self.modify(|regs| {
512+
regs.cr.modify(|_, w| w.tse().clear_bit());
513+
regs.isr.modify(|_, w| w.tsf().clear_bit());
514+
regs.cr.modify(|_, w| w.tse().set_bit());
515+
});
516+
}
517+
518+
/// Disables the timestamp
519+
pub fn disable_timestamp(&mut self) {
520+
self.modify(|regs| {
521+
regs.cr.modify(|_, w| w.tse().clear_bit());
522+
regs.isr.modify(|_, w| w.tsf().clear_bit());
523+
});
524+
}
525+
526+
/// Reads the stored value of the timestamp if present
527+
///
528+
/// Clears the timestamp interrupt flags.
529+
pub fn read_timestamp(&self) -> PrimitiveDateTime {
530+
while self.regs.isr.read().rsf().bit_is_clear() {}
531+
532+
// Timestamp doesn't include year, get it from the main calendar
533+
let ss = self.regs.tsssr.read().ss().bits();
534+
let tr = self.regs.tstr.read();
535+
let dr = self.regs.tsdr.read();
536+
let dry = self.regs.dr.read();
537+
538+
let seconds = decode_ts_seconds(&tr);
539+
let minutes = decode_ts_minutes(&tr);
540+
let hours = decode_ts_hours(&tr);
541+
let day = decode_ts_day(&dr);
542+
let month = decode_ts_month(&dr);
543+
let year = decode_year(&dry);
544+
let prediv_s = self.regs.prer.read().prediv_s().bits();
545+
let nano = ss_to_nano(ss, prediv_s);
451546

452547
PrimitiveDateTime::new(
453548
Date::from_calendar_date(year.into(), month.try_into().unwrap(), day).unwrap(),
454-
Time::from_hms(hours, minutes, seconds).unwrap(),
549+
Time::from_hms_nano(hours, minutes, seconds, nano).unwrap(),
455550
)
456551
}
552+
553+
// TODO: Alarms
554+
555+
/// Start listening for `event`
556+
pub fn listen(&mut self, exti: &mut pac::EXTI, event: Event) {
557+
// Input Mapping:
558+
// EXTI 17 = RTC Alarms
559+
// EXTI 21 = RTC Tamper, RTC Timestamp
560+
// EXTI 22 = RTC Wakeup Timer
561+
self.modify(|regs| match event {
562+
Event::AlarmA => {
563+
exti.rtsr.modify(|_, w| w.tr17().enabled());
564+
regs.cr.modify(|_, w| w.alraie().set_bit());
565+
}
566+
Event::AlarmB => {
567+
exti.rtsr.modify(|_, w| w.tr17().enabled());
568+
regs.cr.modify(|_, w| w.alrbie().set_bit());
569+
}
570+
Event::Wakeup => {
571+
exti.rtsr.modify(|_, w| w.tr22().enabled());
572+
regs.cr.modify(|_, w| w.wutie().set_bit());
573+
}
574+
Event::Timestamp => {
575+
exti.rtsr.modify(|_, w| w.tr21().enabled());
576+
regs.cr.modify(|_, w| w.tsie().set_bit());
577+
}
578+
});
579+
}
580+
581+
/// Stop listening for `event`
582+
pub fn unlisten(&mut self, exti: &mut pac::EXTI, event: Event) {
583+
// See the note in listen() about EXTI
584+
self.modify(|regs| match event {
585+
Event::AlarmA => {
586+
regs.cr.modify(|_, w| w.alraie().clear_bit());
587+
exti.rtsr.modify(|_, w| w.tr17().disabled());
588+
}
589+
Event::AlarmB => {
590+
regs.cr.modify(|_, w| w.alrbie().clear_bit());
591+
exti.rtsr.modify(|_, w| w.tr17().disabled());
592+
}
593+
Event::Wakeup => {
594+
regs.cr.modify(|_, w| w.wutie().clear_bit());
595+
exti.rtsr.modify(|_, w| w.tr22().disabled());
596+
}
597+
Event::Timestamp => {
598+
regs.cr.modify(|_, w| w.tsie().clear_bit());
599+
exti.rtsr.modify(|_, w| w.tr21().disabled());
600+
}
601+
});
602+
}
603+
604+
/// Returns `true` if `event` is pending
605+
pub fn is_pending(&self, event: Event) -> bool {
606+
match event {
607+
Event::AlarmA => self.regs.isr.read().alraf().bit_is_set(),
608+
Event::AlarmB => self.regs.isr.read().alrbf().bit_is_set(),
609+
Event::Wakeup => self.regs.isr.read().wutf().bit_is_set(),
610+
Event::Timestamp => self.regs.isr.read().tsf().bit_is_set(),
611+
}
612+
}
613+
614+
/// Clears the interrupt flag for `event`
615+
pub fn clear_interrupt(&mut self, event: Event) {
616+
match event {
617+
Event::AlarmA => {
618+
self.regs.isr.modify(|_, w| w.alraf().clear_bit());
619+
}
620+
Event::AlarmB => {
621+
self.regs.isr.modify(|_, w| w.alrbf().clear_bit());
622+
}
623+
Event::Wakeup => {
624+
self.regs.isr.modify(|_, w| w.wutf().clear_bit());
625+
}
626+
Event::Timestamp => {
627+
self.regs.isr.modify(|_, w| w.tsf().clear_bit());
628+
}
629+
}
630+
}
457631
}
458632

459633
// Two 32-bit registers (RTC_TR and RTC_DR) contain the seconds, minutes, hours (12- or 24-hour format), day (day
@@ -479,38 +653,67 @@ fn bcd2_encode(word: u32) -> Result<(u8, u8), Error> {
479653
Ok((l, r))
480654
}
481655

482-
fn bcd2_decode(fst: u8, snd: u8) -> u32 {
483-
(fst * 10 + snd).into()
656+
const fn bcd2_decode(fst: u8, snd: u8) -> u8 {
657+
fst * 10 + snd
484658
}
485659

486660
#[inline(always)]
487661
fn decode_seconds(tr: &tr::R) -> u8 {
488-
bcd2_decode(tr.st().bits(), tr.su().bits()) as u8
662+
bcd2_decode(tr.st().bits(), tr.su().bits())
663+
}
664+
#[inline(always)]
665+
fn decode_ts_seconds(tr: &tstr::R) -> u8 {
666+
bcd2_decode(tr.st().bits(), tr.su().bits())
489667
}
490668

491669
#[inline(always)]
492670
fn decode_minutes(tr: &tr::R) -> u8 {
493-
bcd2_decode(tr.mnt().bits(), tr.mnu().bits()) as u8
671+
bcd2_decode(tr.mnt().bits(), tr.mnu().bits())
672+
}
673+
#[inline(always)]
674+
fn decode_ts_minutes(tr: &tstr::R) -> u8 {
675+
bcd2_decode(tr.mnt().bits(), tr.mnu().bits())
494676
}
495677

496678
#[inline(always)]
497679
fn decode_hours(tr: &tr::R) -> u8 {
498-
bcd2_decode(tr.ht().bits(), tr.hu().bits()) as u8
680+
bcd2_decode(tr.ht().bits(), tr.hu().bits())
681+
}
682+
#[inline(always)]
683+
fn decode_ts_hours(tr: &tstr::R) -> u8 {
684+
bcd2_decode(tr.ht().bits(), tr.hu().bits())
499685
}
500686

501687
#[inline(always)]
502688
fn decode_day(dr: &dr::R) -> u8 {
503-
bcd2_decode(dr.dt().bits(), dr.du().bits()) as u8
689+
bcd2_decode(dr.dt().bits(), dr.du().bits())
690+
}
691+
#[inline(always)]
692+
fn decode_ts_day(dr: &tsdr::R) -> u8 {
693+
bcd2_decode(dr.dt().bits(), dr.du().bits())
504694
}
505695

506696
#[inline(always)]
507697
fn decode_month(dr: &dr::R) -> u8 {
508698
let mt = u8::from(dr.mt().bit());
509-
bcd2_decode(mt, dr.mu().bits()) as u8
699+
bcd2_decode(mt, dr.mu().bits())
700+
}
701+
#[inline(always)]
702+
fn decode_ts_month(dr: &tsdr::R) -> u8 {
703+
let mt = u8::from(dr.mt().bit());
704+
bcd2_decode(mt, dr.mu().bits())
510705
}
511706

512707
#[inline(always)]
513708
fn decode_year(dr: &dr::R) -> u16 {
514-
let year = bcd2_decode(dr.yt().bits(), dr.yu().bits()) + 1970; // 1970-01-01 is the epoch begin.
709+
let year = (bcd2_decode(dr.yt().bits(), dr.yu().bits()) as u32) + 1970; // 1970-01-01 is the epoch begin.
515710
year as u16
516711
}
712+
713+
const fn ss_to_nano(ss: u16, prediv_s: u16) -> u32 {
714+
let ss = ss as u32;
715+
let prediv_s = prediv_s as u32;
716+
assert!(ss <= prediv_s);
717+
718+
(((prediv_s - ss) * 100_000) / (prediv_s + 1)) * 10_000
719+
}

0 commit comments

Comments
 (0)