diff options
| author | xoviat <[email protected]> | 2023-08-10 18:59:18 -0500 |
|---|---|---|
| committer | xoviat <[email protected]> | 2023-08-10 18:59:18 -0500 |
| commit | a0c69ffe024588aab3c4cca70a73275851967616 (patch) | |
| tree | 84b07d257c607efbca039e55bf140b5650a09c0c | |
| parent | 0705152105287a4c03ffdc21a460d1a26e67c9f6 (diff) | |
stm32/rtc: autocompute wakeup psc.
| -rw-r--r-- | embassy-stm32/src/rtc/v2.rs | 96 |
1 files changed, 80 insertions, 16 deletions
diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index f15ab806d..32ccb8453 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs | |||
| @@ -5,6 +5,69 @@ use crate::pac::rtc::Rtc; | |||
| 5 | use crate::peripherals::RTC; | 5 | use crate::peripherals::RTC; |
| 6 | use crate::rtc::sealed::Instance; | 6 | use crate::rtc::sealed::Instance; |
| 7 | 7 | ||
| 8 | #[derive(Clone, Copy)] | ||
| 9 | pub(crate) enum WakeupPrescaler { | ||
| 10 | Div2, | ||
| 11 | Div4, | ||
| 12 | Div8, | ||
| 13 | Div16, | ||
| 14 | } | ||
| 15 | |||
| 16 | #[cfg(stm32wb)] | ||
| 17 | impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel { | ||
| 18 | fn from(val: WakeupPrescaler) -> Self { | ||
| 19 | use crate::pac::rtc::vals::Wucksel; | ||
| 20 | |||
| 21 | match val { | ||
| 22 | WakeupPrescaler::Div2 => Wucksel::DIV2, | ||
| 23 | WakeupPrescaler::Div4 => Wucksel::DIV4, | ||
| 24 | WakeupPrescaler::Div8 => Wucksel::DIV8, | ||
| 25 | WakeupPrescaler::Div16 => Wucksel::DIV16, | ||
| 26 | } | ||
| 27 | } | ||
| 28 | } | ||
| 29 | |||
| 30 | #[cfg(stm32wb)] | ||
| 31 | impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler { | ||
| 32 | fn from(val: crate::pac::rtc::vals::Wucksel) -> Self { | ||
| 33 | use crate::pac::rtc::vals::Wucksel; | ||
| 34 | |||
| 35 | match val { | ||
| 36 | Wucksel::DIV2 => WakeupPrescaler::Div2, | ||
| 37 | Wucksel::DIV4 => WakeupPrescaler::Div4, | ||
| 38 | Wucksel::DIV8 => WakeupPrescaler::Div8, | ||
| 39 | Wucksel::DIV16 => WakeupPrescaler::Div16, | ||
| 40 | _ => unreachable!(), | ||
| 41 | } | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 45 | impl From<WakeupPrescaler> for u32 { | ||
| 46 | fn from(val: WakeupPrescaler) -> Self { | ||
| 47 | match val { | ||
| 48 | WakeupPrescaler::Div2 => 2, | ||
| 49 | WakeupPrescaler::Div4 => 4, | ||
| 50 | WakeupPrescaler::Div8 => 8, | ||
| 51 | WakeupPrescaler::Div16 => 16, | ||
| 52 | } | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | impl WakeupPrescaler { | ||
| 57 | pub fn compute_min(val: u32) -> Self { | ||
| 58 | *[ | ||
| 59 | WakeupPrescaler::Div2, | ||
| 60 | WakeupPrescaler::Div4, | ||
| 61 | WakeupPrescaler::Div8, | ||
| 62 | WakeupPrescaler::Div16, | ||
| 63 | ] | ||
| 64 | .iter() | ||
| 65 | .skip_while(|psc| <WakeupPrescaler as Into<u32>>::into(**psc) <= val) | ||
| 66 | .next() | ||
| 67 | .unwrap_or(&WakeupPrescaler::Div16) | ||
| 68 | } | ||
| 69 | } | ||
| 70 | |||
| 8 | impl super::Rtc { | 71 | impl super::Rtc { |
| 9 | fn unlock_registers() { | 72 | fn unlock_registers() { |
| 10 | #[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1))] | 73 | #[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1))] |
| @@ -24,44 +87,45 @@ impl super::Rtc { | |||
| 24 | 87 | ||
| 25 | #[allow(dead_code)] | 88 | #[allow(dead_code)] |
| 26 | #[cfg(all(feature = "time", stm32wb))] | 89 | #[cfg(all(feature = "time", stm32wb))] |
| 27 | // start the wakeup alarm with the given duration | 90 | /// start the wakeup alarm and return the actual duration of the alarm |
| 28 | pub(crate) fn start_wakeup_alarm(duration: embassy_time::Duration) { | 91 | /// the actual duration will be the closest value possible that is less |
| 29 | use embassy_time::TICK_HZ; | 92 | /// than the requested duration. |
| 30 | use stm32_metapac::rtc::vals::Wucksel; | 93 | pub(crate) fn start_wakeup_alarm(requested_duration: embassy_time::Duration) -> embassy_time::Duration { |
| 94 | use embassy_time::{Duration, TICK_HZ}; | ||
| 31 | 95 | ||
| 32 | use crate::interrupt::typelevel::Interrupt; | 96 | use crate::interrupt::typelevel::Interrupt; |
| 33 | use crate::rcc::get_freqs; | 97 | use crate::rcc::get_freqs; |
| 34 | 98 | ||
| 35 | let rtc_hz = unsafe { get_freqs() }.rtc.unwrap().0 as u64; | 99 | let rtc_hz = unsafe { get_freqs() }.rtc.unwrap().0 as u64; |
| 36 | 100 | ||
| 37 | // Choose the lowest prescaler available | 101 | let rtc_ticks = requested_duration.as_ticks() * rtc_hz / TICK_HZ; |
| 38 | #[cfg(stm32wb)] | 102 | let prescaler = WakeupPrescaler::compute_min((rtc_ticks / u16::MAX as u64) as u32); |
| 39 | let rtc_hz = rtc_hz / 2; | ||
| 40 | 103 | ||
| 41 | let rtc_ticks = duration.as_ticks() * rtc_hz / TICK_HZ; | 104 | // adjust the rtc ticks to the prescaler |
| 105 | let rtc_ticks = rtc_ticks / (<WakeupPrescaler as Into<u32>>::into(prescaler) as u64); | ||
| 42 | let rtc_ticks = if rtc_ticks > u16::MAX as u64 { | 106 | let rtc_ticks = if rtc_ticks > u16::MAX as u64 { |
| 43 | u16::MAX | 107 | u16::MAX |
| 44 | } else { | 108 | } else { |
| 45 | rtc_ticks as u16 | 109 | rtc_ticks as u16 |
| 46 | }; | 110 | }; |
| 47 | 111 | ||
| 48 | while !RTC::regs().isr().read().wutf() {} | 112 | let duration = Duration::from_ticks( |
| 49 | 113 | rtc_ticks as u64 * TICK_HZ * (<WakeupPrescaler as Into<u32>>::into(prescaler) as u64) / rtc_hz, | |
| 50 | RTC::regs().isr().modify(|w| w.set_wutf(false)); | 114 | ); |
| 51 | |||
| 52 | RTC::regs().wutr().modify(|w| w.set_wut(rtc_ticks)); | ||
| 53 | 115 | ||
| 54 | crate::interrupt::typelevel::RTC_WKUP::unpend(); | 116 | crate::interrupt::typelevel::RTC_WKUP::unpend(); |
| 55 | unsafe { crate::interrupt::typelevel::RTC_WKUP::enable() }; | 117 | unsafe { crate::interrupt::typelevel::RTC_WKUP::enable() }; |
| 56 | 118 | ||
| 119 | RTC::regs().wutr().modify(|w| w.set_wut(rtc_ticks)); | ||
| 120 | |||
| 57 | RTC::regs().cr().modify(|w| { | 121 | RTC::regs().cr().modify(|w| { |
| 58 | // Choose the lowest prescaler available | 122 | w.set_wucksel(prescaler.into()); |
| 59 | #[cfg(stm32wb)] | ||
| 60 | w.set_wucksel(Wucksel::DIV2); | ||
| 61 | 123 | ||
| 62 | w.set_wutie(true); | 124 | w.set_wutie(true); |
| 63 | w.set_wute(true); | 125 | w.set_wute(true); |
| 64 | }); | 126 | }); |
| 127 | |||
| 128 | duration | ||
| 65 | } | 129 | } |
| 66 | 130 | ||
| 67 | #[allow(dead_code)] | 131 | #[allow(dead_code)] |
