aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/low_power.rs
diff options
context:
space:
mode:
authorliebman <[email protected]>2025-10-22 14:24:01 -0700
committerliebman <[email protected]>2025-11-03 12:50:36 -0800
commitea94cb58a2016b1ab408aa975192de7aefe52ec5 (patch)
tree9f954331a22d65f1565dd54362043a4a674cdfad /embassy-stm32/src/low_power.rs
parent36aa3e10aaf27bb1bd1109a203b378dc93b90b02 (diff)
use DeviceBusy to mark when stop1 or stop2 is unavailable.
Diffstat (limited to 'embassy-stm32/src/low_power.rs')
-rw-r--r--embassy-stm32/src/low_power.rs78
1 files changed, 65 insertions, 13 deletions
diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs
index 4cdaf6a00..0ee81fd18 100644
--- a/embassy-stm32/src/low_power.rs
+++ b/embassy-stm32/src/low_power.rs
@@ -68,6 +68,39 @@ use crate::rtc::Rtc;
68 68
69static mut EXECUTOR: Option<Executor> = None; 69static mut EXECUTOR: Option<Executor> = None;
70 70
71#[cfg(stm32wlex)]
72pub(crate) use self::busy::DeviceBusy;
73#[cfg(stm32wlex)]
74mod busy {
75 use core::sync::atomic::{AtomicU32, Ordering};
76
77 // Count of devices blocking STOP
78 static STOP_BLOCKED: AtomicU32 = AtomicU32::new(0);
79
80 /// Check if STOP1 is blocked.
81 pub(crate) fn stop_blocked() -> bool {
82 STOP_BLOCKED.load(Ordering::SeqCst) > 0
83 }
84
85 /// When ca device goes busy it will construct one of these where it will be dropped when the device goes idle.
86 pub(crate) struct DeviceBusy {}
87
88 impl DeviceBusy {
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 impl Drop for DeviceBusy {
98 fn drop(&mut self) {
99 STOP_BLOCKED.fetch_sub(1, Ordering::SeqCst);
100 trace!("low power: device idle: Stop:{}", STOP_BLOCKED.load(Ordering::SeqCst));
101 }
102 }
103}
71#[cfg(not(stm32u0))] 104#[cfg(not(stm32u0))]
72foreach_interrupt! { 105foreach_interrupt! {
73 (RTC, rtc, $block:ident, WKUP, $irq:ident) => { 106 (RTC, rtc, $block:ident, WKUP, $irq:ident) => {
@@ -92,6 +125,7 @@ foreach_interrupt! {
92 125
93#[allow(dead_code)] 126#[allow(dead_code)]
94pub(crate) unsafe fn on_wakeup_irq() { 127pub(crate) unsafe fn on_wakeup_irq() {
128 info!("low power: on wakeup irq: extscr: {:?}", crate::pac::PWR.extscr().read());
95 EXECUTOR.as_mut().unwrap().on_wakeup_irq(); 129 EXECUTOR.as_mut().unwrap().on_wakeup_irq();
96} 130}
97 131
@@ -180,19 +214,22 @@ impl Executor {
180 } 214 }
181 215
182 unsafe fn on_wakeup_irq(&mut self) { 216 unsafe fn on_wakeup_irq(&mut self) {
183 // when we wake from STOP2, we need to re-initialize the rcc and the time driver
184 // to restore the clocks to their last configured state
185 #[cfg(stm32wlex)] 217 #[cfg(stm32wlex)]
186 crate::rcc::apply_resume_config(); 218 {
187 #[cfg(stm32wlex)] 219 let extscr = crate::pac::PWR.extscr().read();
188 if crate::pac::PWR.extscr().read().c1stop2f() { 220 if extscr.c1stop2f() || extscr.c1stopf() {
189 critical_section::with(|cs| crate::time_driver::init_timer(cs)); 221 // when we wake from any stop mode we need to re-initialize the rcc
190 // reset the refcounts for STOP2 and STOP1 (initializing the time driver will increment one of them for the timer) 222 crate::rcc::apply_resume_config();
191 // and given that we just woke from STOP2, we can reset them 223 if extscr.c1stop2f() {
192 crate::rcc::REFCOUNT_STOP2 = 0; 224 // when we wake from STOP2, we need to re-initialize the time driver
193 crate::rcc::REFCOUNT_STOP1 = 0; 225 critical_section::with(|cs| crate::time_driver::init_timer(cs));
226 // reset the refcounts for STOP2 and STOP1 (initializing the time driver will increment one of them for the timer)
227 // and given that we just woke from STOP2, we can reset them
228 crate::rcc::REFCOUNT_STOP2 = 0;
229 crate::rcc::REFCOUNT_STOP1 = 0;
230 }
231 }
194 } 232 }
195
196 self.time_driver.resume_time(); 233 self.time_driver.resume_time();
197 trace!("low power: resume"); 234 trace!("low power: resume");
198 } 235 }
@@ -208,10 +245,22 @@ impl Executor {
208 self.time_driver.reconfigure_rtc(f); 245 self.time_driver.reconfigure_rtc(f);
209 } 246 }
210 247
248 fn stop1_ok_to_enter(&self) -> bool {
249 #[cfg(stm32wlex)]
250 if self::busy::stop_blocked() {
251 return false;
252 }
253 unsafe { crate::rcc::REFCOUNT_STOP1 == 0 }
254 }
255
256 fn stop2_ok_to_enter(&self) -> bool {
257 self.stop1_ok_to_enter() && unsafe { crate::rcc::REFCOUNT_STOP2 == 0 }
258 }
259
211 fn stop_mode(&self) -> Option<StopMode> { 260 fn stop_mode(&self) -> Option<StopMode> {
212 if unsafe { crate::rcc::REFCOUNT_STOP2 == 0 } && unsafe { crate::rcc::REFCOUNT_STOP1 == 0 } { 261 if self.stop2_ok_to_enter() {
213 Some(StopMode::Stop2) 262 Some(StopMode::Stop2)
214 } else if unsafe { crate::rcc::REFCOUNT_STOP1 == 0 } { 263 } else if self.stop1_ok_to_enter() {
215 Some(StopMode::Stop1) 264 Some(StopMode::Stop1)
216 } else { 265 } else {
217 None 266 None
@@ -299,6 +348,9 @@ impl Executor {
299 (true, true) => trace!("low power: wake from STOP1 and STOP2 ???"), 348 (true, true) => trace!("low power: wake from STOP1 and STOP2 ???"),
300 (false, false) => trace!("low power: stop mode not entered"), 349 (false, false) => trace!("low power: stop mode not entered"),
301 }; 350 };
351 crate::pac::PWR.extscr().modify(|w| {
352 w.set_c1cssf(false);
353 });
302 } 354 }
303 }; 355 };
304 } 356 }