aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/rtc
diff options
context:
space:
mode:
authorxoviat <[email protected]>2023-11-04 13:51:11 -0500
committerxoviat <[email protected]>2023-11-04 13:51:11 -0500
commit3f2abd4fd5da51d7b8a7711d0eac02c7f7b9deed (patch)
tree3375dd57e07879f2d709f7547d95b2a7f757ae14 /embassy-stm32/src/rtc
parentdc467e89a0f093c1656eaf63955c28dd3b08be6c (diff)
parent655ed3aa887fe2d9e424f239cc07db055d8f8d61 (diff)
Merge branch 'main' of github.com:embassy-rs/embassy into low-power
Diffstat (limited to 'embassy-stm32/src/rtc')
-rw-r--r--embassy-stm32/src/rtc/datetime.rs32
-rw-r--r--embassy-stm32/src/rtc/mod.rs101
-rw-r--r--embassy-stm32/src/rtc/v2.rs4
-rw-r--r--embassy-stm32/src/rtc/v3.rs1
4 files changed, 67 insertions, 71 deletions
diff --git a/embassy-stm32/src/rtc/datetime.rs b/embassy-stm32/src/rtc/datetime.rs
index d897843dc..f3428108c 100644
--- a/embassy-stm32/src/rtc/datetime.rs
+++ b/embassy-stm32/src/rtc/datetime.rs
@@ -18,9 +18,13 @@ pub struct RtcInstant {
18} 18}
19 19
20impl RtcInstant { 20impl RtcInstant {
21 #[allow(dead_code)] 21 #[cfg(not(rtc_v2f2))]
22 pub(super) fn from(second: u8, subsecond: u16) -> Result<Self, super::RtcError> { 22 pub(super) const fn from(second: u8, subsecond: u16) -> Result<Self, Error> {
23 Ok(Self { second, subsecond }) 23 if second > 59 {
24 Err(Error::InvalidSecond)
25 } else {
26 Ok(Self { second, subsecond })
27 }
24 } 28 }
25} 29}
26 30
@@ -226,7 +230,7 @@ impl From<DayOfWeek> for chrono::Weekday {
226 } 230 }
227} 231}
228 232
229fn day_of_week_from_u8(v: u8) -> Result<DayOfWeek, Error> { 233pub(super) const fn day_of_week_from_u8(v: u8) -> Result<DayOfWeek, Error> {
230 Ok(match v { 234 Ok(match v {
231 1 => DayOfWeek::Monday, 235 1 => DayOfWeek::Monday,
232 2 => DayOfWeek::Tuesday, 236 2 => DayOfWeek::Tuesday,
@@ -239,24 +243,6 @@ fn day_of_week_from_u8(v: u8) -> Result<DayOfWeek, Error> {
239 }) 243 })
240} 244}
241 245
242pub(super) fn day_of_week_to_u8(dotw: DayOfWeek) -> u8 { 246pub(super) const fn day_of_week_to_u8(dotw: DayOfWeek) -> u8 {
243 dotw as u8 247 dotw as u8
244} 248}
245
246pub(super) fn validate_datetime(dt: &DateTime) -> Result<(), Error> {
247 if dt.year > 4095 {
248 Err(Error::InvalidYear)
249 } else if dt.month < 1 || dt.month > 12 {
250 Err(Error::InvalidMonth)
251 } else if dt.day < 1 || dt.day > 31 {
252 Err(Error::InvalidDay)
253 } else if dt.hour > 23 {
254 Err(Error::InvalidHour)
255 } else if dt.minute > 59 {
256 Err(Error::InvalidMinute)
257 } else if dt.second > 59 {
258 Err(Error::InvalidSecond)
259 } else {
260 Ok(())
261 }
262}
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs
index 68836be07..e94a58575 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
@@ -158,6 +168,14 @@ impl Rtc {
158 168
159 this.configure(async_psc, sync_psc); 169 this.configure(async_psc, sync_psc);
160 170
171 // Wait for the clock to update after initialization
172 #[cfg(not(rtc_v2f2))]
173 {
174 let now = this.instant().unwrap();
175
176 while this.instant().unwrap().subsecond == now.subsecond {}
177 }
178
161 this 179 this
162 } 180 }
163 181
@@ -177,7 +195,6 @@ impl Rtc {
177 /// 195 ///
178 /// Will return `RtcError::InvalidDateTime` if the datetime is not a valid range. 196 /// Will return `RtcError::InvalidDateTime` if the datetime is not a valid range.
179 pub fn set_datetime(&mut self, t: DateTime) -> Result<(), RtcError> { 197 pub fn set_datetime(&mut self, t: DateTime) -> Result<(), RtcError> {
180 self::datetime::validate_datetime(&t).map_err(RtcError::InvalidDateTime)?;
181 self.write(true, |rtc| { 198 self.write(true, |rtc| {
182 let (ht, hu) = byte_to_bcd2(t.hour() as u8); 199 let (ht, hu) = byte_to_bcd2(t.hour() as u8);
183 let (mnt, mnu) = byte_to_bcd2(t.minute() as u8); 200 let (mnt, mnu) = byte_to_bcd2(t.minute() as u8);
@@ -217,16 +234,8 @@ impl Rtc {
217 234
218 #[cfg(not(rtc_v2f2))] 235 #[cfg(not(rtc_v2f2))]
219 /// Return the current instant. 236 /// Return the current instant.
220 pub fn instant(&self) -> Result<RtcInstant, RtcError> { 237 fn instant(&self) -> Result<RtcInstant, RtcError> {
221 let r = RTC::regs(); 238 self.time_provider().instant()
222 let tr = r.tr().read();
223 let subsecond = r.ssr().read().ss();
224 let second = bcd2_to_byte((tr.st(), tr.su()));
225
226 // Unlock the registers
227 r.dr().read();
228
229 RtcInstant::from(second, subsecond.try_into().unwrap())
230 } 239 }
231 240
232 /// Return the current datetime. 241 /// Return the current datetime.
diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs
index b6ab9b209..006fd63f4 100644
--- a/embassy-stm32/src/rtc/v2.rs
+++ b/embassy-stm32/src/rtc/v2.rs
@@ -150,14 +150,14 @@ impl super::Rtc {
150 pub(super) fn configure(&mut self, async_psc: u8, sync_psc: u16) { 150 pub(super) fn configure(&mut self, async_psc: u8, sync_psc: u16) {
151 self.write(true, |rtc| { 151 self.write(true, |rtc| {
152 rtc.cr().modify(|w| { 152 rtc.cr().modify(|w| {
153 #[cfg(not(rtc_v2f2))]
154 w.set_bypshad(true);
153 #[cfg(rtc_v2f2)] 155 #[cfg(rtc_v2f2)]
154 w.set_fmt(false); 156 w.set_fmt(false);
155 #[cfg(not(rtc_v2f2))] 157 #[cfg(not(rtc_v2f2))]
156 w.set_fmt(stm32_metapac::rtc::vals::Fmt::TWENTY_FOUR_HOUR); 158 w.set_fmt(stm32_metapac::rtc::vals::Fmt::TWENTY_FOUR_HOUR);
157 w.set_osel(Osel::DISABLED); 159 w.set_osel(Osel::DISABLED);
158 w.set_pol(Pol::HIGH); 160 w.set_pol(Pol::HIGH);
159 #[cfg(rcc_h7rm0433)]
160 w.set_bypshad(true);
161 }); 161 });
162 162
163 rtc.prer().modify(|w| { 163 rtc.prer().modify(|w| {
diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs
index a6b2655d8..7bf757e7d 100644
--- a/embassy-stm32/src/rtc/v3.rs
+++ b/embassy-stm32/src/rtc/v3.rs
@@ -11,6 +11,7 @@ impl super::Rtc {
11 pub(super) fn configure(&mut self, async_psc: u8, sync_psc: u16) { 11 pub(super) fn configure(&mut self, async_psc: u8, sync_psc: u16) {
12 self.write(true, |rtc| { 12 self.write(true, |rtc| {
13 rtc.cr().modify(|w| { 13 rtc.cr().modify(|w| {
14 w.set_bypshad(true);
14 w.set_fmt(Fmt::TWENTYFOURHOUR); 15 w.set_fmt(Fmt::TWENTYFOURHOUR);
15 w.set_osel(Osel::DISABLED); 16 w.set_osel(Osel::DISABLED);
16 w.set_pol(Pol::HIGH); 17 w.set_pol(Pol::HIGH);