diff options
| author | xoviat <[email protected]> | 2025-11-04 20:55:18 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-11-04 20:55:18 +0000 |
| commit | d23c027dd1a1c5f7cdf818750dddf6a250658423 (patch) | |
| tree | 5b81e8e0ca18d95d9852e986fe67f33db17de559 | |
| parent | da4af0a7ae67d8ec592edf5eff9bbaed2d9e439a (diff) | |
| parent | a6412c923280082c506c75e6428e7d87870580eb (diff) | |
Merge pull request #4838 from embassy-rs/lp2
stm32/low-power: cleanup and improve
| -rw-r--r-- | embassy-stm32/CHANGELOG.md | 1 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/v3.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/exti.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/i2c/v2.rs | 12 | ||||
| -rw-r--r-- | embassy-stm32/src/lib.rs | 18 | ||||
| -rw-r--r-- | embassy-stm32/src/low_power.rs | 164 | ||||
| -rw-r--r-- | embassy-stm32/src/rtc/mod.rs | 24 | ||||
| -rw-r--r-- | embassy-stm32/src/time_driver.rs | 42 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/mod.rs | 4 | ||||
| -rw-r--r-- | examples/stm32h5/src/bin/stop.rs | 5 | ||||
| -rw-r--r-- | examples/stm32l5/src/bin/stop.rs | 5 | ||||
| -rw-r--r-- | examples/stm32wle5/src/bin/adc.rs | 6 | ||||
| -rw-r--r-- | examples/stm32wle5/src/bin/blinky.rs | 6 | ||||
| -rw-r--r-- | examples/stm32wle5/src/bin/button_exti.rs | 6 | ||||
| -rw-r--r-- | examples/stm32wle5/src/bin/i2c.rs | 6 | ||||
| -rw-r--r-- | tests/stm32/src/bin/rtc.rs | 18 | ||||
| -rw-r--r-- | tests/stm32/src/bin/stop.rs | 11 |
17 files changed, 164 insertions, 168 deletions
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index b7d22da39..ee76a5d1b 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md | |||
| @@ -43,6 +43,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 43 | - adc: consolidate ringbuffer | 43 | - adc: consolidate ringbuffer |
| 44 | - feat: Added RTC low-power support for STM32WLEx ([#4716](https://github.com/embassy-rs/embassy/pull/4716)) | 44 | - feat: Added RTC low-power support for STM32WLEx ([#4716](https://github.com/embassy-rs/embassy/pull/4716)) |
| 45 | - fix: Correct STM32WBA VREFBUFTRIM values | 45 | - fix: Correct STM32WBA VREFBUFTRIM values |
| 46 | - low_power: remove stop_with rtc and initialize in init if low-power feature enabled. | ||
| 46 | 47 | ||
| 47 | ## 0.4.0 - 2025-08-26 | 48 | ## 0.4.0 - 2025-08-26 |
| 48 | 49 | ||
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 62c2da557..170b08a25 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs | |||
| @@ -463,7 +463,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 463 | ); | 463 | ); |
| 464 | 464 | ||
| 465 | #[cfg(all(feature = "low-power", stm32wlex))] | 465 | #[cfg(all(feature = "low-power", stm32wlex))] |
| 466 | let _device_busy = crate::low_power::DeviceBusy::new(); | 466 | let _device_busy = crate::low_power::DeviceBusy::new_stop1(); |
| 467 | 467 | ||
| 468 | // Ensure no conversions are ongoing and ADC is enabled. | 468 | // Ensure no conversions are ongoing and ADC is enabled. |
| 469 | Self::cancel_conversions(); | 469 | Self::cancel_conversions(); |
diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index 12600d4eb..2f5c3406a 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs | |||
| @@ -71,7 +71,7 @@ unsafe fn on_irq() { | |||
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | #[cfg(feature = "low-power")] | 73 | #[cfg(feature = "low-power")] |
| 74 | crate::low_power::on_wakeup_irq(); | 74 | crate::low_power::Executor::on_wakeup_irq(); |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | struct BitIter(u32); | 77 | struct BitIter(u32); |
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 6f2d03bd1..ba9590013 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs | |||
| @@ -73,7 +73,7 @@ pub(crate) unsafe fn on_interrupt<T: Instance>() { | |||
| 73 | // restore the clocks to their last configured state as | 73 | // restore the clocks to their last configured state as |
| 74 | // much is lost in STOP modes | 74 | // much is lost in STOP modes |
| 75 | #[cfg(all(feature = "low-power", stm32wlex))] | 75 | #[cfg(all(feature = "low-power", stm32wlex))] |
| 76 | crate::low_power::on_wakeup_irq(); | 76 | crate::low_power::Executor::on_wakeup_irq(); |
| 77 | 77 | ||
| 78 | let regs = T::info().regs; | 78 | let regs = T::info().regs; |
| 79 | let isr = regs.isr().read(); | 79 | let isr = regs.isr().read(); |
| @@ -820,7 +820,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { | |||
| 820 | /// Write. | 820 | /// Write. |
| 821 | pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { | 821 | pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { |
| 822 | #[cfg(all(feature = "low-power", stm32wlex))] | 822 | #[cfg(all(feature = "low-power", stm32wlex))] |
| 823 | let _device_busy = crate::low_power::DeviceBusy::new(); | 823 | let _device_busy = crate::low_power::DeviceBusy::new_stop1(); |
| 824 | let timeout = self.timeout(); | 824 | let timeout = self.timeout(); |
| 825 | if write.is_empty() { | 825 | if write.is_empty() { |
| 826 | self.write_internal(address.into(), write, true, timeout) | 826 | self.write_internal(address.into(), write, true, timeout) |
| @@ -836,7 +836,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { | |||
| 836 | /// The buffers are concatenated in a single write transaction. | 836 | /// The buffers are concatenated in a single write transaction. |
| 837 | pub async fn write_vectored(&mut self, address: Address, write: &[&[u8]]) -> Result<(), Error> { | 837 | pub async fn write_vectored(&mut self, address: Address, write: &[&[u8]]) -> Result<(), Error> { |
| 838 | #[cfg(all(feature = "low-power", stm32wlex))] | 838 | #[cfg(all(feature = "low-power", stm32wlex))] |
| 839 | let _device_busy = crate::low_power::DeviceBusy::new(); | 839 | let _device_busy = crate::low_power::DeviceBusy::new_stop1(); |
| 840 | let timeout = self.timeout(); | 840 | let timeout = self.timeout(); |
| 841 | 841 | ||
| 842 | if write.is_empty() { | 842 | if write.is_empty() { |
| @@ -861,7 +861,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { | |||
| 861 | /// Read. | 861 | /// Read. |
| 862 | pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { | 862 | pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { |
| 863 | #[cfg(all(feature = "low-power", stm32wlex))] | 863 | #[cfg(all(feature = "low-power", stm32wlex))] |
| 864 | let _device_busy = crate::low_power::DeviceBusy::new(); | 864 | let _device_busy = crate::low_power::DeviceBusy::new_stop1(); |
| 865 | let timeout = self.timeout(); | 865 | let timeout = self.timeout(); |
| 866 | 866 | ||
| 867 | if buffer.is_empty() { | 867 | if buffer.is_empty() { |
| @@ -875,7 +875,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { | |||
| 875 | /// Write, restart, read. | 875 | /// Write, restart, read. |
| 876 | pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { | 876 | pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { |
| 877 | #[cfg(all(feature = "low-power", stm32wlex))] | 877 | #[cfg(all(feature = "low-power", stm32wlex))] |
| 878 | let _device_busy = crate::low_power::DeviceBusy::new(); | 878 | let _device_busy = crate::low_power::DeviceBusy::new_stop1(); |
| 879 | let timeout = self.timeout(); | 879 | let timeout = self.timeout(); |
| 880 | 880 | ||
| 881 | if write.is_empty() { | 881 | if write.is_empty() { |
| @@ -902,7 +902,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { | |||
| 902 | /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction | 902 | /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction |
| 903 | pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { | 903 | pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { |
| 904 | #[cfg(all(feature = "low-power", stm32wlex))] | 904 | #[cfg(all(feature = "low-power", stm32wlex))] |
| 905 | let _device_busy = crate::low_power::DeviceBusy::new(); | 905 | let _device_busy = crate::low_power::DeviceBusy::new_stop1(); |
| 906 | let _ = addr; | 906 | let _ = addr; |
| 907 | let _ = operations; | 907 | let _ = operations; |
| 908 | todo!() | 908 | todo!() |
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index dbf0fe620..85606e7de 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs | |||
| @@ -241,6 +241,14 @@ pub struct Config { | |||
| 241 | /// RCC config. | 241 | /// RCC config. |
| 242 | pub rcc: rcc::Config, | 242 | pub rcc: rcc::Config, |
| 243 | 243 | ||
| 244 | #[cfg(feature = "low-power")] | ||
| 245 | /// RTC config | ||
| 246 | pub rtc: rtc::RtcConfig, | ||
| 247 | |||
| 248 | #[cfg(feature = "low-power")] | ||
| 249 | /// Minimum time to stop | ||
| 250 | pub min_stop_pause: embassy_time::Duration, | ||
| 251 | |||
| 244 | /// Enable debug during sleep and stop. | 252 | /// Enable debug during sleep and stop. |
| 245 | /// | 253 | /// |
| 246 | /// May increase power consumption. Defaults to true. | 254 | /// May increase power consumption. Defaults to true. |
| @@ -294,6 +302,10 @@ impl Default for Config { | |||
| 294 | fn default() -> Self { | 302 | fn default() -> Self { |
| 295 | Self { | 303 | Self { |
| 296 | rcc: Default::default(), | 304 | rcc: Default::default(), |
| 305 | #[cfg(feature = "low-power")] | ||
| 306 | rtc: Default::default(), | ||
| 307 | #[cfg(feature = "low-power")] | ||
| 308 | min_stop_pause: embassy_time::Duration::from_millis(250), | ||
| 297 | #[cfg(dbgmcu)] | 309 | #[cfg(dbgmcu)] |
| 298 | enable_debug_during_sleep: true, | 310 | enable_debug_during_sleep: true, |
| 299 | #[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba))] | 311 | #[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba))] |
| @@ -623,6 +635,12 @@ fn init_hw(config: Config) -> Peripherals { | |||
| 623 | exti::init(cs); | 635 | exti::init(cs); |
| 624 | 636 | ||
| 625 | rcc::init_rcc(cs, config.rcc); | 637 | rcc::init_rcc(cs, config.rcc); |
| 638 | |||
| 639 | #[cfg(feature = "low-power")] | ||
| 640 | crate::rtc::init_rtc(cs, config.rtc); | ||
| 641 | |||
| 642 | #[cfg(feature = "low-power")] | ||
| 643 | crate::time_driver::get_driver().set_min_stop_pause(cs, config.min_stop_pause); | ||
| 626 | } | 644 | } |
| 627 | 645 | ||
| 628 | p | 646 | p |
diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index cde3153f6..597cedf86 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs | |||
| @@ -41,10 +41,6 @@ | |||
| 41 | //! config.enable_debug_during_sleep = false; | 41 | //! config.enable_debug_during_sleep = false; |
| 42 | //! let p = embassy_stm32::init(config); | 42 | //! let p = embassy_stm32::init(config); |
| 43 | //! | 43 | //! |
| 44 | //! // give the RTC to the executor... | ||
| 45 | //! let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); | ||
| 46 | //! embassy_stm32::low_power::stop_with_rtc(rtc); | ||
| 47 | //! | ||
| 48 | //! // your application here... | 44 | //! // your application here... |
| 49 | //! } | 45 | //! } |
| 50 | //! ``` | 46 | //! ``` |
| @@ -57,10 +53,11 @@ use core::marker::PhantomData; | |||
| 57 | use core::sync::atomic::{Ordering, compiler_fence}; | 53 | use core::sync::atomic::{Ordering, compiler_fence}; |
| 58 | 54 | ||
| 59 | use cortex_m::peripheral::SCB; | 55 | use cortex_m::peripheral::SCB; |
| 56 | use critical_section::CriticalSection; | ||
| 60 | use embassy_executor::*; | 57 | use embassy_executor::*; |
| 61 | 58 | ||
| 62 | use crate::interrupt; | 59 | use crate::interrupt; |
| 63 | use crate::time_driver::{RtcDriver, get_driver}; | 60 | use crate::time_driver::get_driver; |
| 64 | 61 | ||
| 65 | const THREAD_PENDER: usize = usize::MAX; | 62 | const THREAD_PENDER: usize = usize::MAX; |
| 66 | 63 | ||
| @@ -68,46 +65,59 @@ use crate::rtc::Rtc; | |||
| 68 | 65 | ||
| 69 | static mut EXECUTOR: Option<Executor> = None; | 66 | static mut EXECUTOR: Option<Executor> = None; |
| 70 | 67 | ||
| 71 | #[cfg(stm32wlex)] | 68 | /// Prevent the device from going into the stop mode if held |
| 72 | pub(crate) use self::busy::DeviceBusy; | 69 | pub struct DeviceBusy(StopMode); |
| 73 | #[cfg(stm32wlex)] | ||
| 74 | mod busy { | ||
| 75 | use core::sync::atomic::{AtomicU32, Ordering}; | ||
| 76 | 70 | ||
| 77 | // Count of devices blocking STOP | 71 | impl DeviceBusy { |
| 78 | static STOP_BLOCKED: AtomicU32 = AtomicU32::new(0); | 72 | /// Create a new DeviceBusy with stop1. |
| 73 | pub fn new_stop1() -> Self { | ||
| 74 | Self::new(StopMode::Stop1) | ||
| 75 | } | ||
| 79 | 76 | ||
| 80 | /// Check if STOP1 is blocked. | 77 | /// Create a new DeviceBusy with stop2. |
| 81 | pub(crate) fn stop_blocked() -> bool { | 78 | pub fn new_stop2() -> Self { |
| 82 | STOP_BLOCKED.load(Ordering::SeqCst) > 0 | 79 | Self::new(StopMode::Stop2) |
| 83 | } | 80 | } |
| 84 | 81 | ||
| 85 | /// When ca device goes busy it will construct one of these where it will be dropped when the device goes idle. | 82 | /// Create a new DeviceBusy. |
| 86 | pub(crate) struct DeviceBusy {} | 83 | pub fn new(stop_mode: StopMode) -> Self { |
| 84 | critical_section::with(|_| unsafe { | ||
| 85 | match stop_mode { | ||
| 86 | StopMode::Stop1 => { | ||
| 87 | crate::rcc::REFCOUNT_STOP1 += 1; | ||
| 88 | } | ||
| 89 | StopMode::Stop2 => { | ||
| 90 | crate::rcc::REFCOUNT_STOP2 += 1; | ||
| 91 | } | ||
| 92 | } | ||
| 93 | }); | ||
| 87 | 94 | ||
| 88 | impl DeviceBusy { | 95 | Self(stop_mode) |
| 89 | /// Create a new DeviceBusy. | ||
| 90 | pub(crate) fn new() -> Self { | ||
| 91 | STOP_BLOCKED.fetch_add(1, Ordering::SeqCst); | ||
| 92 | trace!("low power: device busy: Stop:{}", STOP_BLOCKED.load(Ordering::SeqCst)); | ||
| 93 | Self {} | ||
| 94 | } | ||
| 95 | } | 96 | } |
| 97 | } | ||
| 96 | 98 | ||
| 97 | impl Drop for DeviceBusy { | 99 | impl Drop for DeviceBusy { |
| 98 | fn drop(&mut self) { | 100 | fn drop(&mut self) { |
| 99 | STOP_BLOCKED.fetch_sub(1, Ordering::SeqCst); | 101 | critical_section::with(|_| unsafe { |
| 100 | trace!("low power: device idle: Stop:{}", STOP_BLOCKED.load(Ordering::SeqCst)); | 102 | match self.0 { |
| 101 | } | 103 | StopMode::Stop1 => { |
| 104 | crate::rcc::REFCOUNT_STOP1 -= 1; | ||
| 105 | } | ||
| 106 | StopMode::Stop2 => { | ||
| 107 | crate::rcc::REFCOUNT_STOP2 -= 1; | ||
| 108 | } | ||
| 109 | } | ||
| 110 | }); | ||
| 102 | } | 111 | } |
| 103 | } | 112 | } |
| 113 | |||
| 104 | #[cfg(not(stm32u0))] | 114 | #[cfg(not(stm32u0))] |
| 105 | foreach_interrupt! { | 115 | foreach_interrupt! { |
| 106 | (RTC, rtc, $block:ident, WKUP, $irq:ident) => { | 116 | (RTC, rtc, $block:ident, WKUP, $irq:ident) => { |
| 107 | #[interrupt] | 117 | #[interrupt] |
| 108 | #[allow(non_snake_case)] | 118 | #[allow(non_snake_case)] |
| 109 | unsafe fn $irq() { | 119 | unsafe fn $irq() { |
| 110 | EXECUTOR.as_mut().unwrap().on_wakeup_irq(); | 120 | Executor::on_wakeup_irq(); |
| 111 | } | 121 | } |
| 112 | }; | 122 | }; |
| 113 | } | 123 | } |
| @@ -118,27 +128,14 @@ foreach_interrupt! { | |||
| 118 | #[interrupt] | 128 | #[interrupt] |
| 119 | #[allow(non_snake_case)] | 129 | #[allow(non_snake_case)] |
| 120 | unsafe fn $irq() { | 130 | unsafe fn $irq() { |
| 121 | EXECUTOR.as_mut().unwrap().on_wakeup_irq(); | 131 | Executor::on_wakeup_irq(); |
| 122 | } | 132 | } |
| 123 | }; | 133 | }; |
| 124 | } | 134 | } |
| 125 | 135 | ||
| 126 | #[allow(dead_code)] | ||
| 127 | pub(crate) unsafe fn on_wakeup_irq() { | ||
| 128 | if EXECUTOR.is_some() { | ||
| 129 | trace!("low power: wakeup irq"); | ||
| 130 | EXECUTOR.as_mut().unwrap().on_wakeup_irq(); | ||
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 134 | /// Configure STOP mode with RTC. | ||
| 135 | pub fn stop_with_rtc(rtc: Rtc) { | ||
| 136 | unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc) | ||
| 137 | } | ||
| 138 | |||
| 139 | /// Reconfigure the RTC, if set. | 136 | /// Reconfigure the RTC, if set. |
| 140 | pub fn reconfigure_rtc(f: impl FnOnce(&mut Rtc)) { | 137 | pub fn reconfigure_rtc<R>(f: impl FnOnce(&mut Rtc) -> R) -> R { |
| 141 | unsafe { EXECUTOR.as_mut().unwrap() }.reconfigure_rtc(f); | 138 | get_driver().reconfigure_rtc(f) |
| 142 | } | 139 | } |
| 143 | 140 | ||
| 144 | /// Get whether the core is ready to enter the given stop mode. | 141 | /// Get whether the core is ready to enter the given stop mode. |
| @@ -146,11 +143,11 @@ pub fn reconfigure_rtc(f: impl FnOnce(&mut Rtc)) { | |||
| 146 | /// This will return false if some peripheral driver is in use that | 143 | /// This will return false if some peripheral driver is in use that |
| 147 | /// prevents entering the given stop mode. | 144 | /// prevents entering the given stop mode. |
| 148 | pub fn stop_ready(stop_mode: StopMode) -> bool { | 145 | pub fn stop_ready(stop_mode: StopMode) -> bool { |
| 149 | match unsafe { EXECUTOR.as_mut().unwrap() }.stop_mode() { | 146 | critical_section::with(|cs| match Executor::stop_mode(cs) { |
| 150 | Some(StopMode::Stop2) => true, | 147 | Some(StopMode::Stop2) => true, |
| 151 | Some(StopMode::Stop1) => stop_mode == StopMode::Stop1, | 148 | Some(StopMode::Stop1) => stop_mode == StopMode::Stop1, |
| 152 | None => false, | 149 | None => false, |
| 153 | } | 150 | }) |
| 154 | } | 151 | } |
| 155 | 152 | ||
| 156 | /// Available Stop modes. | 153 | /// Available Stop modes. |
| @@ -193,7 +190,6 @@ pub struct Executor { | |||
| 193 | inner: raw::Executor, | 190 | inner: raw::Executor, |
| 194 | not_send: PhantomData<*mut ()>, | 191 | not_send: PhantomData<*mut ()>, |
| 195 | scb: SCB, | 192 | scb: SCB, |
| 196 | time_driver: &'static RtcDriver, | ||
| 197 | } | 193 | } |
| 198 | 194 | ||
| 199 | impl Executor { | 195 | impl Executor { |
| @@ -206,7 +202,6 @@ impl Executor { | |||
| 206 | inner: raw::Executor::new(THREAD_PENDER as *mut ()), | 202 | inner: raw::Executor::new(THREAD_PENDER as *mut ()), |
| 207 | not_send: PhantomData, | 203 | not_send: PhantomData, |
| 208 | scb: cortex_m::Peripherals::steal().SCB, | 204 | scb: cortex_m::Peripherals::steal().SCB, |
| 209 | time_driver: get_driver(), | ||
| 210 | }); | 205 | }); |
| 211 | 206 | ||
| 212 | let executor = EXECUTOR.as_mut().unwrap(); | 207 | let executor = EXECUTOR.as_mut().unwrap(); |
| @@ -215,54 +210,33 @@ impl Executor { | |||
| 215 | }) | 210 | }) |
| 216 | } | 211 | } |
| 217 | 212 | ||
| 218 | unsafe fn on_wakeup_irq(&mut self) { | 213 | pub(crate) unsafe fn on_wakeup_irq() { |
| 219 | #[cfg(stm32wlex)] | 214 | critical_section::with(|cs| { |
| 220 | { | 215 | #[cfg(stm32wlex)] |
| 221 | let extscr = crate::pac::PWR.extscr().read(); | 216 | { |
| 222 | if extscr.c1stop2f() || extscr.c1stopf() { | 217 | let extscr = crate::pac::PWR.extscr().read(); |
| 223 | // when we wake from any stop mode we need to re-initialize the rcc | 218 | if extscr.c1stop2f() || extscr.c1stopf() { |
| 224 | crate::rcc::apply_resume_config(); | 219 | // when we wake from any stop mode we need to re-initialize the rcc |
| 225 | if extscr.c1stop2f() { | 220 | crate::rcc::apply_resume_config(); |
| 226 | // when we wake from STOP2, we need to re-initialize the time driver | 221 | if extscr.c1stop2f() { |
| 227 | critical_section::with(|cs| crate::time_driver::init_timer(cs)); | 222 | // when we wake from STOP2, we need to re-initialize the time driver |
| 228 | // reset the refcounts for STOP2 and STOP1 (initializing the time driver will increment one of them for the timer) | 223 | crate::time_driver::init_timer(cs); |
| 229 | // and given that we just woke from STOP2, we can reset them | 224 | // reset the refcounts for STOP2 and STOP1 (initializing the time driver will increment one of them for the timer) |
| 230 | crate::rcc::REFCOUNT_STOP2 = 0; | 225 | // and given that we just woke from STOP2, we can reset them |
| 231 | crate::rcc::REFCOUNT_STOP1 = 0; | 226 | crate::rcc::REFCOUNT_STOP2 = 0; |
| 227 | crate::rcc::REFCOUNT_STOP1 = 0; | ||
| 228 | } | ||
| 232 | } | 229 | } |
| 233 | } | 230 | } |
| 234 | } | 231 | get_driver().resume_time(cs); |
| 235 | self.time_driver.resume_time(); | 232 | trace!("low power: resume"); |
| 236 | trace!("low power: resume"); | 233 | }); |
| 237 | } | ||
| 238 | |||
| 239 | pub(self) fn stop_with_rtc(&mut self, rtc: Rtc) { | ||
| 240 | self.time_driver.set_rtc(rtc); | ||
| 241 | self.time_driver.reconfigure_rtc(|rtc| rtc.enable_wakeup_line()); | ||
| 242 | |||
| 243 | trace!("low power: stop with rtc configured"); | ||
| 244 | } | ||
| 245 | |||
| 246 | pub(self) fn reconfigure_rtc(&mut self, f: impl FnOnce(&mut Rtc)) { | ||
| 247 | self.time_driver.reconfigure_rtc(f); | ||
| 248 | } | ||
| 249 | |||
| 250 | fn stop1_ok_to_enter(&self) -> bool { | ||
| 251 | #[cfg(stm32wlex)] | ||
| 252 | if self::busy::stop_blocked() { | ||
| 253 | return false; | ||
| 254 | } | ||
| 255 | unsafe { crate::rcc::REFCOUNT_STOP1 == 0 } | ||
| 256 | } | ||
| 257 | |||
| 258 | fn stop2_ok_to_enter(&self) -> bool { | ||
| 259 | self.stop1_ok_to_enter() && unsafe { crate::rcc::REFCOUNT_STOP2 == 0 } | ||
| 260 | } | 234 | } |
| 261 | 235 | ||
| 262 | fn stop_mode(&self) -> Option<StopMode> { | 236 | fn stop_mode(_cs: CriticalSection) -> Option<StopMode> { |
| 263 | if self.stop2_ok_to_enter() { | 237 | if unsafe { crate::rcc::REFCOUNT_STOP2 == 0 && crate::rcc::REFCOUNT_STOP1 == 0 } { |
| 264 | Some(StopMode::Stop2) | 238 | Some(StopMode::Stop2) |
| 265 | } else if self.stop1_ok_to_enter() { | 239 | } else if unsafe { crate::rcc::REFCOUNT_STOP1 == 0 } { |
| 266 | Some(StopMode::Stop1) | 240 | Some(StopMode::Stop1) |
| 267 | } else { | 241 | } else { |
| 268 | None | 242 | None |
| @@ -291,14 +265,14 @@ impl Executor { | |||
| 291 | 265 | ||
| 292 | compiler_fence(Ordering::SeqCst); | 266 | compiler_fence(Ordering::SeqCst); |
| 293 | 267 | ||
| 294 | let stop_mode = self.stop_mode(); | 268 | let stop_mode = critical_section::with(|cs| Self::stop_mode(cs)); |
| 295 | 269 | ||
| 296 | if stop_mode.is_none() { | 270 | if stop_mode.is_none() { |
| 297 | trace!("low power: not ready to stop"); | 271 | trace!("low power: not ready to stop"); |
| 298 | return; | 272 | return; |
| 299 | } | 273 | } |
| 300 | 274 | ||
| 301 | if self.time_driver.pause_time().is_err() { | 275 | if get_driver().pause_time().is_err() { |
| 302 | trace!("low power: failed to pause time"); | 276 | trace!("low power: failed to pause time"); |
| 303 | return; | 277 | return; |
| 304 | } | 278 | } |
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index bc6df528b..fa5b45e3c 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs | |||
| @@ -8,6 +8,8 @@ mod low_power; | |||
| 8 | use core::cell::Cell; | 8 | use core::cell::Cell; |
| 9 | 9 | ||
| 10 | #[cfg(feature = "low-power")] | 10 | #[cfg(feature = "low-power")] |
| 11 | use critical_section::CriticalSection; | ||
| 12 | #[cfg(feature = "low-power")] | ||
| 11 | use embassy_sync::blocking_mutex::Mutex; | 13 | use embassy_sync::blocking_mutex::Mutex; |
| 12 | #[cfg(feature = "low-power")] | 14 | #[cfg(feature = "low-power")] |
| 13 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | 15 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; |
| @@ -44,11 +46,18 @@ pub enum RtcError { | |||
| 44 | } | 46 | } |
| 45 | 47 | ||
| 46 | /// Provides immutable access to the current time of the RTC. | 48 | /// Provides immutable access to the current time of the RTC. |
| 49 | #[derive(Clone)] | ||
| 47 | pub struct RtcTimeProvider { | 50 | pub struct RtcTimeProvider { |
| 48 | _private: (), | 51 | _private: (), |
| 49 | } | 52 | } |
| 50 | 53 | ||
| 51 | impl RtcTimeProvider { | 54 | impl RtcTimeProvider { |
| 55 | #[cfg(feature = "low-power")] | ||
| 56 | /// Create a new RTC time provider instance. | ||
| 57 | pub fn new(_rtc: Peri<'static, RTC>) -> Self { | ||
| 58 | Self { _private: () } | ||
| 59 | } | ||
| 60 | |||
| 52 | /// Return the current datetime. | 61 | /// Return the current datetime. |
| 53 | /// | 62 | /// |
| 54 | /// # Errors | 63 | /// # Errors |
| @@ -145,8 +154,13 @@ pub enum RtcCalibrationCyclePeriod { | |||
| 145 | } | 154 | } |
| 146 | 155 | ||
| 147 | impl Rtc { | 156 | impl Rtc { |
| 157 | #[cfg(not(feature = "low-power"))] | ||
| 148 | /// Create a new RTC instance. | 158 | /// Create a new RTC instance. |
| 149 | pub fn new(_rtc: Peri<'static, RTC>, rtc_config: RtcConfig) -> Self { | 159 | pub fn new(_rtc: Peri<'static, RTC>, rtc_config: RtcConfig) -> Self { |
| 160 | Self::new_inner(rtc_config) | ||
| 161 | } | ||
| 162 | |||
| 163 | pub(self) fn new_inner(rtc_config: RtcConfig) -> Self { | ||
| 150 | #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))] | 164 | #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))] |
| 151 | crate::rcc::enable_and_reset::<RTC>(); | 165 | crate::rcc::enable_and_reset::<RTC>(); |
| 152 | 166 | ||
| @@ -169,6 +183,9 @@ impl Rtc { | |||
| 169 | while now == this.time_provider().read(|_, _, ss| Ok(ss)).unwrap() {} | 183 | while now == this.time_provider().read(|_, _, ss| Ok(ss)).unwrap() {} |
| 170 | } | 184 | } |
| 171 | 185 | ||
| 186 | #[cfg(feature = "low-power")] | ||
| 187 | this.enable_wakeup_line(); | ||
| 188 | |||
| 172 | this | 189 | this |
| 173 | } | 190 | } |
| 174 | 191 | ||
| @@ -315,3 +332,10 @@ trait SealedInstance { | |||
| 315 | 332 | ||
| 316 | // fn apply_config(&mut self, rtc_config: RtcConfig); | 333 | // fn apply_config(&mut self, rtc_config: RtcConfig); |
| 317 | } | 334 | } |
| 335 | |||
| 336 | #[cfg(feature = "low-power")] | ||
| 337 | pub(crate) fn init_rtc(cs: CriticalSection, config: RtcConfig) { | ||
| 338 | crate::time_driver::get_driver().set_rtc(cs, Rtc::new_inner(config)); | ||
| 339 | |||
| 340 | trace!("low power: stop with rtc configured"); | ||
| 341 | } | ||
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 4956d1f68..1941788e8 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs | |||
| @@ -216,6 +216,9 @@ pub(crate) struct RtcDriver { | |||
| 216 | alarm: Mutex<CriticalSectionRawMutex, AlarmState>, | 216 | alarm: Mutex<CriticalSectionRawMutex, AlarmState>, |
| 217 | #[cfg(feature = "low-power")] | 217 | #[cfg(feature = "low-power")] |
| 218 | rtc: Mutex<CriticalSectionRawMutex, RefCell<Option<Rtc>>>, | 218 | rtc: Mutex<CriticalSectionRawMutex, RefCell<Option<Rtc>>>, |
| 219 | #[cfg(feature = "low-power")] | ||
| 220 | /// The minimum pause time beyond which the executor will enter a low-power state. | ||
| 221 | min_stop_pause: Mutex<CriticalSectionRawMutex, Cell<embassy_time::Duration>>, | ||
| 219 | /// Saved count for the timer (its value is lost when entering STOP2) | 222 | /// Saved count for the timer (its value is lost when entering STOP2) |
| 220 | #[cfg(all(feature = "low-power", stm32wlex))] | 223 | #[cfg(all(feature = "low-power", stm32wlex))] |
| 221 | saved_count: AtomicU16, | 224 | saved_count: AtomicU16, |
| @@ -227,6 +230,8 @@ embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { | |||
| 227 | alarm: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()), | 230 | alarm: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()), |
| 228 | #[cfg(feature = "low-power")] | 231 | #[cfg(feature = "low-power")] |
| 229 | rtc: Mutex::const_new(CriticalSectionRawMutex::new(), RefCell::new(None)), | 232 | rtc: Mutex::const_new(CriticalSectionRawMutex::new(), RefCell::new(None)), |
| 233 | #[cfg(feature = "low-power")] | ||
| 234 | min_stop_pause: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(embassy_time::Duration::from_millis(0))), | ||
| 230 | #[cfg(all(feature = "low-power", stm32wlex))] | 235 | #[cfg(all(feature = "low-power", stm32wlex))] |
| 231 | saved_count: AtomicU16::new(0), | 236 | saved_count: AtomicU16::new(0), |
| 232 | queue: Mutex::new(RefCell::new(Queue::new())) | 237 | queue: Mutex::new(RefCell::new(Queue::new())) |
| @@ -400,27 +405,26 @@ impl RtcDriver { | |||
| 400 | } | 405 | } |
| 401 | 406 | ||
| 402 | /* | 407 | /* |
| 403 | Low-power public functions: all create a critical section | 408 | Low-power public functions: all create or require a critical section |
| 404 | */ | 409 | */ |
| 405 | #[cfg(feature = "low-power")] | 410 | #[cfg(feature = "low-power")] |
| 406 | /// Set the rtc but panic if it's already been set | 411 | pub(crate) fn set_min_stop_pause(&self, cs: CriticalSection, min_stop_pause: embassy_time::Duration) { |
| 407 | pub(crate) fn set_rtc(&self, mut rtc: Rtc) { | 412 | self.min_stop_pause.borrow(cs).replace(min_stop_pause); |
| 408 | critical_section::with(|cs| { | ||
| 409 | rtc.stop_wakeup_alarm(cs); | ||
| 410 | |||
| 411 | assert!(self.rtc.borrow(cs).replace(Some(rtc)).is_none()) | ||
| 412 | }); | ||
| 413 | } | 413 | } |
| 414 | 414 | ||
| 415 | #[cfg(feature = "low-power")] | 415 | #[cfg(feature = "low-power")] |
| 416 | /// Set the rtc but panic if it's already been set | 416 | /// Set the rtc but panic if it's already been set |
| 417 | pub(crate) fn reconfigure_rtc(&self, f: impl FnOnce(&mut Rtc)) { | 417 | pub(crate) fn set_rtc(&self, cs: CriticalSection, mut rtc: Rtc) { |
| 418 | critical_section::with(|cs| f(self.rtc.borrow(cs).borrow_mut().as_mut().unwrap())); | 418 | rtc.stop_wakeup_alarm(cs); |
| 419 | |||
| 420 | assert!(self.rtc.borrow(cs).replace(Some(rtc)).is_none()); | ||
| 419 | } | 421 | } |
| 420 | 422 | ||
| 421 | #[cfg(feature = "low-power")] | 423 | #[cfg(feature = "low-power")] |
| 422 | /// The minimum pause time beyond which the executor will enter a low-power state. | 424 | /// Reconfigure the rtc |
| 423 | pub(crate) const MIN_STOP_PAUSE: embassy_time::Duration = embassy_time::Duration::from_millis(250); | 425 | pub(crate) fn reconfigure_rtc<R>(&self, f: impl FnOnce(&mut Rtc) -> R) -> R { |
| 426 | critical_section::with(|cs| f(self.rtc.borrow(cs).borrow_mut().as_mut().unwrap())) | ||
| 427 | } | ||
| 424 | 428 | ||
| 425 | #[cfg(feature = "low-power")] | 429 | #[cfg(feature = "low-power")] |
| 426 | /// Pause the timer if ready; return err if not | 430 | /// Pause the timer if ready; return err if not |
| @@ -434,9 +438,9 @@ impl RtcDriver { | |||
| 434 | self.stop_wakeup_alarm(cs); | 438 | self.stop_wakeup_alarm(cs); |
| 435 | 439 | ||
| 436 | let time_until_next_alarm = self.time_until_next_alarm(cs); | 440 | let time_until_next_alarm = self.time_until_next_alarm(cs); |
| 437 | if time_until_next_alarm < Self::MIN_STOP_PAUSE { | 441 | if time_until_next_alarm < self.min_stop_pause.borrow(cs).get() { |
| 438 | trace!( | 442 | trace!( |
| 439 | "time_until_next_alarm < Self::MIN_STOP_PAUSE ({})", | 443 | "time_until_next_alarm < self.min_stop_pause ({})", |
| 440 | time_until_next_alarm | 444 | time_until_next_alarm |
| 441 | ); | 445 | ); |
| 442 | Err(()) | 446 | Err(()) |
| @@ -460,18 +464,16 @@ impl RtcDriver { | |||
| 460 | 464 | ||
| 461 | #[cfg(feature = "low-power")] | 465 | #[cfg(feature = "low-power")] |
| 462 | /// Resume the timer with the given offset | 466 | /// Resume the timer with the given offset |
| 463 | pub(crate) fn resume_time(&self) { | 467 | pub(crate) fn resume_time(&self, cs: CriticalSection) { |
| 464 | if regs_gp16().cr1().read().cen() { | 468 | if regs_gp16().cr1().read().cen() { |
| 465 | // Time isn't currently stopped | 469 | // Time isn't currently stopped |
| 466 | 470 | ||
| 467 | return; | 471 | return; |
| 468 | } | 472 | } |
| 469 | 473 | ||
| 470 | critical_section::with(|cs| { | 474 | self.stop_wakeup_alarm(cs); |
| 471 | self.stop_wakeup_alarm(cs); | ||
| 472 | 475 | ||
| 473 | regs_gp16().cr1().modify(|w| w.set_cen(true)); | 476 | regs_gp16().cr1().modify(|w| w.set_cen(true)); |
| 474 | }) | ||
| 475 | } | 477 | } |
| 476 | 478 | ||
| 477 | fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool { | 479 | fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool { |
| @@ -543,7 +545,7 @@ impl Driver for RtcDriver { | |||
| 543 | } | 545 | } |
| 544 | 546 | ||
| 545 | #[cfg(feature = "low-power")] | 547 | #[cfg(feature = "low-power")] |
| 546 | pub(crate) fn get_driver() -> &'static RtcDriver { | 548 | pub(crate) const fn get_driver() -> &'static RtcDriver { |
| 547 | &DRIVER | 549 | &DRIVER |
| 548 | } | 550 | } |
| 549 | 551 | ||
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index b09bc7166..804d1ef37 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs | |||
| @@ -399,7 +399,7 @@ pub struct UpdateInterruptHandler<T: CoreInstance> { | |||
| 399 | impl<T: CoreInstance> interrupt::typelevel::Handler<T::UpdateInterrupt> for UpdateInterruptHandler<T> { | 399 | impl<T: CoreInstance> interrupt::typelevel::Handler<T::UpdateInterrupt> for UpdateInterruptHandler<T> { |
| 400 | unsafe fn on_interrupt() { | 400 | unsafe fn on_interrupt() { |
| 401 | #[cfg(feature = "low-power")] | 401 | #[cfg(feature = "low-power")] |
| 402 | crate::low_power::on_wakeup_irq(); | 402 | crate::low_power::Executor::on_wakeup_irq(); |
| 403 | 403 | ||
| 404 | let regs = crate::pac::timer::TimCore::from_ptr(T::regs()); | 404 | let regs = crate::pac::timer::TimCore::from_ptr(T::regs()); |
| 405 | 405 | ||
| @@ -429,7 +429,7 @@ impl<T: GeneralInstance1Channel> interrupt::typelevel::Handler<T::CaptureCompare | |||
| 429 | { | 429 | { |
| 430 | unsafe fn on_interrupt() { | 430 | unsafe fn on_interrupt() { |
| 431 | #[cfg(feature = "low-power")] | 431 | #[cfg(feature = "low-power")] |
| 432 | crate::low_power::on_wakeup_irq(); | 432 | crate::low_power::Executor::on_wakeup_irq(); |
| 433 | 433 | ||
| 434 | let regs = crate::pac::timer::TimGp16::from_ptr(T::regs()); | 434 | let regs = crate::pac::timer::TimGp16::from_ptr(T::regs()); |
| 435 | 435 | ||
diff --git a/examples/stm32h5/src/bin/stop.rs b/examples/stm32h5/src/bin/stop.rs index 2026d8f99..caebc9daf 100644 --- a/examples/stm32h5/src/bin/stop.rs +++ b/examples/stm32h5/src/bin/stop.rs | |||
| @@ -9,7 +9,6 @@ use embassy_executor::Spawner; | |||
| 9 | use embassy_stm32::gpio::{AnyPin, Level, Output, Speed}; | 9 | use embassy_stm32::gpio::{AnyPin, Level, Output, Speed}; |
| 10 | use embassy_stm32::low_power::Executor; | 10 | use embassy_stm32::low_power::Executor; |
| 11 | use embassy_stm32::rcc::{HSIPrescaler, LsConfig}; | 11 | use embassy_stm32::rcc::{HSIPrescaler, LsConfig}; |
| 12 | use embassy_stm32::rtc::{Rtc, RtcConfig}; | ||
| 13 | use embassy_stm32::{Config, Peri}; | 12 | use embassy_stm32::{Config, Peri}; |
| 14 | use embassy_time::Timer; | 13 | use embassy_time::Timer; |
| 15 | use {defmt_rtt as _, panic_probe as _}; | 14 | use {defmt_rtt as _, panic_probe as _}; |
| @@ -36,10 +35,6 @@ async fn async_main(spawner: Spawner) { | |||
| 36 | // config.enable_debug_during_sleep = false; | 35 | // config.enable_debug_during_sleep = false; |
| 37 | let p = embassy_stm32::init(config); | 36 | let p = embassy_stm32::init(config); |
| 38 | 37 | ||
| 39 | // give the RTC to the executor... | ||
| 40 | let rtc = Rtc::new(p.RTC, RtcConfig::default()); | ||
| 41 | embassy_stm32::low_power::stop_with_rtc(rtc); | ||
| 42 | |||
| 43 | spawner.spawn(unwrap!(blinky(p.PB4.into()))); | 38 | spawner.spawn(unwrap!(blinky(p.PB4.into()))); |
| 44 | spawner.spawn(unwrap!(timeout())); | 39 | spawner.spawn(unwrap!(timeout())); |
| 45 | } | 40 | } |
diff --git a/examples/stm32l5/src/bin/stop.rs b/examples/stm32l5/src/bin/stop.rs index 7662dbfa8..3d119f90f 100644 --- a/examples/stm32l5/src/bin/stop.rs +++ b/examples/stm32l5/src/bin/stop.rs | |||
| @@ -6,7 +6,6 @@ use embassy_executor::Spawner; | |||
| 6 | use embassy_stm32::gpio::{AnyPin, Level, Output, Speed}; | 6 | use embassy_stm32::gpio::{AnyPin, Level, Output, Speed}; |
| 7 | use embassy_stm32::low_power::Executor; | 7 | use embassy_stm32::low_power::Executor; |
| 8 | use embassy_stm32::rcc::LsConfig; | 8 | use embassy_stm32::rcc::LsConfig; |
| 9 | use embassy_stm32::rtc::{Rtc, RtcConfig}; | ||
| 10 | use embassy_stm32::{Config, Peri}; | 9 | use embassy_stm32::{Config, Peri}; |
| 11 | use embassy_time::Timer; | 10 | use embassy_time::Timer; |
| 12 | use {defmt_rtt as _, panic_probe as _}; | 11 | use {defmt_rtt as _, panic_probe as _}; |
| @@ -27,10 +26,6 @@ async fn async_main(spawner: Spawner) { | |||
| 27 | // config.enable_debug_during_sleep = false; | 26 | // config.enable_debug_during_sleep = false; |
| 28 | let p = embassy_stm32::init(config); | 27 | let p = embassy_stm32::init(config); |
| 29 | 28 | ||
| 30 | // give the RTC to the executor... | ||
| 31 | let rtc = Rtc::new(p.RTC, RtcConfig::default()); | ||
| 32 | embassy_stm32::low_power::stop_with_rtc(rtc); | ||
| 33 | |||
| 34 | spawner.spawn(unwrap!(blinky(p.PC7.into()))); | 29 | spawner.spawn(unwrap!(blinky(p.PC7.into()))); |
| 35 | spawner.spawn(unwrap!(timeout())); | 30 | spawner.spawn(unwrap!(timeout())); |
| 36 | } | 31 | } |
diff --git a/examples/stm32wle5/src/bin/adc.rs b/examples/stm32wle5/src/bin/adc.rs index ff1a5fa16..8b830a1e6 100644 --- a/examples/stm32wle5/src/bin/adc.rs +++ b/examples/stm32wle5/src/bin/adc.rs | |||
| @@ -7,7 +7,6 @@ use defmt_rtt as _; | |||
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 8 | use embassy_stm32::adc::{Adc, SampleTime}; | 8 | use embassy_stm32::adc::{Adc, SampleTime}; |
| 9 | use embassy_stm32::low_power::Executor; | 9 | use embassy_stm32::low_power::Executor; |
| 10 | use embassy_stm32::rtc::{Rtc, RtcConfig}; | ||
| 11 | use embassy_time::Timer; | 10 | use embassy_time::Timer; |
| 12 | use panic_probe as _; | 11 | use panic_probe as _; |
| 13 | use static_cell::StaticCell; | 12 | use static_cell::StaticCell; |
| @@ -71,11 +70,6 @@ async fn async_main(_spawner: Spawner) { | |||
| 71 | defmt_serial::defmt_serial(SERIAL.init(uart)); | 70 | defmt_serial::defmt_serial(SERIAL.init(uart)); |
| 72 | } | 71 | } |
| 73 | 72 | ||
| 74 | // give the RTC to the low_power executor... | ||
| 75 | let rtc_config = RtcConfig::default(); | ||
| 76 | let rtc = Rtc::new(p.RTC, rtc_config); | ||
| 77 | embassy_stm32::low_power::stop_with_rtc(rtc); | ||
| 78 | |||
| 79 | info!("Hello World!"); | 73 | info!("Hello World!"); |
| 80 | 74 | ||
| 81 | let mut adc = Adc::new(p.ADC1); | 75 | let mut adc = Adc::new(p.ADC1); |
diff --git a/examples/stm32wle5/src/bin/blinky.rs b/examples/stm32wle5/src/bin/blinky.rs index 1191a1157..b2745fdaf 100644 --- a/examples/stm32wle5/src/bin/blinky.rs +++ b/examples/stm32wle5/src/bin/blinky.rs | |||
| @@ -7,7 +7,6 @@ use defmt_rtt as _; | |||
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 8 | use embassy_stm32::gpio::{Level, Output, Speed}; | 8 | use embassy_stm32::gpio::{Level, Output, Speed}; |
| 9 | use embassy_stm32::low_power::Executor; | 9 | use embassy_stm32::low_power::Executor; |
| 10 | use embassy_stm32::rtc::{Rtc, RtcConfig}; | ||
| 11 | use embassy_time::Timer; | 10 | use embassy_time::Timer; |
| 12 | use panic_probe as _; | 11 | use panic_probe as _; |
| 13 | use static_cell::StaticCell; | 12 | use static_cell::StaticCell; |
| @@ -69,11 +68,6 @@ async fn async_main(_spawner: Spawner) { | |||
| 69 | defmt_serial::defmt_serial(SERIAL.init(uart)); | 68 | defmt_serial::defmt_serial(SERIAL.init(uart)); |
| 70 | } | 69 | } |
| 71 | 70 | ||
| 72 | // give the RTC to the low_power executor... | ||
| 73 | let rtc_config = RtcConfig::default(); | ||
| 74 | let rtc = Rtc::new(p.RTC, rtc_config); | ||
| 75 | embassy_stm32::low_power::stop_with_rtc(rtc); | ||
| 76 | |||
| 77 | info!("Hello World!"); | 71 | info!("Hello World!"); |
| 78 | 72 | ||
| 79 | let mut led = Output::new(p.PB5, Level::High, Speed::Low); | 73 | let mut led = Output::new(p.PB5, Level::High, Speed::Low); |
diff --git a/examples/stm32wle5/src/bin/button_exti.rs b/examples/stm32wle5/src/bin/button_exti.rs index f07f9724d..db1bff0be 100644 --- a/examples/stm32wle5/src/bin/button_exti.rs +++ b/examples/stm32wle5/src/bin/button_exti.rs | |||
| @@ -8,7 +8,6 @@ use embassy_executor::Spawner; | |||
| 8 | use embassy_stm32::exti::ExtiInput; | 8 | use embassy_stm32::exti::ExtiInput; |
| 9 | use embassy_stm32::gpio::Pull; | 9 | use embassy_stm32::gpio::Pull; |
| 10 | use embassy_stm32::low_power::Executor; | 10 | use embassy_stm32::low_power::Executor; |
| 11 | use embassy_stm32::rtc::{Rtc, RtcConfig}; | ||
| 12 | use panic_probe as _; | 11 | use panic_probe as _; |
| 13 | use static_cell::StaticCell; | 12 | use static_cell::StaticCell; |
| 14 | 13 | ||
| @@ -71,11 +70,6 @@ async fn async_main(_spawner: Spawner) { | |||
| 71 | defmt_serial::defmt_serial(SERIAL.init(uart)); | 70 | defmt_serial::defmt_serial(SERIAL.init(uart)); |
| 72 | } | 71 | } |
| 73 | 72 | ||
| 74 | // give the RTC to the low_power executor... | ||
| 75 | let rtc_config = RtcConfig::default(); | ||
| 76 | let rtc = Rtc::new(p.RTC, rtc_config); | ||
| 77 | embassy_stm32::low_power::stop_with_rtc(rtc); | ||
| 78 | |||
| 79 | info!("Hello World!"); | 73 | info!("Hello World!"); |
| 80 | 74 | ||
| 81 | let mut button = ExtiInput::new(p.PA0, p.EXTI0, Pull::Up); | 75 | let mut button = ExtiInput::new(p.PA0, p.EXTI0, Pull::Up); |
diff --git a/examples/stm32wle5/src/bin/i2c.rs b/examples/stm32wle5/src/bin/i2c.rs index af07f911e..c31c673c9 100644 --- a/examples/stm32wle5/src/bin/i2c.rs +++ b/examples/stm32wle5/src/bin/i2c.rs | |||
| @@ -7,7 +7,6 @@ use defmt_rtt as _; | |||
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 8 | use embassy_stm32::i2c::I2c; | 8 | use embassy_stm32::i2c::I2c; |
| 9 | use embassy_stm32::low_power::Executor; | 9 | use embassy_stm32::low_power::Executor; |
| 10 | use embassy_stm32::rtc::{Rtc, RtcConfig}; | ||
| 11 | use embassy_stm32::time::Hertz; | 10 | use embassy_stm32::time::Hertz; |
| 12 | use embassy_stm32::{bind_interrupts, i2c, peripherals}; | 11 | use embassy_stm32::{bind_interrupts, i2c, peripherals}; |
| 13 | use embassy_time::{Duration, Timer}; | 12 | use embassy_time::{Duration, Timer}; |
| @@ -78,11 +77,6 @@ async fn async_main(_spawner: Spawner) { | |||
| 78 | defmt_serial::defmt_serial(SERIAL.init(uart)); | 77 | defmt_serial::defmt_serial(SERIAL.init(uart)); |
| 79 | } | 78 | } |
| 80 | 79 | ||
| 81 | // give the RTC to the low_power executor... | ||
| 82 | let rtc_config = RtcConfig::default(); | ||
| 83 | let rtc = Rtc::new(p.RTC, rtc_config); | ||
| 84 | embassy_stm32::low_power::stop_with_rtc(rtc); | ||
| 85 | |||
| 86 | info!("Hello World!"); | 80 | info!("Hello World!"); |
| 87 | let en3v3 = embassy_stm32::gpio::Output::new( | 81 | let en3v3 = embassy_stm32::gpio::Output::new( |
| 88 | p.PA9, | 82 | p.PA9, |
diff --git a/tests/stm32/src/bin/rtc.rs b/tests/stm32/src/bin/rtc.rs index 5fe98d807..5c80eb250 100644 --- a/tests/stm32/src/bin/rtc.rs +++ b/tests/stm32/src/bin/rtc.rs | |||
| @@ -9,10 +9,14 @@ use chrono::{NaiveDate, NaiveDateTime}; | |||
| 9 | use common::*; | 9 | use common::*; |
| 10 | use defmt::assert; | 10 | use defmt::assert; |
| 11 | use embassy_executor::Spawner; | 11 | use embassy_executor::Spawner; |
| 12 | #[cfg(feature = "stop")] | ||
| 13 | use embassy_stm32::low_power::reconfigure_rtc; | ||
| 12 | use embassy_stm32::rcc::LsConfig; | 14 | use embassy_stm32::rcc::LsConfig; |
| 15 | #[cfg(feature = "stop")] | ||
| 16 | use embassy_stm32::rtc::RtcTimeProvider; | ||
| 17 | #[cfg(not(feature = "stop"))] | ||
| 13 | use embassy_stm32::rtc::{Rtc, RtcConfig}; | 18 | use embassy_stm32::rtc::{Rtc, RtcConfig}; |
| 14 | use embassy_time::Timer; | 19 | use embassy_time::Timer; |
| 15 | |||
| 16 | #[embassy_executor::main] | 20 | #[embassy_executor::main] |
| 17 | async fn main(_spawner: Spawner) { | 21 | async fn main(_spawner: Spawner) { |
| 18 | let mut config = config(); | 22 | let mut config = config(); |
| @@ -26,14 +30,26 @@ async fn main(_spawner: Spawner) { | |||
| 26 | .and_hms_opt(10, 30, 15) | 30 | .and_hms_opt(10, 30, 15) |
| 27 | .unwrap(); | 31 | .unwrap(); |
| 28 | 32 | ||
| 33 | #[cfg(not(feature = "stop"))] | ||
| 29 | let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); | 34 | let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); |
| 30 | 35 | ||
| 36 | #[cfg(feature = "stop")] | ||
| 37 | let time_provider = RtcTimeProvider::new(p.RTC); | ||
| 38 | |||
| 39 | #[cfg(not(feature = "stop"))] | ||
| 31 | rtc.set_datetime(now.into()).expect("datetime not set"); | 40 | rtc.set_datetime(now.into()).expect("datetime not set"); |
| 32 | 41 | ||
| 42 | #[cfg(feature = "stop")] | ||
| 43 | reconfigure_rtc(|rtc| rtc.set_datetime(now.into()).expect("datetime not set")); | ||
| 44 | |||
| 33 | info!("Waiting 5 seconds"); | 45 | info!("Waiting 5 seconds"); |
| 34 | Timer::after_millis(5000).await; | 46 | Timer::after_millis(5000).await; |
| 35 | 47 | ||
| 48 | #[cfg(not(feature = "stop"))] | ||
| 36 | let then: NaiveDateTime = rtc.now().unwrap().into(); | 49 | let then: NaiveDateTime = rtc.now().unwrap().into(); |
| 50 | #[cfg(feature = "stop")] | ||
| 51 | let then: NaiveDateTime = time_provider.now().unwrap().into(); | ||
| 52 | |||
| 37 | let seconds = (then - now).num_seconds(); | 53 | let seconds = (then - now).num_seconds(); |
| 38 | 54 | ||
| 39 | info!("measured = {}", seconds); | 55 | info!("measured = {}", seconds); |
diff --git a/tests/stm32/src/bin/stop.rs b/tests/stm32/src/bin/stop.rs index 73580f0f2..a9dbac676 100644 --- a/tests/stm32/src/bin/stop.rs +++ b/tests/stm32/src/bin/stop.rs | |||
| @@ -10,9 +10,8 @@ use common::*; | |||
| 10 | use cortex_m_rt::entry; | 10 | use cortex_m_rt::entry; |
| 11 | use embassy_executor::Spawner; | 11 | use embassy_executor::Spawner; |
| 12 | use embassy_stm32::Config; | 12 | use embassy_stm32::Config; |
| 13 | use embassy_stm32::low_power::{Executor, StopMode, stop_ready, stop_with_rtc}; | 13 | use embassy_stm32::low_power::{Executor, StopMode, reconfigure_rtc, stop_ready}; |
| 14 | use embassy_stm32::rcc::LsConfig; | 14 | use embassy_stm32::rcc::LsConfig; |
| 15 | use embassy_stm32::rtc::{Rtc, RtcConfig}; | ||
| 16 | use embassy_time::Timer; | 15 | use embassy_time::Timer; |
| 17 | 16 | ||
| 18 | #[entry] | 17 | #[entry] |
| @@ -57,7 +56,7 @@ async fn async_main(spawner: Spawner) { | |||
| 57 | config.rcc.hsi = Some(HSIPrescaler::DIV4); // 64 MHz HSI will need a /4 | 56 | config.rcc.hsi = Some(HSIPrescaler::DIV4); // 64 MHz HSI will need a /4 |
| 58 | } | 57 | } |
| 59 | 58 | ||
| 60 | let p = init_with_config(config); | 59 | let _p = init_with_config(config); |
| 61 | info!("Hello World!"); | 60 | info!("Hello World!"); |
| 62 | 61 | ||
| 63 | let now = NaiveDate::from_ymd_opt(2020, 5, 15) | 62 | let now = NaiveDate::from_ymd_opt(2020, 5, 15) |
| @@ -65,11 +64,7 @@ async fn async_main(spawner: Spawner) { | |||
| 65 | .and_hms_opt(10, 30, 15) | 64 | .and_hms_opt(10, 30, 15) |
| 66 | .unwrap(); | 65 | .unwrap(); |
| 67 | 66 | ||
| 68 | let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); | 67 | reconfigure_rtc(|rtc| rtc.set_datetime(now.into()).expect("datetime not set")); |
| 69 | |||
| 70 | rtc.set_datetime(now.into()).expect("datetime not set"); | ||
| 71 | |||
| 72 | stop_with_rtc(rtc); | ||
| 73 | 68 | ||
| 74 | spawner.spawn(task_1().unwrap()); | 69 | spawner.spawn(task_1().unwrap()); |
| 75 | spawner.spawn(task_2().unwrap()); | 70 | spawner.spawn(task_2().unwrap()); |
