diff options
| author | xoviat <[email protected]> | 2025-11-15 17:48:20 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-11-15 17:48:20 +0000 |
| commit | 933e27d99aaa4869aa601d6ac0f68b6e79788d3e (patch) | |
| tree | 433c03f159bbf7e811ff0bfb02c08950c41c24fa | |
| parent | 6600c2f88356a4535b3bf66e626a9ad605330f57 (diff) | |
| parent | c3a2ea8424c19c0b653e8c778645d7455ec714b1 (diff) | |
Merge pull request #4889 from xoviat/time
cleanup low_power add_time function
| -rw-r--r-- | embassy-stm32/CHANGELOG.md | 1 | ||||
| -rw-r--r-- | embassy-stm32/src/rtc/low_power.rs | 69 | ||||
| -rw-r--r-- | embassy-stm32/src/time_driver.rs | 33 |
3 files changed, 21 insertions, 82 deletions
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index c3b3cb3ab..72fe1c7a8 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md | |||
| @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 7 | 7 | ||
| 8 | ## Unreleased - ReleaseDate | 8 | ## Unreleased - ReleaseDate |
| 9 | 9 | ||
| 10 | - chore: cleanup low-power add time | ||
| 10 | - fix: Allow setting SAI peripheral `frame_length` to `256` | 11 | - fix: Allow setting SAI peripheral `frame_length` to `256` |
| 11 | - fix: flash erase on dual-bank STM32Gxxx | 12 | - fix: flash erase on dual-bank STM32Gxxx |
| 12 | - feat: Add support for STM32N657X0 | 13 | - feat: Add support for STM32N657X0 |
diff --git a/embassy-stm32/src/rtc/low_power.rs b/embassy-stm32/src/rtc/low_power.rs index e5bf30927..f049d6b12 100644 --- a/embassy-stm32/src/rtc/low_power.rs +++ b/embassy-stm32/src/rtc/low_power.rs | |||
| @@ -3,6 +3,7 @@ use embassy_time::{Duration, TICK_HZ}; | |||
| 3 | 3 | ||
| 4 | use super::{DateTimeError, Rtc, RtcError, bcd2_to_byte}; | 4 | use super::{DateTimeError, Rtc, RtcError, bcd2_to_byte}; |
| 5 | use crate::interrupt::typelevel::Interrupt; | 5 | use crate::interrupt::typelevel::Interrupt; |
| 6 | use crate::pac::rtc::vals::Wucksel; | ||
| 6 | use crate::peripherals::RTC; | 7 | use crate::peripherals::RTC; |
| 7 | use crate::rtc::{RtcTimeProvider, SealedInstance}; | 8 | use crate::rtc::{RtcTimeProvider, SealedInstance}; |
| 8 | 9 | ||
| @@ -58,60 +59,16 @@ impl core::ops::Sub for RtcInstant { | |||
| 58 | } | 59 | } |
| 59 | } | 60 | } |
| 60 | 61 | ||
| 61 | #[repr(u8)] | 62 | fn wucksel_compute_min(val: u32) -> (Wucksel, u32) { |
| 62 | #[derive(Clone, Copy, Debug)] | 63 | *[ |
| 63 | pub(crate) enum WakeupPrescaler { | 64 | (Wucksel::DIV2, 2), |
| 64 | Div2 = 2, | 65 | (Wucksel::DIV4, 4), |
| 65 | Div4 = 4, | 66 | (Wucksel::DIV8, 8), |
| 66 | Div8 = 8, | 67 | (Wucksel::DIV16, 16), |
| 67 | Div16 = 16, | 68 | ] |
| 68 | } | 69 | .iter() |
| 69 | 70 | .find(|(_, psc)| *psc as u32 > val) | |
| 70 | #[cfg(any( | 71 | .unwrap_or(&(Wucksel::DIV16, 16)) |
| 71 | stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5, stm32u0, stm32wba, stm32wlex | ||
| 72 | ))] | ||
| 73 | impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel { | ||
| 74 | fn from(val: WakeupPrescaler) -> Self { | ||
| 75 | use crate::pac::rtc::vals::Wucksel; | ||
| 76 | |||
| 77 | match val { | ||
| 78 | WakeupPrescaler::Div2 => Wucksel::DIV2, | ||
| 79 | WakeupPrescaler::Div4 => Wucksel::DIV4, | ||
| 80 | WakeupPrescaler::Div8 => Wucksel::DIV8, | ||
| 81 | WakeupPrescaler::Div16 => Wucksel::DIV16, | ||
| 82 | } | ||
| 83 | } | ||
| 84 | } | ||
| 85 | |||
| 86 | #[cfg(any( | ||
| 87 | stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5, stm32u0, stm32wba, stm32wlex | ||
| 88 | ))] | ||
| 89 | impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler { | ||
| 90 | fn from(val: crate::pac::rtc::vals::Wucksel) -> Self { | ||
| 91 | use crate::pac::rtc::vals::Wucksel; | ||
| 92 | |||
| 93 | match val { | ||
| 94 | Wucksel::DIV2 => WakeupPrescaler::Div2, | ||
| 95 | Wucksel::DIV4 => WakeupPrescaler::Div4, | ||
| 96 | Wucksel::DIV8 => WakeupPrescaler::Div8, | ||
| 97 | Wucksel::DIV16 => WakeupPrescaler::Div16, | ||
| 98 | _ => unreachable!(), | ||
| 99 | } | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | impl WakeupPrescaler { | ||
| 104 | pub fn compute_min(val: u32) -> Self { | ||
| 105 | *[ | ||
| 106 | WakeupPrescaler::Div2, | ||
| 107 | WakeupPrescaler::Div4, | ||
| 108 | WakeupPrescaler::Div8, | ||
| 109 | WakeupPrescaler::Div16, | ||
| 110 | ] | ||
| 111 | .iter() | ||
| 112 | .find(|psc| **psc as u32 > val) | ||
| 113 | .unwrap_or(&WakeupPrescaler::Div16) | ||
| 114 | } | ||
| 115 | } | 72 | } |
| 116 | 73 | ||
| 117 | impl Rtc { | 74 | impl Rtc { |
| @@ -138,7 +95,7 @@ impl Rtc { | |||
| 138 | let requested_duration = requested_duration.as_ticks().clamp(0, u32::MAX as u64); | 95 | let requested_duration = requested_duration.as_ticks().clamp(0, u32::MAX as u64); |
| 139 | let rtc_hz = Self::frequency().0 as u64; | 96 | let rtc_hz = Self::frequency().0 as u64; |
| 140 | let rtc_ticks = requested_duration * rtc_hz / TICK_HZ; | 97 | let rtc_ticks = requested_duration * rtc_hz / TICK_HZ; |
| 141 | let prescaler = WakeupPrescaler::compute_min((rtc_ticks / u16::MAX as u64) as u32); | 98 | let (wucksel, prescaler) = wucksel_compute_min((rtc_ticks / u16::MAX as u64) as u32); |
| 142 | 99 | ||
| 143 | // adjust the rtc ticks to the prescaler and subtract one rtc tick | 100 | // adjust the rtc ticks to the prescaler and subtract one rtc tick |
| 144 | let rtc_ticks = rtc_ticks / prescaler as u64; | 101 | let rtc_ticks = rtc_ticks / prescaler as u64; |
| @@ -159,7 +116,7 @@ impl Rtc { | |||
| 159 | while !regs.icsr().read().wutwf() {} | 116 | while !regs.icsr().read().wutwf() {} |
| 160 | } | 117 | } |
| 161 | 118 | ||
| 162 | regs.cr().modify(|w| w.set_wucksel(prescaler.into())); | 119 | regs.cr().modify(|w| w.set_wucksel(wucksel)); |
| 163 | regs.wutr().write(|w| w.set_wut(rtc_ticks)); | 120 | regs.wutr().write(|w| w.set_wut(rtc_ticks)); |
| 164 | regs.cr().modify(|w| w.set_wute(true)); | 121 | regs.cr().modify(|w| w.set_wute(true)); |
| 165 | regs.cr().modify(|w| w.set_wutie(true)); | 122 | regs.cr().modify(|w| w.set_wutie(true)); |
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 7db51d72e..bc34892ee 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs | |||
| @@ -196,6 +196,11 @@ fn calc_now(period: u32, counter: u16) -> u64 { | |||
| 196 | ((period as u64) << 15) + ((counter as u32 ^ ((period & 1) << 15)) as u64) | 196 | ((period as u64) << 15) + ((counter as u32 ^ ((period & 1) << 15)) as u64) |
| 197 | } | 197 | } |
| 198 | 198 | ||
| 199 | #[cfg(feature = "low-power")] | ||
| 200 | fn calc_period_counter(ticks: u64) -> (u32, u16) { | ||
| 201 | (2 * (ticks >> 16) as u32 + (ticks as u16 >= 0x8000) as u32, ticks as u16) | ||
| 202 | } | ||
| 203 | |||
| 199 | struct AlarmState { | 204 | struct AlarmState { |
| 200 | timestamp: Cell<u64>, | 205 | timestamp: Cell<u64>, |
| 201 | } | 206 | } |
| @@ -358,34 +363,10 @@ impl RtcDriver { | |||
| 358 | #[cfg(feature = "low-power")] | 363 | #[cfg(feature = "low-power")] |
| 359 | /// Add the given offset to the current time | 364 | /// Add the given offset to the current time |
| 360 | fn add_time(&self, offset: embassy_time::Duration, cs: CriticalSection) { | 365 | fn add_time(&self, offset: embassy_time::Duration, cs: CriticalSection) { |
| 361 | let offset = offset.as_ticks(); | 366 | let (period, counter) = calc_period_counter(self.now() + offset.as_ticks()); |
| 362 | let cnt = regs_gp16().cnt().read().cnt() as u32; | ||
| 363 | let period = self.period.load(Ordering::SeqCst); | ||
| 364 | |||
| 365 | // Correct the race, if it exists | ||
| 366 | let period = if period & 1 == 1 && cnt < u16::MAX as u32 / 2 { | ||
| 367 | period + 1 | ||
| 368 | } else { | ||
| 369 | period | ||
| 370 | }; | ||
| 371 | |||
| 372 | // Normalize to the full overflow | ||
| 373 | let period = (period / 2) * 2; | ||
| 374 | |||
| 375 | // Add the offset | ||
| 376 | let period = period + 2 * (offset / u16::MAX as u64) as u32; | ||
| 377 | let cnt = cnt + (offset % u16::MAX as u64) as u32; | ||
| 378 | |||
| 379 | let (cnt, period) = if cnt > u16::MAX as u32 { | ||
| 380 | (cnt - u16::MAX as u32, period + 2) | ||
| 381 | } else { | ||
| 382 | (cnt, period) | ||
| 383 | }; | ||
| 384 | |||
| 385 | let period = if cnt > u16::MAX as u32 / 2 { period + 1 } else { period }; | ||
| 386 | 367 | ||
| 387 | self.period.store(period, Ordering::SeqCst); | 368 | self.period.store(period, Ordering::SeqCst); |
| 388 | regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16)); | 369 | regs_gp16().cnt().write(|w| w.set_cnt(counter)); |
| 389 | 370 | ||
| 390 | // Now, recompute alarm | 371 | // Now, recompute alarm |
| 391 | let alarm = self.alarm.borrow(cs); | 372 | let alarm = self.alarm.borrow(cs); |
