aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/rtc/low_power.rs
diff options
context:
space:
mode:
authorxoviat <[email protected]>2025-12-18 15:42:13 +0000
committerGitHub <[email protected]>2025-12-18 15:42:13 +0000
commitda16ea77af0fdd875ac568d5e2da1931b8740892 (patch)
tree2fa25c7907ba8ef1923c4baeeb93dd88c57bce7e /embassy-stm32/src/rtc/low_power.rs
parentb5b49cbcf3a991bf6d434b0870da50f3ee722612 (diff)
parentcec833c5f48ae93d1a47d5b763e613d8407d48a1 (diff)
Merge pull request #5101 from xoviat/low-power-rtc
stm32: use datemath to resume time
Diffstat (limited to 'embassy-stm32/src/rtc/low_power.rs')
-rw-r--r--embassy-stm32/src/rtc/low_power.rs94
1 files changed, 15 insertions, 79 deletions
diff --git a/embassy-stm32/src/rtc/low_power.rs b/embassy-stm32/src/rtc/low_power.rs
index f049d6b12..cd5cea081 100644
--- a/embassy-stm32/src/rtc/low_power.rs
+++ b/embassy-stm32/src/rtc/low_power.rs
@@ -1,64 +1,12 @@
1#[cfg(feature = "time")] 1use chrono::{DateTime, NaiveDateTime, TimeDelta, Utc};
2use embassy_time::{Duration, TICK_HZ}; 2use embassy_time::{Duration, Instant, TICK_HZ};
3 3
4use super::{DateTimeError, Rtc, RtcError, bcd2_to_byte}; 4use super::Rtc;
5use crate::interrupt::typelevel::Interrupt; 5use crate::interrupt::typelevel::Interrupt;
6use crate::pac::rtc::vals::Wucksel; 6use crate::pac::rtc::vals::Wucksel;
7use crate::peripherals::RTC; 7use crate::peripherals::RTC;
8use crate::rtc::{RtcTimeProvider, SealedInstance}; 8use crate::rtc::{RtcTimeProvider, SealedInstance};
9 9
10/// Represents an instant in time that can be substracted to compute a duration
11pub(super) struct RtcInstant {
12 /// 0..59
13 second: u8,
14 /// 0..256
15 subsecond: u16,
16}
17
18impl RtcInstant {
19 #[cfg(not(rtc_v2_f2))]
20 const fn from(second: u8, subsecond: u16) -> Result<Self, DateTimeError> {
21 if second > 59 {
22 Err(DateTimeError::InvalidSecond)
23 } else {
24 Ok(Self { second, subsecond })
25 }
26 }
27}
28
29#[cfg(feature = "defmt")]
30impl defmt::Format for RtcInstant {
31 fn format(&self, fmt: defmt::Formatter) {
32 defmt::write!(
33 fmt,
34 "{}:{}",
35 self.second,
36 RTC::regs().prer().read().prediv_s() - self.subsecond,
37 )
38 }
39}
40
41#[cfg(feature = "time")]
42impl core::ops::Sub for RtcInstant {
43 type Output = embassy_time::Duration;
44
45 fn sub(self, rhs: Self) -> Self::Output {
46 let second = if self.second < rhs.second {
47 self.second + 60
48 } else {
49 self.second
50 };
51
52 let psc = RTC::regs().prer().read().prediv_s() as u32;
53
54 let self_ticks = second as u32 * (psc + 1) + (psc - self.subsecond as u32);
55 let other_ticks = rhs.second as u32 * (psc + 1) + (psc - rhs.subsecond as u32);
56 let rtc_ticks = self_ticks - other_ticks;
57
58 Duration::from_ticks(((rtc_ticks * TICK_HZ as u32) / (psc + 1)) as u64)
59 }
60}
61
62fn wucksel_compute_min(val: u32) -> (Wucksel, u32) { 10fn wucksel_compute_min(val: u32) -> (Wucksel, u32) {
63 *[ 11 *[
64 (Wucksel::DIV2, 2), 12 (Wucksel::DIV2, 2),
@@ -72,22 +20,15 @@ fn wucksel_compute_min(val: u32) -> (Wucksel, u32) {
72} 20}
73 21
74impl Rtc { 22impl Rtc {
75 /// Return the current instant. 23 pub(super) fn calc_epoch(&self) -> DateTime<Utc> {
76 fn instant(&self) -> Result<RtcInstant, RtcError> { 24 let now: NaiveDateTime = RtcTimeProvider::new().now().unwrap().into();
77 RtcTimeProvider::new().read(|_, tr, ss| {
78 let second = bcd2_to_byte((tr.st(), tr.su()));
79 25
80 RtcInstant::from(second, ss).map_err(RtcError::InvalidDateTime) 26 now.and_utc() - TimeDelta::microseconds(Instant::now().as_micros().try_into().unwrap())
81 })
82 } 27 }
83 28
84 /// start the wakeup alarm and with a duration that is as close to but less than 29 /// start the wakeup alarm and with a duration that is as close to but less than
85 /// the requested duration, and record the instant the wakeup alarm was started 30 /// the requested duration, and record the instant the wakeup alarm was started
86 pub(crate) fn start_wakeup_alarm( 31 pub(crate) fn start_wakeup_alarm(&mut self, requested_duration: embassy_time::Duration) {
87 &mut self,
88 requested_duration: embassy_time::Duration,
89 cs: critical_section::CriticalSection,
90 ) {
91 // Panic if the rcc mod knows we're not using low-power rtc 32 // Panic if the rcc mod knows we're not using low-power rtc
92 #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] 33 #[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
93 unsafe { crate::rcc::get_freqs() }.rtc.to_hertz().unwrap(); 34 unsafe { crate::rcc::get_freqs() }.rtc.to_hertz().unwrap();
@@ -122,27 +63,19 @@ impl Rtc {
122 regs.cr().modify(|w| w.set_wutie(true)); 63 regs.cr().modify(|w| w.set_wutie(true));
123 }); 64 });
124 65
125 let instant = self.instant().unwrap();
126 trace!( 66 trace!(
127 "rtc: start wakeup alarm for {} ms (psc: {}, ticks: {}) at {}", 67 "rtc: start wakeup alarm for {} ms (psc: {}, ticks: {})",
128 Duration::from_ticks(rtc_ticks as u64 * TICK_HZ * prescaler as u64 / rtc_hz).as_millis(), 68 Duration::from_ticks(rtc_ticks as u64 * TICK_HZ * prescaler as u64 / rtc_hz).as_millis(),
129 prescaler as u32, 69 prescaler as u32,
130 rtc_ticks, 70 rtc_ticks,
131 instant,
132 ); 71 );
133
134 assert!(self.stop_time.borrow(cs).replace(Some(instant)).is_none())
135 } 72 }
136 73
137 /// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm` 74 /// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm`
138 /// was called, otherwise none 75 /// was called, otherwise none
139 pub(crate) fn stop_wakeup_alarm( 76 pub(crate) fn stop_wakeup_alarm(&mut self) -> embassy_time::Instant {
140 &mut self,
141 cs: critical_section::CriticalSection,
142 ) -> Option<embassy_time::Duration> {
143 let instant = self.instant().unwrap();
144 if RTC::regs().cr().read().wute() { 77 if RTC::regs().cr().read().wute() {
145 trace!("rtc: stop wakeup alarm at {}", instant); 78 trace!("rtc: stop wakeup alarm");
146 79
147 self.write(false, |regs| { 80 self.write(false, |regs| {
148 regs.cr().modify(|w| w.set_wutie(false)); 81 regs.cr().modify(|w| w.set_wutie(false));
@@ -166,10 +99,13 @@ impl Rtc {
166 }); 99 });
167 } 100 }
168 101
169 self.stop_time.borrow(cs).take().map(|stop_time| instant - stop_time) 102 let datetime: NaiveDateTime = RtcTimeProvider::new().now().expect("failed to read now").into();
103 let offset = datetime.and_utc() - self.epoch;
104
105 Instant::from_micros(offset.num_microseconds().unwrap().try_into().unwrap())
170 } 106 }
171 107
172 pub(crate) fn enable_wakeup_line(&self) { 108 pub(super) fn enable_wakeup_line(&mut self) {
173 <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::unpend(); 109 <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::unpend();
174 unsafe { <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::enable() }; 110 unsafe { <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::enable() };
175 111