diff options
Diffstat (limited to 'embassy-stm32/src/rtc/mod.rs')
| -rw-r--r-- | embassy-stm32/src/rtc/mod.rs | 121 |
1 files changed, 99 insertions, 22 deletions
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 92dec0960..e88bd7ab2 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs | |||
| @@ -5,15 +5,19 @@ mod datetime; | |||
| 5 | mod low_power; | 5 | mod low_power; |
| 6 | 6 | ||
| 7 | #[cfg(feature = "low-power")] | 7 | #[cfg(feature = "low-power")] |
| 8 | use core::cell::Cell; | 8 | use core::cell::{Cell, RefCell, RefMut}; |
| 9 | #[cfg(feature = "low-power")] | ||
| 10 | use core::ops; | ||
| 9 | 11 | ||
| 10 | #[cfg(feature = "low-power")] | 12 | #[cfg(feature = "low-power")] |
| 11 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | 13 | use critical_section::CriticalSection; |
| 12 | #[cfg(feature = "low-power")] | 14 | #[cfg(feature = "low-power")] |
| 13 | use embassy_sync::blocking_mutex::Mutex; | 15 | use embassy_sync::blocking_mutex::Mutex; |
| 16 | #[cfg(feature = "low-power")] | ||
| 17 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 14 | 18 | ||
| 15 | use self::datetime::{day_of_week_from_u8, day_of_week_to_u8}; | ||
| 16 | pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; | 19 | pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; |
| 20 | use self::datetime::{day_of_week_from_u8, day_of_week_to_u8}; | ||
| 17 | use crate::pac::rtc::regs::{Dr, Tr}; | 21 | use crate::pac::rtc::regs::{Dr, Tr}; |
| 18 | use crate::time::Hertz; | 22 | use crate::time::Hertz; |
| 19 | 23 | ||
| @@ -25,8 +29,8 @@ mod _version; | |||
| 25 | #[allow(unused_imports)] | 29 | #[allow(unused_imports)] |
| 26 | pub use _version::*; | 30 | pub use _version::*; |
| 27 | 31 | ||
| 28 | use crate::peripherals::RTC; | ||
| 29 | use crate::Peri; | 32 | use crate::Peri; |
| 33 | use crate::peripherals::RTC; | ||
| 30 | 34 | ||
| 31 | /// Errors that can occur on methods on [RtcClock] | 35 | /// Errors that can occur on methods on [RtcClock] |
| 32 | #[non_exhaustive] | 36 | #[non_exhaustive] |
| @@ -44,11 +48,17 @@ pub enum RtcError { | |||
| 44 | } | 48 | } |
| 45 | 49 | ||
| 46 | /// Provides immutable access to the current time of the RTC. | 50 | /// Provides immutable access to the current time of the RTC. |
| 51 | #[derive(Clone)] | ||
| 47 | pub struct RtcTimeProvider { | 52 | pub struct RtcTimeProvider { |
| 48 | _private: (), | 53 | _private: (), |
| 49 | } | 54 | } |
| 50 | 55 | ||
| 51 | impl RtcTimeProvider { | 56 | impl RtcTimeProvider { |
| 57 | /// Create a new RTC time provider instance. | ||
| 58 | pub(self) const fn new() -> Self { | ||
| 59 | Self { _private: () } | ||
| 60 | } | ||
| 61 | |||
| 52 | /// Return the current datetime. | 62 | /// Return the current datetime. |
| 53 | /// | 63 | /// |
| 54 | /// # Errors | 64 | /// # Errors |
| @@ -106,6 +116,50 @@ impl RtcTimeProvider { | |||
| 106 | } | 116 | } |
| 107 | } | 117 | } |
| 108 | 118 | ||
| 119 | #[cfg(feature = "low-power")] | ||
| 120 | /// Contains an RTC driver. | ||
| 121 | pub struct RtcContainer { | ||
| 122 | pub(self) mutex: &'static Mutex<CriticalSectionRawMutex, RefCell<Option<Rtc>>>, | ||
| 123 | } | ||
| 124 | |||
| 125 | #[cfg(feature = "low-power")] | ||
| 126 | impl RtcContainer { | ||
| 127 | pub(self) const fn new() -> Self { | ||
| 128 | Self { | ||
| 129 | mutex: &crate::time_driver::get_driver().rtc, | ||
| 130 | } | ||
| 131 | } | ||
| 132 | |||
| 133 | /// Acquire an RTC borrow. | ||
| 134 | pub fn borrow_mut<'a>(&self, cs: CriticalSection<'a>) -> RtcBorrow<'a> { | ||
| 135 | RtcBorrow { | ||
| 136 | ref_mut: self.mutex.borrow(cs).borrow_mut(), | ||
| 137 | } | ||
| 138 | } | ||
| 139 | } | ||
| 140 | |||
| 141 | #[cfg(feature = "low-power")] | ||
| 142 | /// Contains an RTC borrow. | ||
| 143 | pub struct RtcBorrow<'a> { | ||
| 144 | pub(self) ref_mut: RefMut<'a, Option<Rtc>>, | ||
| 145 | } | ||
| 146 | |||
| 147 | #[cfg(feature = "low-power")] | ||
| 148 | impl<'a> ops::Deref for RtcBorrow<'a> { | ||
| 149 | type Target = Rtc; | ||
| 150 | |||
| 151 | fn deref(&self) -> &Self::Target { | ||
| 152 | self.ref_mut.as_ref().unwrap() | ||
| 153 | } | ||
| 154 | } | ||
| 155 | |||
| 156 | #[cfg(feature = "low-power")] | ||
| 157 | impl<'a> ops::DerefMut for RtcBorrow<'a> { | ||
| 158 | fn deref_mut(&mut self) -> &mut Self::Target { | ||
| 159 | self.ref_mut.as_mut().unwrap() | ||
| 160 | } | ||
| 161 | } | ||
| 162 | |||
| 109 | /// RTC driver. | 163 | /// RTC driver. |
| 110 | pub struct Rtc { | 164 | pub struct Rtc { |
| 111 | #[cfg(feature = "low-power")] | 165 | #[cfg(feature = "low-power")] |
| @@ -121,13 +175,21 @@ pub struct RtcConfig { | |||
| 121 | /// | 175 | /// |
| 122 | /// A high counter frequency may impact stop power consumption | 176 | /// A high counter frequency may impact stop power consumption |
| 123 | pub frequency: Hertz, | 177 | pub frequency: Hertz, |
| 178 | |||
| 179 | #[cfg(feature = "_allow-disable-rtc")] | ||
| 180 | /// Allow disabling the rtc, even when stop is configured | ||
| 181 | pub _disable_rtc: bool, | ||
| 124 | } | 182 | } |
| 125 | 183 | ||
| 126 | impl Default for RtcConfig { | 184 | impl Default for RtcConfig { |
| 127 | /// LSI with prescalers assuming 32.768 kHz. | 185 | /// LSI with prescalers assuming 32.768 kHz. |
| 128 | /// Raw sub-seconds in 1/256. | 186 | /// Raw sub-seconds in 1/256. |
| 129 | fn default() -> Self { | 187 | fn default() -> Self { |
| 130 | RtcConfig { frequency: Hertz(256) } | 188 | RtcConfig { |
| 189 | frequency: Hertz(256), | ||
| 190 | #[cfg(feature = "_allow-disable-rtc")] | ||
| 191 | _disable_rtc: false, | ||
| 192 | } | ||
| 131 | } | 193 | } |
| 132 | } | 194 | } |
| 133 | 195 | ||
| @@ -145,8 +207,19 @@ pub enum RtcCalibrationCyclePeriod { | |||
| 145 | } | 207 | } |
| 146 | 208 | ||
| 147 | impl Rtc { | 209 | impl Rtc { |
| 210 | #[cfg(not(feature = "low-power"))] | ||
| 148 | /// Create a new RTC instance. | 211 | /// Create a new RTC instance. |
| 149 | pub fn new(_rtc: Peri<'static, RTC>, rtc_config: RtcConfig) -> Self { | 212 | pub fn new(_rtc: Peri<'static, RTC>, rtc_config: RtcConfig) -> (Self, RtcTimeProvider) { |
| 213 | (Self::new_inner(rtc_config), RtcTimeProvider::new()) | ||
| 214 | } | ||
| 215 | |||
| 216 | #[cfg(feature = "low-power")] | ||
| 217 | /// Create a new RTC instance. | ||
| 218 | pub fn new(_rtc: Peri<'static, RTC>) -> (RtcContainer, RtcTimeProvider) { | ||
| 219 | (RtcContainer::new(), RtcTimeProvider::new()) | ||
| 220 | } | ||
| 221 | |||
| 222 | pub(self) fn new_inner(rtc_config: RtcConfig) -> Self { | ||
| 150 | #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))] | 223 | #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))] |
| 151 | crate::rcc::enable_and_reset::<RTC>(); | 224 | crate::rcc::enable_and_reset::<RTC>(); |
| 152 | 225 | ||
| @@ -165,10 +238,13 @@ impl Rtc { | |||
| 165 | // Wait for the clock to update after initialization | 238 | // Wait for the clock to update after initialization |
| 166 | #[cfg(not(rtc_v2_f2))] | 239 | #[cfg(not(rtc_v2_f2))] |
| 167 | { | 240 | { |
| 168 | let now = this.time_provider().read(|_, _, ss| Ok(ss)).unwrap(); | 241 | let now = RtcTimeProvider::new().read(|_, _, ss| Ok(ss)).unwrap(); |
| 169 | while now == this.time_provider().read(|_, _, ss| Ok(ss)).unwrap() {} | 242 | while now == RtcTimeProvider::new().read(|_, _, ss| Ok(ss)).unwrap() {} |
| 170 | } | 243 | } |
| 171 | 244 | ||
| 245 | #[cfg(feature = "low-power")] | ||
| 246 | this.enable_wakeup_line(); | ||
| 247 | |||
| 172 | this | 248 | this |
| 173 | } | 249 | } |
| 174 | 250 | ||
| @@ -177,11 +253,6 @@ impl Rtc { | |||
| 177 | freqs.rtc.to_hertz().unwrap() | 253 | freqs.rtc.to_hertz().unwrap() |
| 178 | } | 254 | } |
| 179 | 255 | ||
| 180 | /// Acquire a [`RtcTimeProvider`] instance. | ||
| 181 | pub const fn time_provider(&self) -> RtcTimeProvider { | ||
| 182 | RtcTimeProvider { _private: () } | ||
| 183 | } | ||
| 184 | |||
| 185 | /// Set the datetime to a new value. | 256 | /// Set the datetime to a new value. |
| 186 | /// | 257 | /// |
| 187 | /// # Errors | 258 | /// # Errors |
| @@ -225,15 +296,6 @@ impl Rtc { | |||
| 225 | Ok(()) | 296 | Ok(()) |
| 226 | } | 297 | } |
| 227 | 298 | ||
| 228 | /// Return the current datetime. | ||
| 229 | /// | ||
| 230 | /// # Errors | ||
| 231 | /// | ||
| 232 | /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`]. | ||
| 233 | pub fn now(&self) -> Result<DateTime, RtcError> { | ||
| 234 | self.time_provider().now() | ||
| 235 | } | ||
| 236 | |||
| 237 | /// Check if daylight savings time is active. | 299 | /// Check if daylight savings time is active. |
| 238 | pub fn get_daylight_savings(&self) -> bool { | 300 | pub fn get_daylight_savings(&self) -> bool { |
| 239 | let cr = RTC::regs().cr().read(); | 301 | let cr = RTC::regs().cr().read(); |
| @@ -315,3 +377,18 @@ trait SealedInstance { | |||
| 315 | 377 | ||
| 316 | // fn apply_config(&mut self, rtc_config: RtcConfig); | 378 | // fn apply_config(&mut self, rtc_config: RtcConfig); |
| 317 | } | 379 | } |
| 380 | |||
| 381 | #[cfg(feature = "low-power")] | ||
| 382 | pub(crate) fn init_rtc(cs: CriticalSection, config: RtcConfig, min_stop_pause: embassy_time::Duration) { | ||
| 383 | use crate::time_driver::get_driver; | ||
| 384 | |||
| 385 | #[cfg(feature = "_allow-disable-rtc")] | ||
| 386 | if config._disable_rtc { | ||
| 387 | return; | ||
| 388 | } | ||
| 389 | |||
| 390 | get_driver().set_rtc(cs, Rtc::new_inner(config)); | ||
| 391 | get_driver().set_min_stop_pause(cs, min_stop_pause); | ||
| 392 | |||
| 393 | trace!("low power: stop with rtc configured"); | ||
| 394 | } | ||
