aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/rtc/mod.rs
diff options
context:
space:
mode:
authorxoviat <[email protected]>2023-11-01 17:17:14 -0500
committerxoviat <[email protected]>2023-11-01 17:17:14 -0500
commitbab61f96650751d1133538431f3bfccdfda29bf7 (patch)
tree456421b3951e5a576b36974670f2180286c971ac /embassy-stm32/src/rtc/mod.rs
parent2765f0978f0a4001300dbb85a470503eb323ff52 (diff)
stm32/rtc: misc. cleanup and move to bps by default
Diffstat (limited to 'embassy-stm32/src/rtc/mod.rs')
-rw-r--r--embassy-stm32/src/rtc/mod.rs102
1 files changed, 56 insertions, 46 deletions
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs
index c8990c30a..e527fdfee 100644
--- a/embassy-stm32/src/rtc/mod.rs
+++ b/embassy-stm32/src/rtc/mod.rs
@@ -9,8 +9,11 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
9#[cfg(feature = "low-power")] 9#[cfg(feature = "low-power")]
10use embassy_sync::blocking_mutex::Mutex; 10use embassy_sync::blocking_mutex::Mutex;
11 11
12pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError, RtcInstant}; 12use self::datetime::day_of_week_to_u8;
13use crate::rtc::datetime::day_of_week_to_u8; 13#[cfg(not(rtc_v2f2))]
14use self::datetime::RtcInstant;
15pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError};
16use crate::pac::rtc::regs::{Dr, Tr};
14use crate::time::Hertz; 17use crate::time::Hertz;
15 18
16/// refer to AN4759 to compare features of RTC2 and RTC3 19/// refer to AN4759 to compare features of RTC2 and RTC3
@@ -31,11 +34,15 @@ use crate::peripherals::RTC;
31use crate::rtc::sealed::Instance; 34use crate::rtc::sealed::Instance;
32 35
33/// Errors that can occur on methods on [RtcClock] 36/// Errors that can occur on methods on [RtcClock]
37#[non_exhaustive]
34#[derive(Clone, Debug, PartialEq, Eq)] 38#[derive(Clone, Debug, PartialEq, Eq)]
35pub enum RtcError { 39pub enum RtcError {
36 /// An invalid DateTime was given or stored on the hardware. 40 /// An invalid DateTime was given or stored on the hardware.
37 InvalidDateTime(DateTimeError), 41 InvalidDateTime(DateTimeError),
38 42
43 /// The current time could not be read
44 ReadFailure,
45
39 /// The RTC clock is not running 46 /// The RTC clock is not running
40 NotRunning, 47 NotRunning,
41} 48}
@@ -45,48 +52,25 @@ pub struct RtcTimeProvider {
45} 52}
46 53
47impl RtcTimeProvider { 54impl RtcTimeProvider {
55 #[cfg(not(rtc_v2f2))]
56 pub(crate) fn instant(&self) -> Result<RtcInstant, RtcError> {
57 self.read(|_, tr, ss| {
58 let second = bcd2_to_byte((tr.st(), tr.su()));
59
60 RtcInstant::from(second, ss).map_err(RtcError::InvalidDateTime)
61 })
62 }
63
48 /// Return the current datetime. 64 /// Return the current datetime.
49 /// 65 ///
50 /// # Errors 66 /// # Errors
51 /// 67 ///
52 /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`]. 68 /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`].
53 pub fn now(&self) -> Result<DateTime, RtcError> { 69 pub fn now(&self) -> Result<DateTime, RtcError> {
54 // For RM0433 we use BYPSHAD=1 to work around errata ES0392 2.19.1 70 self.read(|dr, tr, _| {
55 #[cfg(rcc_h7rm0433)]
56 loop {
57 let r = RTC::regs();
58 let ss = r.ssr().read().ss();
59 let dr = r.dr().read();
60 let tr = r.tr().read();
61
62 // If an RTCCLK edge occurs during read we may see inconsistent values
63 // so read ssr again and see if it has changed. (see RM0433 Rev 7 46.3.9)
64 let ss_after = r.ssr().read().ss();
65 if ss == ss_after {
66 let second = bcd2_to_byte((tr.st(), tr.su()));
67 let minute = bcd2_to_byte((tr.mnt(), tr.mnu()));
68 let hour = bcd2_to_byte((tr.ht(), tr.hu()));
69
70 let weekday = dr.wdu();
71 let day = bcd2_to_byte((dr.dt(), dr.du()));
72 let month = bcd2_to_byte((dr.mt() as u8, dr.mu()));
73 let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16;
74
75 return DateTime::from(year, month, day, weekday, hour, minute, second)
76 .map_err(RtcError::InvalidDateTime);
77 }
78 }
79
80 #[cfg(not(rcc_h7rm0433))]
81 {
82 let r = RTC::regs();
83 let tr = r.tr().read();
84 let second = bcd2_to_byte((tr.st(), tr.su())); 71 let second = bcd2_to_byte((tr.st(), tr.su()));
85 let minute = bcd2_to_byte((tr.mnt(), tr.mnu())); 72 let minute = bcd2_to_byte((tr.mnt(), tr.mnu()));
86 let hour = bcd2_to_byte((tr.ht(), tr.hu())); 73 let hour = bcd2_to_byte((tr.ht(), tr.hu()));
87 // Reading either RTC_SSR or RTC_TR locks the values in the higher-order
88 // calendar shadow registers until RTC_DR is read.
89 let dr = r.dr().read();
90 74
91 let weekday = dr.wdu(); 75 let weekday = dr.wdu();
92 let day = bcd2_to_byte((dr.dt(), dr.du())); 76 let day = bcd2_to_byte((dr.dt(), dr.du()));
@@ -94,7 +78,33 @@ impl RtcTimeProvider {
94 let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16; 78 let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16;
95 79
96 DateTime::from(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime) 80 DateTime::from(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime)
81 })
82 }
83
84 fn read<R>(&self, mut f: impl FnMut(Dr, Tr, u16) -> Result<R, RtcError>) -> Result<R, RtcError> {
85 let r = RTC::regs();
86
87 #[cfg(not(rtc_v2f2))]
88 let read_ss = || r.ssr().read().ss();
89 #[cfg(rtc_v2f2)]
90 let read_ss = || 0;
91
92 let mut ss = read_ss();
93 for _ in 0..5 {
94 let tr = r.tr().read();
95 let dr = r.dr().read();
96 let ss_after = read_ss();
97
98 // If an RTCCLK edge occurs during read we may see inconsistent values
99 // so read ssr again and see if it has changed. (see RM0433 Rev 7 46.3.9)
100 if ss == ss_after {
101 return f(dr, tr, ss.try_into().unwrap());
102 } else {
103 ss = ss_after
104 }
97 } 105 }
106
107 return Err(RtcError::ReadFailure);
98 } 108 }
99} 109}
100 110
@@ -145,6 +155,7 @@ impl Rtc {
145 #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))] 155 #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))]
146 critical_section::with(|cs| { 156 critical_section::with(|cs| {
147 <RTC as crate::rcc::sealed::RccPeripheral>::enable_and_reset_with_cs(cs); 157 <RTC as crate::rcc::sealed::RccPeripheral>::enable_and_reset_with_cs(cs);
158
148 #[cfg(feature = "low-power")] 159 #[cfg(feature = "low-power")]
149 unsafe { 160 unsafe {
150 crate::rcc::REFCOUNT_STOP2 -= 1 161 crate::rcc::REFCOUNT_STOP2 -= 1
@@ -164,6 +175,14 @@ impl Rtc {
164 175
165 this.configure(async_psc, sync_psc); 176 this.configure(async_psc, sync_psc);
166 177
178 // Wait for the clock to update after initialization
179 #[cfg(not(rtc_v2f2))]
180 {
181 let now = this.instant().unwrap();
182
183 while this.instant().unwrap().subsecond == now.subsecond {}
184 }
185
167 this 186 this
168 } 187 }
169 188
@@ -183,7 +202,6 @@ impl Rtc {
183 /// 202 ///
184 /// Will return `RtcError::InvalidDateTime` if the datetime is not a valid range. 203 /// Will return `RtcError::InvalidDateTime` if the datetime is not a valid range.
185 pub fn set_datetime(&mut self, t: DateTime) -> Result<(), RtcError> { 204 pub fn set_datetime(&mut self, t: DateTime) -> Result<(), RtcError> {
186 self::datetime::validate_datetime(&t).map_err(RtcError::InvalidDateTime)?;
187 self.write(true, |rtc| { 205 self.write(true, |rtc| {
188 let (ht, hu) = byte_to_bcd2(t.hour() as u8); 206 let (ht, hu) = byte_to_bcd2(t.hour() as u8);
189 let (mnt, mnu) = byte_to_bcd2(t.minute() as u8); 207 let (mnt, mnu) = byte_to_bcd2(t.minute() as u8);
@@ -223,16 +241,8 @@ impl Rtc {
223 241
224 #[cfg(not(rtc_v2f2))] 242 #[cfg(not(rtc_v2f2))]
225 /// Return the current instant. 243 /// Return the current instant.
226 pub fn instant(&self) -> Result<RtcInstant, RtcError> { 244 fn instant(&self) -> Result<RtcInstant, RtcError> {
227 let r = RTC::regs(); 245 self.time_provider().instant()
228 let tr = r.tr().read();
229 let subsecond = r.ssr().read().ss();
230 let second = bcd2_to_byte((tr.st(), tr.su()));
231
232 // Unlock the registers
233 r.dr().read();
234
235 RtcInstant::from(second, subsecond.try_into().unwrap())
236 } 246 }
237 247
238 /// Return the current datetime. 248 /// Return the current datetime.