diff options
| author | Dario Nieuwenhuis <[email protected]> | 2024-05-30 13:26:14 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2024-05-30 13:26:14 +0200 |
| commit | 2c691baadd28f0072c606a843ba14db1ea08ef86 (patch) | |
| tree | 3a44ea990b8f9690bcd505a787023d533eb70d9b /embassy-stm32/src/rtc | |
| parent | c46172acac0be14b99148c2ec7aa38c9ac605fe1 (diff) | |
stm32/rtc: move lowpower stuff to a separate mod.
Diffstat (limited to 'embassy-stm32/src/rtc')
| -rw-r--r-- | embassy-stm32/src/rtc/datetime.rs | 59 | ||||
| -rw-r--r-- | embassy-stm32/src/rtc/low_power.rs | 230 | ||||
| -rw-r--r-- | embassy-stm32/src/rtc/mod.rs | 196 |
3 files changed, 236 insertions, 249 deletions
diff --git a/embassy-stm32/src/rtc/datetime.rs b/embassy-stm32/src/rtc/datetime.rs index 77d89293d..32732e96e 100644 --- a/embassy-stm32/src/rtc/datetime.rs +++ b/embassy-stm32/src/rtc/datetime.rs | |||
| @@ -1,65 +1,6 @@ | |||
| 1 | #[cfg(feature = "chrono")] | 1 | #[cfg(feature = "chrono")] |
| 2 | use chrono::{Datelike, NaiveDate, Timelike, Weekday}; | 2 | use chrono::{Datelike, NaiveDate, Timelike, Weekday}; |
| 3 | 3 | ||
| 4 | #[cfg(any(feature = "defmt", feature = "time"))] | ||
| 5 | use crate::peripherals::RTC; | ||
| 6 | #[cfg(any(feature = "defmt", feature = "time"))] | ||
| 7 | use crate::rtc::SealedInstance; | ||
| 8 | |||
| 9 | /// Represents an instant in time that can be substracted to compute a duration | ||
| 10 | pub struct RtcInstant { | ||
| 11 | /// 0..59 | ||
| 12 | pub second: u8, | ||
| 13 | /// 0..256 | ||
| 14 | pub subsecond: u16, | ||
| 15 | } | ||
| 16 | |||
| 17 | impl RtcInstant { | ||
| 18 | #[cfg(not(rtc_v2f2))] | ||
| 19 | pub(super) const fn from(second: u8, subsecond: u16) -> Result<Self, Error> { | ||
| 20 | if second > 59 { | ||
| 21 | Err(Error::InvalidSecond) | ||
| 22 | } else { | ||
| 23 | Ok(Self { second, subsecond }) | ||
| 24 | } | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | #[cfg(feature = "defmt")] | ||
| 29 | impl defmt::Format for RtcInstant { | ||
| 30 | fn format(&self, fmt: defmt::Formatter) { | ||
| 31 | defmt::write!( | ||
| 32 | fmt, | ||
| 33 | "{}:{}", | ||
| 34 | self.second, | ||
| 35 | RTC::regs().prer().read().prediv_s() - self.subsecond, | ||
| 36 | ) | ||
| 37 | } | ||
| 38 | } | ||
| 39 | |||
| 40 | #[cfg(feature = "time")] | ||
| 41 | impl core::ops::Sub for RtcInstant { | ||
| 42 | type Output = embassy_time::Duration; | ||
| 43 | |||
| 44 | fn sub(self, rhs: Self) -> Self::Output { | ||
| 45 | use embassy_time::{Duration, TICK_HZ}; | ||
| 46 | |||
| 47 | let second = if self.second < rhs.second { | ||
| 48 | self.second + 60 | ||
| 49 | } else { | ||
| 50 | self.second | ||
| 51 | }; | ||
| 52 | |||
| 53 | let psc = RTC::regs().prer().read().prediv_s() as u32; | ||
| 54 | |||
| 55 | let self_ticks = second as u32 * (psc + 1) + (psc - self.subsecond as u32); | ||
| 56 | let other_ticks = rhs.second as u32 * (psc + 1) + (psc - rhs.subsecond as u32); | ||
| 57 | let rtc_ticks = self_ticks - other_ticks; | ||
| 58 | |||
| 59 | Duration::from_ticks(((rtc_ticks * TICK_HZ as u32) / (psc + 1)) as u64) | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 63 | /// Errors regarding the [`DateTime`] struct. | 4 | /// Errors regarding the [`DateTime`] struct. |
| 64 | #[derive(Clone, Debug, PartialEq, Eq)] | 5 | #[derive(Clone, Debug, PartialEq, Eq)] |
| 65 | pub enum Error { | 6 | pub enum Error { |
diff --git a/embassy-stm32/src/rtc/low_power.rs b/embassy-stm32/src/rtc/low_power.rs new file mode 100644 index 000000000..a4ff1acbc --- /dev/null +++ b/embassy-stm32/src/rtc/low_power.rs | |||
| @@ -0,0 +1,230 @@ | |||
| 1 | use super::{bcd2_to_byte, DateTimeError, Rtc, RtcError}; | ||
| 2 | use crate::peripherals::RTC; | ||
| 3 | use crate::rtc::SealedInstance; | ||
| 4 | |||
| 5 | /// Represents an instant in time that can be substracted to compute a duration | ||
| 6 | pub(super) struct RtcInstant { | ||
| 7 | /// 0..59 | ||
| 8 | second: u8, | ||
| 9 | /// 0..256 | ||
| 10 | subsecond: u16, | ||
| 11 | } | ||
| 12 | |||
| 13 | impl RtcInstant { | ||
| 14 | #[cfg(not(rtc_v2f2))] | ||
| 15 | const fn from(second: u8, subsecond: u16) -> Result<Self, DateTimeError> { | ||
| 16 | if second > 59 { | ||
| 17 | Err(DateTimeError::InvalidSecond) | ||
| 18 | } else { | ||
| 19 | Ok(Self { second, subsecond }) | ||
| 20 | } | ||
| 21 | } | ||
| 22 | } | ||
| 23 | |||
| 24 | #[cfg(feature = "defmt")] | ||
| 25 | impl defmt::Format for RtcInstant { | ||
| 26 | fn format(&self, fmt: defmt::Formatter) { | ||
| 27 | defmt::write!( | ||
| 28 | fmt, | ||
| 29 | "{}:{}", | ||
| 30 | self.second, | ||
| 31 | RTC::regs().prer().read().prediv_s() - self.subsecond, | ||
| 32 | ) | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 36 | #[cfg(feature = "time")] | ||
| 37 | impl core::ops::Sub for RtcInstant { | ||
| 38 | type Output = embassy_time::Duration; | ||
| 39 | |||
| 40 | fn sub(self, rhs: Self) -> Self::Output { | ||
| 41 | use embassy_time::{Duration, TICK_HZ}; | ||
| 42 | |||
| 43 | let second = if self.second < rhs.second { | ||
| 44 | self.second + 60 | ||
| 45 | } else { | ||
| 46 | self.second | ||
| 47 | }; | ||
| 48 | |||
| 49 | let psc = RTC::regs().prer().read().prediv_s() as u32; | ||
| 50 | |||
| 51 | let self_ticks = second as u32 * (psc + 1) + (psc - self.subsecond as u32); | ||
| 52 | let other_ticks = rhs.second as u32 * (psc + 1) + (psc - rhs.subsecond as u32); | ||
| 53 | let rtc_ticks = self_ticks - other_ticks; | ||
| 54 | |||
| 55 | Duration::from_ticks(((rtc_ticks * TICK_HZ as u32) / (psc + 1)) as u64) | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | #[repr(u8)] | ||
| 60 | #[derive(Clone, Copy, Debug)] | ||
| 61 | pub(crate) enum WakeupPrescaler { | ||
| 62 | Div2 = 2, | ||
| 63 | Div4 = 4, | ||
| 64 | Div8 = 8, | ||
| 65 | Div16 = 16, | ||
| 66 | } | ||
| 67 | |||
| 68 | #[cfg(any(stm32f4, stm32l0, stm32g4, stm32l5, stm32wb, stm32h5, stm32g0))] | ||
| 69 | impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel { | ||
| 70 | fn from(val: WakeupPrescaler) -> Self { | ||
| 71 | use crate::pac::rtc::vals::Wucksel; | ||
| 72 | |||
| 73 | match val { | ||
| 74 | WakeupPrescaler::Div2 => Wucksel::DIV2, | ||
| 75 | WakeupPrescaler::Div4 => Wucksel::DIV4, | ||
| 76 | WakeupPrescaler::Div8 => Wucksel::DIV8, | ||
| 77 | WakeupPrescaler::Div16 => Wucksel::DIV16, | ||
| 78 | } | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 82 | #[cfg(any(stm32f4, stm32l0, stm32g4, stm32l5, stm32wb, stm32h5, stm32g0))] | ||
| 83 | impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler { | ||
| 84 | fn from(val: crate::pac::rtc::vals::Wucksel) -> Self { | ||
| 85 | use crate::pac::rtc::vals::Wucksel; | ||
| 86 | |||
| 87 | match val { | ||
| 88 | Wucksel::DIV2 => WakeupPrescaler::Div2, | ||
| 89 | Wucksel::DIV4 => WakeupPrescaler::Div4, | ||
| 90 | Wucksel::DIV8 => WakeupPrescaler::Div8, | ||
| 91 | Wucksel::DIV16 => WakeupPrescaler::Div16, | ||
| 92 | _ => unreachable!(), | ||
| 93 | } | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 97 | impl WakeupPrescaler { | ||
| 98 | pub fn compute_min(val: u32) -> Self { | ||
| 99 | *[ | ||
| 100 | WakeupPrescaler::Div2, | ||
| 101 | WakeupPrescaler::Div4, | ||
| 102 | WakeupPrescaler::Div8, | ||
| 103 | WakeupPrescaler::Div16, | ||
| 104 | ] | ||
| 105 | .iter() | ||
| 106 | .find(|psc| **psc as u32 > val) | ||
| 107 | .unwrap_or(&WakeupPrescaler::Div16) | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 111 | impl Rtc { | ||
| 112 | /// Return the current instant. | ||
| 113 | fn instant(&self) -> Result<RtcInstant, RtcError> { | ||
| 114 | self.time_provider().read(|_, tr, ss| { | ||
| 115 | let second = bcd2_to_byte((tr.st(), tr.su())); | ||
| 116 | |||
| 117 | RtcInstant::from(second, ss).map_err(RtcError::InvalidDateTime) | ||
| 118 | }) | ||
| 119 | } | ||
| 120 | |||
| 121 | /// start the wakeup alarm and with a duration that is as close to but less than | ||
| 122 | /// the requested duration, and record the instant the wakeup alarm was started | ||
| 123 | pub(crate) fn start_wakeup_alarm( | ||
| 124 | &self, | ||
| 125 | requested_duration: embassy_time::Duration, | ||
| 126 | cs: critical_section::CriticalSection, | ||
| 127 | ) { | ||
| 128 | use embassy_time::{Duration, TICK_HZ}; | ||
| 129 | |||
| 130 | #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))] | ||
| 131 | use crate::pac::rtc::vals::Calrf; | ||
| 132 | |||
| 133 | // Panic if the rcc mod knows we're not using low-power rtc | ||
| 134 | #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] | ||
| 135 | unsafe { crate::rcc::get_freqs() }.rtc.unwrap(); | ||
| 136 | |||
| 137 | let requested_duration = requested_duration.as_ticks().clamp(0, u32::MAX as u64); | ||
| 138 | let rtc_hz = Self::frequency().0 as u64; | ||
| 139 | let rtc_ticks = requested_duration * rtc_hz / TICK_HZ; | ||
| 140 | let prescaler = WakeupPrescaler::compute_min((rtc_ticks / u16::MAX as u64) as u32); | ||
| 141 | |||
| 142 | // adjust the rtc ticks to the prescaler and subtract one rtc tick | ||
| 143 | let rtc_ticks = rtc_ticks / prescaler as u64; | ||
| 144 | let rtc_ticks = rtc_ticks.clamp(0, (u16::MAX - 1) as u64).saturating_sub(1) as u16; | ||
| 145 | |||
| 146 | self.write(false, |regs| { | ||
| 147 | regs.cr().modify(|w| w.set_wute(false)); | ||
| 148 | |||
| 149 | #[cfg(any( | ||
| 150 | rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb | ||
| 151 | ))] | ||
| 152 | { | ||
| 153 | regs.isr().modify(|w| w.set_wutf(false)); | ||
| 154 | while !regs.isr().read().wutwf() {} | ||
| 155 | } | ||
| 156 | |||
| 157 | #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))] | ||
| 158 | { | ||
| 159 | regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR)); | ||
| 160 | while !regs.icsr().read().wutwf() {} | ||
| 161 | } | ||
| 162 | |||
| 163 | regs.cr().modify(|w| w.set_wucksel(prescaler.into())); | ||
| 164 | regs.wutr().write(|w| w.set_wut(rtc_ticks)); | ||
| 165 | regs.cr().modify(|w| w.set_wute(true)); | ||
| 166 | regs.cr().modify(|w| w.set_wutie(true)); | ||
| 167 | }); | ||
| 168 | |||
| 169 | let instant = self.instant().unwrap(); | ||
| 170 | trace!( | ||
| 171 | "rtc: start wakeup alarm for {} ms (psc: {}, ticks: {}) at {}", | ||
| 172 | Duration::from_ticks(rtc_ticks as u64 * TICK_HZ * prescaler as u64 / rtc_hz).as_millis(), | ||
| 173 | prescaler as u32, | ||
| 174 | rtc_ticks, | ||
| 175 | instant, | ||
| 176 | ); | ||
| 177 | |||
| 178 | assert!(self.stop_time.borrow(cs).replace(Some(instant)).is_none()) | ||
| 179 | } | ||
| 180 | |||
| 181 | /// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm` | ||
| 182 | /// was called, otherwise none | ||
| 183 | pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option<embassy_time::Duration> { | ||
| 184 | use crate::interrupt::typelevel::Interrupt; | ||
| 185 | #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))] | ||
| 186 | use crate::pac::rtc::vals::Calrf; | ||
| 187 | |||
| 188 | let instant = self.instant().unwrap(); | ||
| 189 | if RTC::regs().cr().read().wute() { | ||
| 190 | trace!("rtc: stop wakeup alarm at {}", instant); | ||
| 191 | |||
| 192 | self.write(false, |regs| { | ||
| 193 | regs.cr().modify(|w| w.set_wutie(false)); | ||
| 194 | regs.cr().modify(|w| w.set_wute(false)); | ||
| 195 | |||
| 196 | #[cfg(any( | ||
| 197 | rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb | ||
| 198 | ))] | ||
| 199 | regs.isr().modify(|w| w.set_wutf(false)); | ||
| 200 | |||
| 201 | #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))] | ||
| 202 | regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR)); | ||
| 203 | |||
| 204 | // Check RM for EXTI and/or NVIC section, "Event event input mapping" or "EXTI interrupt/event mapping" or something similar, | ||
| 205 | // there is a table for every "Event input" / "EXTI Line". | ||
| 206 | // If you find the EXTI line related to "RTC wakeup" marks as "Configurable" (not "Direct"), | ||
| 207 | // then write 1 to related field of Pending Register, to clean it's pending state. | ||
| 208 | #[cfg(any(exti_v1, stm32h7, stm32wb))] | ||
| 209 | crate::pac::EXTI | ||
| 210 | .pr(0) | ||
| 211 | .modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); | ||
| 212 | |||
| 213 | <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::unpend(); | ||
| 214 | }); | ||
| 215 | } | ||
| 216 | |||
| 217 | self.stop_time.borrow(cs).take().map(|stop_time| instant - stop_time) | ||
| 218 | } | ||
| 219 | |||
| 220 | pub(crate) fn enable_wakeup_line(&self) { | ||
| 221 | use crate::interrupt::typelevel::Interrupt; | ||
| 222 | use crate::pac::EXTI; | ||
| 223 | |||
| 224 | <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::unpend(); | ||
| 225 | unsafe { <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::enable() }; | ||
| 226 | |||
| 227 | EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); | ||
| 228 | EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); | ||
| 229 | } | ||
| 230 | } | ||
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 92a58ee9a..cb9c10676 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs | |||
| @@ -2,6 +2,9 @@ | |||
| 2 | mod datetime; | 2 | mod datetime; |
| 3 | 3 | ||
| 4 | #[cfg(feature = "low-power")] | 4 | #[cfg(feature = "low-power")] |
| 5 | mod low_power; | ||
| 6 | |||
| 7 | #[cfg(feature = "low-power")] | ||
| 5 | use core::cell::Cell; | 8 | use core::cell::Cell; |
| 6 | 9 | ||
| 7 | #[cfg(feature = "low-power")] | 10 | #[cfg(feature = "low-power")] |
| @@ -9,8 +12,6 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | |||
| 9 | #[cfg(feature = "low-power")] | 12 | #[cfg(feature = "low-power")] |
| 10 | use embassy_sync::blocking_mutex::Mutex; | 13 | use embassy_sync::blocking_mutex::Mutex; |
| 11 | 14 | ||
| 12 | #[cfg(not(rtc_v2f2))] | ||
| 13 | use self::datetime::RtcInstant; | ||
| 14 | use self::datetime::{day_of_week_from_u8, day_of_week_to_u8}; | 15 | use self::datetime::{day_of_week_from_u8, day_of_week_to_u8}; |
| 15 | pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; | 16 | pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; |
| 16 | use crate::pac::rtc::regs::{Dr, Tr}; | 17 | use crate::pac::rtc::regs::{Dr, Tr}; |
| @@ -32,60 +33,6 @@ use embassy_hal_internal::Peripheral; | |||
| 32 | 33 | ||
| 33 | use crate::peripherals::RTC; | 34 | use crate::peripherals::RTC; |
| 34 | 35 | ||
| 35 | #[allow(dead_code)] | ||
| 36 | #[repr(u8)] | ||
| 37 | #[derive(Clone, Copy, Debug)] | ||
| 38 | pub(crate) enum WakeupPrescaler { | ||
| 39 | Div2 = 2, | ||
| 40 | Div4 = 4, | ||
| 41 | Div8 = 8, | ||
| 42 | Div16 = 16, | ||
| 43 | } | ||
| 44 | |||
| 45 | #[cfg(any(stm32f4, stm32l0, stm32g4, stm32l5, stm32wb, stm32h5, stm32g0))] | ||
| 46 | impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel { | ||
| 47 | fn from(val: WakeupPrescaler) -> Self { | ||
| 48 | use crate::pac::rtc::vals::Wucksel; | ||
| 49 | |||
| 50 | match val { | ||
| 51 | WakeupPrescaler::Div2 => Wucksel::DIV2, | ||
| 52 | WakeupPrescaler::Div4 => Wucksel::DIV4, | ||
| 53 | WakeupPrescaler::Div8 => Wucksel::DIV8, | ||
| 54 | WakeupPrescaler::Div16 => Wucksel::DIV16, | ||
| 55 | } | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | #[cfg(any(stm32f4, stm32l0, stm32g4, stm32l5, stm32wb, stm32h5, stm32g0))] | ||
| 60 | impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler { | ||
| 61 | fn from(val: crate::pac::rtc::vals::Wucksel) -> Self { | ||
| 62 | use crate::pac::rtc::vals::Wucksel; | ||
| 63 | |||
| 64 | match val { | ||
| 65 | Wucksel::DIV2 => WakeupPrescaler::Div2, | ||
| 66 | Wucksel::DIV4 => WakeupPrescaler::Div4, | ||
| 67 | Wucksel::DIV8 => WakeupPrescaler::Div8, | ||
| 68 | Wucksel::DIV16 => WakeupPrescaler::Div16, | ||
| 69 | _ => unreachable!(), | ||
| 70 | } | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 74 | #[cfg(feature = "low-power")] | ||
| 75 | impl WakeupPrescaler { | ||
| 76 | pub fn compute_min(val: u32) -> Self { | ||
| 77 | *[ | ||
| 78 | WakeupPrescaler::Div2, | ||
| 79 | WakeupPrescaler::Div4, | ||
| 80 | WakeupPrescaler::Div8, | ||
| 81 | WakeupPrescaler::Div16, | ||
| 82 | ] | ||
| 83 | .iter() | ||
| 84 | .find(|psc| **psc as u32 > val) | ||
| 85 | .unwrap_or(&WakeupPrescaler::Div16) | ||
| 86 | } | ||
| 87 | } | ||
| 88 | |||
| 89 | /// Errors that can occur on methods on [RtcClock] | 36 | /// Errors that can occur on methods on [RtcClock] |
| 90 | #[non_exhaustive] | 37 | #[non_exhaustive] |
| 91 | #[derive(Clone, Debug, PartialEq, Eq)] | 38 | #[derive(Clone, Debug, PartialEq, Eq)] |
| @@ -106,15 +53,6 @@ pub struct RtcTimeProvider { | |||
| 106 | } | 53 | } |
| 107 | 54 | ||
| 108 | impl RtcTimeProvider { | 55 | impl RtcTimeProvider { |
| 109 | #[cfg(not(rtc_v2f2))] | ||
| 110 | pub(crate) fn instant(&self) -> Result<RtcInstant, RtcError> { | ||
| 111 | self.read(|_, tr, ss| { | ||
| 112 | let second = bcd2_to_byte((tr.st(), tr.su())); | ||
| 113 | |||
| 114 | RtcInstant::from(second, ss).map_err(RtcError::InvalidDateTime) | ||
| 115 | }) | ||
| 116 | } | ||
| 117 | |||
| 118 | /// Return the current datetime. | 56 | /// Return the current datetime. |
| 119 | /// | 57 | /// |
| 120 | /// # Errors | 58 | /// # Errors |
| @@ -165,8 +103,7 @@ impl RtcTimeProvider { | |||
| 165 | /// RTC driver. | 103 | /// RTC driver. |
| 166 | pub struct Rtc { | 104 | pub struct Rtc { |
| 167 | #[cfg(feature = "low-power")] | 105 | #[cfg(feature = "low-power")] |
| 168 | stop_time: Mutex<CriticalSectionRawMutex, Cell<Option<RtcInstant>>>, | 106 | stop_time: Mutex<CriticalSectionRawMutex, Cell<Option<low_power::RtcInstant>>>, |
| 169 | #[cfg(not(feature = "low-power"))] | ||
| 170 | _private: (), | 107 | _private: (), |
| 171 | } | 108 | } |
| 172 | 109 | ||
| @@ -210,7 +147,6 @@ impl Rtc { | |||
| 210 | let mut this = Self { | 147 | let mut this = Self { |
| 211 | #[cfg(feature = "low-power")] | 148 | #[cfg(feature = "low-power")] |
| 212 | stop_time: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), | 149 | stop_time: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), |
| 213 | #[cfg(not(feature = "low-power"))] | ||
| 214 | _private: (), | 150 | _private: (), |
| 215 | }; | 151 | }; |
| 216 | 152 | ||
| @@ -223,9 +159,8 @@ impl Rtc { | |||
| 223 | // Wait for the clock to update after initialization | 159 | // Wait for the clock to update after initialization |
| 224 | #[cfg(not(rtc_v2f2))] | 160 | #[cfg(not(rtc_v2f2))] |
| 225 | { | 161 | { |
| 226 | let now = this.instant().unwrap(); | 162 | let now = this.time_provider().read(|_, _, ss| Ok(ss)).unwrap(); |
| 227 | 163 | while now == this.time_provider().read(|_, _, ss| Ok(ss)).unwrap() {} | |
| 228 | while this.instant().unwrap().subsecond == now.subsecond {} | ||
| 229 | } | 164 | } |
| 230 | 165 | ||
| 231 | this | 166 | this |
| @@ -284,12 +219,6 @@ impl Rtc { | |||
| 284 | Ok(()) | 219 | Ok(()) |
| 285 | } | 220 | } |
| 286 | 221 | ||
| 287 | #[cfg(not(rtc_v2f2))] | ||
| 288 | /// Return the current instant. | ||
| 289 | fn instant(&self) -> Result<RtcInstant, RtcError> { | ||
| 290 | self.time_provider().instant() | ||
| 291 | } | ||
| 292 | |||
| 293 | /// Return the current datetime. | 222 | /// Return the current datetime. |
| 294 | /// | 223 | /// |
| 295 | /// # Errors | 224 | /// # Errors |
| @@ -330,119 +259,6 @@ impl Rtc { | |||
| 330 | pub fn write_backup_register(&self, register: usize, value: u32) { | 259 | pub fn write_backup_register(&self, register: usize, value: u32) { |
| 331 | RTC::write_backup_register(RTC::regs(), register, value) | 260 | RTC::write_backup_register(RTC::regs(), register, value) |
| 332 | } | 261 | } |
| 333 | |||
| 334 | #[cfg(feature = "low-power")] | ||
| 335 | /// start the wakeup alarm and with a duration that is as close to but less than | ||
| 336 | /// the requested duration, and record the instant the wakeup alarm was started | ||
| 337 | pub(crate) fn start_wakeup_alarm( | ||
| 338 | &self, | ||
| 339 | requested_duration: embassy_time::Duration, | ||
| 340 | cs: critical_section::CriticalSection, | ||
| 341 | ) { | ||
| 342 | use embassy_time::{Duration, TICK_HZ}; | ||
| 343 | |||
| 344 | #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))] | ||
| 345 | use crate::pac::rtc::vals::Calrf; | ||
| 346 | |||
| 347 | // Panic if the rcc mod knows we're not using low-power rtc | ||
| 348 | #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] | ||
| 349 | unsafe { crate::rcc::get_freqs() }.rtc.unwrap(); | ||
| 350 | |||
| 351 | let requested_duration = requested_duration.as_ticks().clamp(0, u32::MAX as u64); | ||
| 352 | let rtc_hz = Self::frequency().0 as u64; | ||
| 353 | let rtc_ticks = requested_duration * rtc_hz / TICK_HZ; | ||
| 354 | let prescaler = WakeupPrescaler::compute_min((rtc_ticks / u16::MAX as u64) as u32); | ||
| 355 | |||
| 356 | // adjust the rtc ticks to the prescaler and subtract one rtc tick | ||
| 357 | let rtc_ticks = rtc_ticks / prescaler as u64; | ||
| 358 | let rtc_ticks = rtc_ticks.clamp(0, (u16::MAX - 1) as u64).saturating_sub(1) as u16; | ||
| 359 | |||
| 360 | self.write(false, |regs| { | ||
| 361 | regs.cr().modify(|w| w.set_wute(false)); | ||
| 362 | |||
| 363 | #[cfg(any( | ||
| 364 | rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb | ||
| 365 | ))] | ||
| 366 | { | ||
| 367 | regs.isr().modify(|w| w.set_wutf(false)); | ||
| 368 | while !regs.isr().read().wutwf() {} | ||
| 369 | } | ||
| 370 | |||
| 371 | #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))] | ||
| 372 | { | ||
| 373 | regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR)); | ||
| 374 | while !regs.icsr().read().wutwf() {} | ||
| 375 | } | ||
| 376 | |||
| 377 | regs.cr().modify(|w| w.set_wucksel(prescaler.into())); | ||
| 378 | regs.wutr().write(|w| w.set_wut(rtc_ticks)); | ||
| 379 | regs.cr().modify(|w| w.set_wute(true)); | ||
| 380 | regs.cr().modify(|w| w.set_wutie(true)); | ||
| 381 | }); | ||
| 382 | |||
| 383 | let instant = self.instant().unwrap(); | ||
| 384 | trace!( | ||
| 385 | "rtc: start wakeup alarm for {} ms (psc: {}, ticks: {}) at {}", | ||
| 386 | Duration::from_ticks(rtc_ticks as u64 * TICK_HZ * prescaler as u64 / rtc_hz).as_millis(), | ||
| 387 | prescaler as u32, | ||
| 388 | rtc_ticks, | ||
| 389 | instant, | ||
| 390 | ); | ||
| 391 | |||
| 392 | assert!(self.stop_time.borrow(cs).replace(Some(instant)).is_none()) | ||
| 393 | } | ||
| 394 | |||
| 395 | #[cfg(feature = "low-power")] | ||
| 396 | /// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm` | ||
| 397 | /// was called, otherwise none | ||
| 398 | pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option<embassy_time::Duration> { | ||
| 399 | use crate::interrupt::typelevel::Interrupt; | ||
| 400 | #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))] | ||
| 401 | use crate::pac::rtc::vals::Calrf; | ||
| 402 | |||
| 403 | let instant = self.instant().unwrap(); | ||
| 404 | if RTC::regs().cr().read().wute() { | ||
| 405 | trace!("rtc: stop wakeup alarm at {}", instant); | ||
| 406 | |||
| 407 | self.write(false, |regs| { | ||
| 408 | regs.cr().modify(|w| w.set_wutie(false)); | ||
| 409 | regs.cr().modify(|w| w.set_wute(false)); | ||
| 410 | |||
| 411 | #[cfg(any( | ||
| 412 | rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb | ||
| 413 | ))] | ||
| 414 | regs.isr().modify(|w| w.set_wutf(false)); | ||
| 415 | |||
| 416 | #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))] | ||
| 417 | regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR)); | ||
| 418 | |||
| 419 | // Check RM for EXTI and/or NVIC section, "Event event input mapping" or "EXTI interrupt/event mapping" or something similar, | ||
| 420 | // there is a table for every "Event input" / "EXTI Line". | ||
| 421 | // If you find the EXTI line related to "RTC wakeup" marks as "Configurable" (not "Direct"), | ||
| 422 | // then write 1 to related field of Pending Register, to clean it's pending state. | ||
| 423 | #[cfg(any(exti_v1, stm32h7, stm32wb))] | ||
| 424 | crate::pac::EXTI | ||
| 425 | .pr(0) | ||
| 426 | .modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); | ||
| 427 | |||
| 428 | <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::unpend(); | ||
| 429 | }); | ||
| 430 | } | ||
| 431 | |||
| 432 | self.stop_time.borrow(cs).take().map(|stop_time| instant - stop_time) | ||
| 433 | } | ||
| 434 | |||
| 435 | #[cfg(feature = "low-power")] | ||
| 436 | pub(crate) fn enable_wakeup_line(&self) { | ||
| 437 | use crate::interrupt::typelevel::Interrupt; | ||
| 438 | use crate::pac::EXTI; | ||
| 439 | |||
| 440 | <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::unpend(); | ||
| 441 | unsafe { <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::enable() }; | ||
| 442 | |||
| 443 | EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); | ||
| 444 | EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); | ||
| 445 | } | ||
| 446 | } | 262 | } |
| 447 | 263 | ||
| 448 | pub(crate) fn byte_to_bcd2(byte: u8) -> (u8, u8) { | 264 | pub(crate) fn byte_to_bcd2(byte: u8) -> (u8, u8) { |
