aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxoviat <[email protected]>2023-08-10 18:59:18 -0500
committerxoviat <[email protected]>2023-08-10 18:59:18 -0500
commita0c69ffe024588aab3c4cca70a73275851967616 (patch)
tree84b07d257c607efbca039e55bf140b5650a09c0c
parent0705152105287a4c03ffdc21a460d1a26e67c9f6 (diff)
stm32/rtc: autocompute wakeup psc.
-rw-r--r--embassy-stm32/src/rtc/v2.rs96
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;
5use crate::peripherals::RTC; 5use crate::peripherals::RTC;
6use crate::rtc::sealed::Instance; 6use crate::rtc::sealed::Instance;
7 7
8#[derive(Clone, Copy)]
9pub(crate) enum WakeupPrescaler {
10 Div2,
11 Div4,
12 Div8,
13 Div16,
14}
15
16#[cfg(stm32wb)]
17impl 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)]
31impl 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
45impl 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
56impl 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
8impl super::Rtc { 71impl 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)]