aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxoviat <[email protected]>2025-11-15 17:48:20 +0000
committerGitHub <[email protected]>2025-11-15 17:48:20 +0000
commit933e27d99aaa4869aa601d6ac0f68b6e79788d3e (patch)
tree433c03f159bbf7e811ff0bfb02c08950c41c24fa
parent6600c2f88356a4535b3bf66e626a9ad605330f57 (diff)
parentc3a2ea8424c19c0b653e8c778645d7455ec714b1 (diff)
Merge pull request #4889 from xoviat/time
cleanup low_power add_time function
-rw-r--r--embassy-stm32/CHANGELOG.md1
-rw-r--r--embassy-stm32/src/rtc/low_power.rs69
-rw-r--r--embassy-stm32/src/time_driver.rs33
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
4use super::{DateTimeError, Rtc, RtcError, bcd2_to_byte}; 4use super::{DateTimeError, Rtc, RtcError, bcd2_to_byte};
5use crate::interrupt::typelevel::Interrupt; 5use crate::interrupt::typelevel::Interrupt;
6use crate::pac::rtc::vals::Wucksel;
6use crate::peripherals::RTC; 7use crate::peripherals::RTC;
7use crate::rtc::{RtcTimeProvider, SealedInstance}; 8use 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)] 62fn wucksel_compute_min(val: u32) -> (Wucksel, u32) {
62#[derive(Clone, Copy, Debug)] 63 *[
63pub(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))]
73impl 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))]
89impl 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
103impl 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
117impl Rtc { 74impl 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")]
200fn calc_period_counter(ticks: u64) -> (u32, u16) {
201 (2 * (ticks >> 16) as u32 + (ticks as u16 >= 0x8000) as u32, ticks as u16)
202}
203
199struct AlarmState { 204struct 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);