diff options
| -rw-r--r-- | embassy-stm32/CHANGELOG.md | 1 | ||||
| -rw-r--r-- | embassy-stm32/src/low_power.rs | 18 | ||||
| -rw-r--r-- | embassy-stm32/src/rtc/low_power.rs | 7 | ||||
| -rw-r--r-- | embassy-stm32/src/rtc/v2.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/rtc/v3.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/time_driver.rs | 17 | ||||
| -rw-r--r-- | examples/stm32h5/src/bin/stop.rs | 2 | ||||
| -rw-r--r-- | examples/stm32l5/src/bin/stop.rs | 2 | ||||
| -rw-r--r-- | tests/stm32/src/bin/stop.rs | 3 |
9 files changed, 32 insertions, 22 deletions
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index a703a0c73..a9ab78e31 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md | |||
| @@ -37,6 +37,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 37 | - fix: sdmmc: don't wait for DBCKEND flag on sdmmc_v2 devices as it never fires (Fixes #4723) | 37 | - fix: sdmmc: don't wait for DBCKEND flag on sdmmc_v2 devices as it never fires (Fixes #4723) |
| 38 | - fix: usart: fix race condition in ringbuffered usart | 38 | - fix: usart: fix race condition in ringbuffered usart |
| 39 | - feat: stm32/fdcan: add ability to control automatic recovery from bus off ([#4821](https://github.com/embassy-rs/embassy/pull/4821)) | 39 | - feat: stm32/fdcan: add ability to control automatic recovery from bus off ([#4821](https://github.com/embassy-rs/embassy/pull/4821)) |
| 40 | - low-power: update rtc api to allow reconfig | ||
| 40 | 41 | ||
| 41 | ## 0.4.0 - 2025-08-26 | 42 | ## 0.4.0 - 2025-08-26 |
| 42 | 43 | ||
diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 1b66ca680..74cd11b93 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs | |||
| @@ -43,8 +43,6 @@ | |||
| 43 | //! | 43 | //! |
| 44 | //! // give the RTC to the executor... | 44 | //! // give the RTC to the executor... |
| 45 | //! let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); | 45 | //! let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); |
| 46 | //! static RTC: StaticCell<Rtc> = StaticCell::new(); | ||
| 47 | //! let rtc = RTC.init(rtc); | ||
| 48 | //! embassy_stm32::low_power::stop_with_rtc(rtc); | 46 | //! embassy_stm32::low_power::stop_with_rtc(rtc); |
| 49 | //! | 47 | //! |
| 50 | //! // your application here... | 48 | //! // your application here... |
| @@ -98,10 +96,15 @@ pub(crate) unsafe fn on_wakeup_irq() { | |||
| 98 | } | 96 | } |
| 99 | 97 | ||
| 100 | /// Configure STOP mode with RTC. | 98 | /// Configure STOP mode with RTC. |
| 101 | pub fn stop_with_rtc(rtc: &'static Rtc) { | 99 | pub fn stop_with_rtc(rtc: Rtc) { |
| 102 | unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc) | 100 | unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc) |
| 103 | } | 101 | } |
| 104 | 102 | ||
| 103 | /// Reconfigure the RTC, if set. | ||
| 104 | pub fn reconfigure_rtc(f: impl FnOnce(&mut Rtc)) { | ||
| 105 | unsafe { EXECUTOR.as_mut().unwrap() }.reconfigure_rtc(f); | ||
| 106 | } | ||
| 107 | |||
| 105 | /// Get whether the core is ready to enter the given stop mode. | 108 | /// Get whether the core is ready to enter the given stop mode. |
| 106 | /// | 109 | /// |
| 107 | /// This will return false if some peripheral driver is in use that | 110 | /// This will return false if some peripheral driver is in use that |
| @@ -181,14 +184,17 @@ impl Executor { | |||
| 181 | trace!("low power: resume"); | 184 | trace!("low power: resume"); |
| 182 | } | 185 | } |
| 183 | 186 | ||
| 184 | pub(self) fn stop_with_rtc(&mut self, rtc: &'static Rtc) { | 187 | pub(self) fn stop_with_rtc(&mut self, rtc: Rtc) { |
| 185 | self.time_driver.set_rtc(rtc); | 188 | self.time_driver.set_rtc(rtc); |
| 186 | 189 | self.time_driver.reconfigure_rtc(|rtc| rtc.enable_wakeup_line()); | |
| 187 | rtc.enable_wakeup_line(); | ||
| 188 | 190 | ||
| 189 | trace!("low power: stop with rtc configured"); | 191 | trace!("low power: stop with rtc configured"); |
| 190 | } | 192 | } |
| 191 | 193 | ||
| 194 | pub(self) fn reconfigure_rtc(&mut self, f: impl FnOnce(&mut Rtc)) { | ||
| 195 | self.time_driver.reconfigure_rtc(f); | ||
| 196 | } | ||
| 197 | |||
| 192 | fn stop_mode(&self) -> Option<StopMode> { | 198 | fn stop_mode(&self) -> Option<StopMode> { |
| 193 | if unsafe { crate::rcc::REFCOUNT_STOP2 == 0 } && unsafe { crate::rcc::REFCOUNT_STOP1 == 0 } { | 199 | if unsafe { crate::rcc::REFCOUNT_STOP2 == 0 } && unsafe { crate::rcc::REFCOUNT_STOP1 == 0 } { |
| 194 | Some(StopMode::Stop2) | 200 | Some(StopMode::Stop2) |
diff --git a/embassy-stm32/src/rtc/low_power.rs b/embassy-stm32/src/rtc/low_power.rs index 999f24714..9e0f03879 100644 --- a/embassy-stm32/src/rtc/low_power.rs +++ b/embassy-stm32/src/rtc/low_power.rs | |||
| @@ -127,7 +127,7 @@ impl Rtc { | |||
| 127 | /// start the wakeup alarm and with a duration that is as close to but less than | 127 | /// start the wakeup alarm and with a duration that is as close to but less than |
| 128 | /// the requested duration, and record the instant the wakeup alarm was started | 128 | /// the requested duration, and record the instant the wakeup alarm was started |
| 129 | pub(crate) fn start_wakeup_alarm( | 129 | pub(crate) fn start_wakeup_alarm( |
| 130 | &self, | 130 | &mut self, |
| 131 | requested_duration: embassy_time::Duration, | 131 | requested_duration: embassy_time::Duration, |
| 132 | cs: critical_section::CriticalSection, | 132 | cs: critical_section::CriticalSection, |
| 133 | ) { | 133 | ) { |
| @@ -179,7 +179,10 @@ impl Rtc { | |||
| 179 | 179 | ||
| 180 | /// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm` | 180 | /// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm` |
| 181 | /// was called, otherwise none | 181 | /// was called, otherwise none |
| 182 | pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option<embassy_time::Duration> { | 182 | pub(crate) fn stop_wakeup_alarm( |
| 183 | &mut self, | ||
| 184 | cs: critical_section::CriticalSection, | ||
| 185 | ) -> Option<embassy_time::Duration> { | ||
| 183 | let instant = self.instant().unwrap(); | 186 | let instant = self.instant().unwrap(); |
| 184 | if RTC::regs().cr().read().wute() { | 187 | if RTC::regs().cr().read().wute() { |
| 185 | trace!("rtc: stop wakeup alarm at {}", instant); | 188 | trace!("rtc: stop wakeup alarm at {}", instant); |
diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 23f6ccb0c..8ac022536 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs | |||
| @@ -93,7 +93,7 @@ impl super::Rtc { | |||
| 93 | }) | 93 | }) |
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | pub(super) fn write<F, R>(&self, init_mode: bool, f: F) -> R | 96 | pub(super) fn write<F, R>(&mut self, init_mode: bool, f: F) -> R |
| 97 | where | 97 | where |
| 98 | F: FnOnce(crate::pac::rtc::Rtc) -> R, | 98 | F: FnOnce(crate::pac::rtc::Rtc) -> R, |
| 99 | { | 99 | { |
diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs index 01da5d70a..528dc78b4 100644 --- a/embassy-stm32/src/rtc/v3.rs +++ b/embassy-stm32/src/rtc/v3.rs | |||
| @@ -95,7 +95,7 @@ impl super::Rtc { | |||
| 95 | }) | 95 | }) |
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | pub(super) fn write<F, R>(&self, init_mode: bool, f: F) -> R | 98 | pub(super) fn write<F, R>(&mut self, init_mode: bool, f: F) -> R |
| 99 | where | 99 | where |
| 100 | F: FnOnce(crate::pac::rtc::Rtc) -> R, | 100 | F: FnOnce(crate::pac::rtc::Rtc) -> R, |
| 101 | { | 101 | { |
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 74b10a183..7fd5751b3 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs | |||
| @@ -213,7 +213,7 @@ pub(crate) struct RtcDriver { | |||
| 213 | period: AtomicU32, | 213 | period: AtomicU32, |
| 214 | alarm: Mutex<CriticalSectionRawMutex, AlarmState>, | 214 | alarm: Mutex<CriticalSectionRawMutex, AlarmState>, |
| 215 | #[cfg(feature = "low-power")] | 215 | #[cfg(feature = "low-power")] |
| 216 | rtc: Mutex<CriticalSectionRawMutex, Cell<Option<&'static Rtc>>>, | 216 | rtc: Mutex<CriticalSectionRawMutex, RefCell<Option<Rtc>>>, |
| 217 | queue: Mutex<CriticalSectionRawMutex, RefCell<Queue>>, | 217 | queue: Mutex<CriticalSectionRawMutex, RefCell<Queue>>, |
| 218 | } | 218 | } |
| 219 | 219 | ||
| @@ -221,7 +221,7 @@ embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { | |||
| 221 | period: AtomicU32::new(0), | 221 | period: AtomicU32::new(0), |
| 222 | alarm: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()), | 222 | alarm: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()), |
| 223 | #[cfg(feature = "low-power")] | 223 | #[cfg(feature = "low-power")] |
| 224 | rtc: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), | 224 | rtc: Mutex::const_new(CriticalSectionRawMutex::new(), RefCell::new(None)), |
| 225 | queue: Mutex::new(RefCell::new(Queue::new())) | 225 | queue: Mutex::new(RefCell::new(Queue::new())) |
| 226 | }); | 226 | }); |
| 227 | 227 | ||
| @@ -379,7 +379,7 @@ impl RtcDriver { | |||
| 379 | #[cfg(feature = "low-power")] | 379 | #[cfg(feature = "low-power")] |
| 380 | /// Stop the wakeup alarm, if enabled, and add the appropriate offset | 380 | /// Stop the wakeup alarm, if enabled, and add the appropriate offset |
| 381 | fn stop_wakeup_alarm(&self, cs: CriticalSection) { | 381 | fn stop_wakeup_alarm(&self, cs: CriticalSection) { |
| 382 | if let Some(offset) = self.rtc.borrow(cs).get().unwrap().stop_wakeup_alarm(cs) { | 382 | if let Some(offset) = self.rtc.borrow(cs).borrow_mut().as_mut().unwrap().stop_wakeup_alarm(cs) { |
| 383 | self.add_time(offset, cs); | 383 | self.add_time(offset, cs); |
| 384 | } | 384 | } |
| 385 | } | 385 | } |
| @@ -389,7 +389,7 @@ impl RtcDriver { | |||
| 389 | */ | 389 | */ |
| 390 | #[cfg(feature = "low-power")] | 390 | #[cfg(feature = "low-power")] |
| 391 | /// Set the rtc but panic if it's already been set | 391 | /// Set the rtc but panic if it's already been set |
| 392 | pub(crate) fn set_rtc(&self, rtc: &'static Rtc) { | 392 | pub(crate) fn set_rtc(&self, mut rtc: Rtc) { |
| 393 | critical_section::with(|cs| { | 393 | critical_section::with(|cs| { |
| 394 | rtc.stop_wakeup_alarm(cs); | 394 | rtc.stop_wakeup_alarm(cs); |
| 395 | 395 | ||
| @@ -398,6 +398,12 @@ impl RtcDriver { | |||
| 398 | } | 398 | } |
| 399 | 399 | ||
| 400 | #[cfg(feature = "low-power")] | 400 | #[cfg(feature = "low-power")] |
| 401 | /// Set the rtc but panic if it's already been set | ||
| 402 | pub(crate) fn reconfigure_rtc(&self, f: impl FnOnce(&mut Rtc)) { | ||
| 403 | critical_section::with(|cs| f(self.rtc.borrow(cs).borrow_mut().as_mut().unwrap())); | ||
| 404 | } | ||
| 405 | |||
| 406 | #[cfg(feature = "low-power")] | ||
| 401 | /// The minimum pause time beyond which the executor will enter a low-power state. | 407 | /// The minimum pause time beyond which the executor will enter a low-power state. |
| 402 | pub(crate) const MIN_STOP_PAUSE: embassy_time::Duration = embassy_time::Duration::from_millis(250); | 408 | pub(crate) const MIN_STOP_PAUSE: embassy_time::Duration = embassy_time::Duration::from_millis(250); |
| 403 | 409 | ||
| @@ -418,7 +424,8 @@ impl RtcDriver { | |||
| 418 | } else { | 424 | } else { |
| 419 | self.rtc | 425 | self.rtc |
| 420 | .borrow(cs) | 426 | .borrow(cs) |
| 421 | .get() | 427 | .borrow_mut() |
| 428 | .as_mut() | ||
| 422 | .unwrap() | 429 | .unwrap() |
| 423 | .start_wakeup_alarm(time_until_next_alarm, cs); | 430 | .start_wakeup_alarm(time_until_next_alarm, cs); |
| 424 | 431 | ||
diff --git a/examples/stm32h5/src/bin/stop.rs b/examples/stm32h5/src/bin/stop.rs index 3c4f49f64..29a735ed2 100644 --- a/examples/stm32h5/src/bin/stop.rs +++ b/examples/stm32h5/src/bin/stop.rs | |||
| @@ -39,8 +39,6 @@ async fn async_main(spawner: Spawner) { | |||
| 39 | 39 | ||
| 40 | // give the RTC to the executor... | 40 | // give the RTC to the executor... |
| 41 | let rtc = Rtc::new(p.RTC, RtcConfig::default()); | 41 | let rtc = Rtc::new(p.RTC, RtcConfig::default()); |
| 42 | static RTC: StaticCell<Rtc> = StaticCell::new(); | ||
| 43 | let rtc = RTC.init(rtc); | ||
| 44 | embassy_stm32::low_power::stop_with_rtc(rtc); | 42 | embassy_stm32::low_power::stop_with_rtc(rtc); |
| 45 | 43 | ||
| 46 | spawner.spawn(unwrap!(blinky(p.PB4.into()))); | 44 | spawner.spawn(unwrap!(blinky(p.PB4.into()))); |
diff --git a/examples/stm32l5/src/bin/stop.rs b/examples/stm32l5/src/bin/stop.rs index c34053190..fd2aca372 100644 --- a/examples/stm32l5/src/bin/stop.rs +++ b/examples/stm32l5/src/bin/stop.rs | |||
| @@ -30,8 +30,6 @@ async fn async_main(spawner: Spawner) { | |||
| 30 | 30 | ||
| 31 | // give the RTC to the executor... | 31 | // give the RTC to the executor... |
| 32 | let rtc = Rtc::new(p.RTC, RtcConfig::default()); | 32 | let rtc = Rtc::new(p.RTC, RtcConfig::default()); |
| 33 | static RTC: StaticCell<Rtc> = StaticCell::new(); | ||
| 34 | let rtc = RTC.init(rtc); | ||
| 35 | embassy_stm32::low_power::stop_with_rtc(rtc); | 33 | embassy_stm32::low_power::stop_with_rtc(rtc); |
| 36 | 34 | ||
| 37 | spawner.spawn(unwrap!(blinky(p.PC7.into()))); | 35 | spawner.spawn(unwrap!(blinky(p.PC7.into()))); |
diff --git a/tests/stm32/src/bin/stop.rs b/tests/stm32/src/bin/stop.rs index 833ca05d0..cb3a5774c 100644 --- a/tests/stm32/src/bin/stop.rs +++ b/tests/stm32/src/bin/stop.rs | |||
| @@ -70,9 +70,6 @@ async fn async_main(spawner: Spawner) { | |||
| 70 | 70 | ||
| 71 | rtc.set_datetime(now.into()).expect("datetime not set"); | 71 | rtc.set_datetime(now.into()).expect("datetime not set"); |
| 72 | 72 | ||
| 73 | static RTC: StaticCell<Rtc> = StaticCell::new(); | ||
| 74 | let rtc = RTC.init(rtc); | ||
| 75 | |||
| 76 | stop_with_rtc(rtc); | 73 | stop_with_rtc(rtc); |
| 77 | 74 | ||
| 78 | spawner.spawn(task_1().unwrap()); | 75 | spawner.spawn(task_1().unwrap()); |
