From 997ad131325a30f79ef5bf407200830ce488302e Mon Sep 17 00:00:00 2001 From: xoviat Date: Sat, 6 Dec 2025 15:24:30 -0600 Subject: low-power: improve debug logic --- embassy-stm32/src/exti.rs | 2 +- embassy-stm32/src/i2c/v2.rs | 2 +- embassy-stm32/src/low_power.rs | 46 ++++++++++++++++++++++------------------ embassy-stm32/src/rcc/mod.rs | 2 +- embassy-stm32/src/time_driver.rs | 6 ++++++ embassy-stm32/src/timer/mod.rs | 4 ++-- 6 files changed, 36 insertions(+), 26 deletions(-) diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index 7b7896d46..458174b5d 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs @@ -74,7 +74,7 @@ unsafe fn on_irq() { } #[cfg(feature = "low-power")] - crate::low_power::Executor::on_wakeup_irq(); + crate::low_power::Executor::on_wakeup_irq_or_event(); } struct BitIter(u32); diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 6b213484c..7ad9978b1 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() { // restore the clocks to their last configured state as // much is lost in STOP modes #[cfg(all(feature = "low-power", stm32wlex))] - crate::low_power::Executor::on_wakeup_irq(); + crate::low_power::Executor::on_wakeup_irq_or_event(); let regs = T::info().regs; let isr = regs.isr().read(); diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index cdf3323fb..94217f07f 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -88,7 +88,7 @@ foreach_interrupt! { #[interrupt] #[allow(non_snake_case)] unsafe fn $irq() { - Executor::on_wakeup_irq(); + Executor::on_wakeup_irq_or_event(); } }; } @@ -99,7 +99,7 @@ foreach_interrupt! { #[interrupt] #[allow(non_snake_case)] unsafe fn $irq() { - Executor::on_wakeup_irq(); + Executor::on_wakeup_irq_or_event(); } }; } @@ -164,7 +164,11 @@ impl Executor { } } - pub(crate) unsafe fn on_wakeup_irq() { + pub(crate) unsafe fn on_wakeup_irq_or_event() { + if !get_driver().is_stopped() { + return; + } + critical_section::with(|cs| { #[cfg(stm32wlex)] { @@ -172,6 +176,17 @@ impl Executor { use crate::pac::{PWR, RCC}; use crate::rcc::init as init_rcc; + let es = crate::pac::PWR.extscr().read(); + match (es.c1stopf(), es.c1stop2f()) { + (true, false) => debug!("low power: wake from STOP1"), + (false, true) => debug!("low power: wake from STOP2"), + (true, true) => debug!("low power: wake from STOP1 and STOP2 ???"), + (false, false) => trace!("low power: stop mode not entered"), + }; + crate::pac::PWR.extscr().modify(|w| { + w.set_c1cssf(false); + }); + let extscr = PWR.extscr().read(); if extscr.c1stop2f() || extscr.c1stopf() { // when we wake from any stop mode we need to re-initialize the rcc @@ -190,7 +205,8 @@ impl Executor { } } get_driver().resume_time(cs); - trace!("low power: resume"); + + trace!("low power: resume time"); }); } @@ -201,10 +217,8 @@ impl Executor { fn stop_mode(_cs: CriticalSection) -> Option { // We cannot enter standby because we will lose program state. if unsafe { REFCOUNT_STOP2 == 0 && REFCOUNT_STOP1 == 0 } { - trace!("low power: stop 2"); Some(StopMode::Stop2) } else if unsafe { REFCOUNT_STOP1 == 0 } { - trace!("low power: stop 1"); Some(StopMode::Stop1) } else { trace!("low power: not ready to stop (refcount_stop1: {})", unsafe { @@ -305,9 +319,11 @@ impl Executor { get_driver().pause_time(cs).ok()?; self.configure_stop(cs, stop_mode).ok()?; - Some(()) + Some(stop_mode) }) - .map(|_| { + .map(|stop_mode| { + trace!("low power: enter stop: {}", stop_mode); + #[cfg(not(feature = "low-power-debug-with-sleep"))] Self::get_scb().set_sleepdeep(); }); @@ -339,19 +355,7 @@ impl Executor { self.inner.poll(); self.configure_pwr(); asm!("wfe"); - #[cfg(stm32wlex)] - { - let es = crate::pac::PWR.extscr().read(); - match (es.c1stopf(), es.c1stop2f()) { - (true, false) => debug!("low power: wake from STOP1"), - (false, true) => debug!("low power: wake from STOP2"), - (true, true) => debug!("low power: wake from STOP1 and STOP2 ???"), - (false, false) => trace!("low power: stop mode not entered"), - }; - crate::pac::PWR.extscr().modify(|w| { - w.set_c1cssf(false); - }); - } + Self::on_wakeup_irq_or_event(); }; } } diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 1dd634cfe..5890e68f4 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -172,7 +172,7 @@ pub(crate) struct RccInfo { /// E.g. if `StopMode::Stop1` is selected, the peripheral prevents the chip from entering Stop1 mode. #[cfg(feature = "low-power")] #[allow(dead_code)] -#[derive(Debug, Clone, Copy, PartialEq, Default)] +#[derive(Debug, Clone, Copy, PartialEq, Default, defmt::Format)] pub enum StopMode { #[default] /// Peripheral prevents chip from entering Stop1 or executor will enter Stop1 diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index cfcf5f3fd..ed5d902bd 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -329,6 +329,12 @@ impl RtcDriver { regs_gp16().cr1().modify(|w| w.set_cen(true)); } + #[cfg(feature = "low-power")] + /// Returns whether time is currently stopped + pub(crate) fn is_stopped(&self) -> bool { + !regs_gp16().cr1().read().cen() + } + fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool { let r = regs_gp16(); diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 74d1c9e77..998e3a6f4 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -406,7 +406,7 @@ pub struct UpdateInterruptHandler { impl interrupt::typelevel::Handler for UpdateInterruptHandler { unsafe fn on_interrupt() { #[cfg(feature = "low-power")] - crate::low_power::Executor::on_wakeup_irq(); + crate::low_power::Executor::on_wakeup_irq_or_event(); let regs = crate::pac::timer::TimCore::from_ptr(T::regs()); @@ -436,7 +436,7 @@ impl interrupt::typelevel::Handler