diff --git a/ci.sh b/ci.sh index 5c69d3a2..2e6bbae8 100755 --- a/ci.sh +++ b/ci.sh @@ -218,8 +218,6 @@ cargo batch \ rm out/tests/stm32wb55rg/wpan_mac rm out/tests/stm32wb55rg/wpan_ble -# unstable -rm out/tests/stm32f429zi/stop # unstable, I think it's running out of RAM? rm out/tests/stm32f207zg/eth diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index bc79ab7a..2a2df5c5 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -90,6 +90,7 @@ defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-emb exti = [] low-power = [ "dep:embassy-executor", "embassy-executor/arch-cortex-m" ] +low-power-debug-with-sleep = [] embassy-executor = [] ## Automatically generate `memory.x` file using [`stm32-metapac`](https://docs.rs/stm32-metapac/) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 3400529c..276c1d63 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -556,6 +556,32 @@ fn main() { }, }; + /* + If LP and non-LP peripherals share the same RCC enable bit, then a refcount leak will result. + + This should be checked in stm32-data-gen. + */ + let stop_refcount = if p.name.starts_with("LP") { + quote! { REFCOUNT_STOP2 } + } else { + quote! { REFCOUNT_STOP1 } + }; + + let (incr_stop_refcount, decr_stop_refcount) = if p.name != "RTC" { + ( + quote! { + #[cfg(feature = "low-power")] + unsafe { crate::rcc::#stop_refcount += 1 }; + }, + quote! { + #[cfg(feature = "low-power")] + unsafe { crate::rcc::#stop_refcount -= 1 }; + }, + ) + } else { + (quote! {}, quote! {}) + }; + g.extend(quote! { impl crate::rcc::sealed::RccPeripheral for peripherals::#pname { fn frequency() -> crate::time::Hertz { @@ -563,8 +589,7 @@ fn main() { } fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) { #before_enable - #[cfg(feature = "low-power")] - unsafe { crate::rcc::REFCOUNT_STOP2 += 1 }; + #incr_stop_refcount crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true)); #after_enable #rst @@ -572,8 +597,7 @@ fn main() { fn disable_with_cs(_cs: critical_section::CriticalSection) { #before_disable crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false)); - #[cfg(feature = "low-power")] - unsafe { crate::rcc::REFCOUNT_STOP2 -= 1 }; + #decr_stop_refcount } } diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 23d42bae..511da917 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -228,8 +228,9 @@ pub fn init(config: Config) -> Peripherals { #[cfg(feature = "low-power")] { - crate::rcc::REFCOUNT_STOP2 = 0 - }; + crate::rcc::REFCOUNT_STOP2 = 0; + crate::rcc::REFCOUNT_STOP1 = 0; + } } p diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index aea3a5ce..20d8f904 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -80,11 +80,17 @@ pub fn stop_with_rtc(rtc: &'static Rtc) { } pub fn stop_ready(stop_mode: StopMode) -> bool { - unsafe { EXECUTOR.as_mut().unwrap() }.stop_ready(stop_mode) + match unsafe { EXECUTOR.as_mut().unwrap() }.stop_mode() { + Some(StopMode::Stop2) => true, + Some(StopMode::Stop1) => stop_mode == StopMode::Stop1, + None => false, + } } #[non_exhaustive] +#[derive(PartialEq)] pub enum StopMode { + Stop1, Stop2, } @@ -135,23 +141,39 @@ impl Executor { trace!("low power: stop with rtc configured"); } - fn stop_ready(&self, stop_mode: StopMode) -> bool { - match stop_mode { - StopMode::Stop2 => unsafe { crate::rcc::REFCOUNT_STOP2 == 0 }, + fn stop_mode(&self) -> Option { + if unsafe { crate::rcc::REFCOUNT_STOP2 == 0 } && unsafe { crate::rcc::REFCOUNT_STOP1 == 0 } { + Some(StopMode::Stop2) + } else if unsafe { crate::rcc::REFCOUNT_STOP1 == 0 } { + Some(StopMode::Stop1) + } else { + None } } + fn configure_stop(&mut self, _stop_mode: StopMode) { + // TODO: configure chip-specific settings for stop + } + fn configure_pwr(&mut self) { self.scb.clear_sleepdeep(); compiler_fence(Ordering::SeqCst); - if !self.stop_ready(StopMode::Stop2) { + let stop_mode = self.stop_mode(); + if stop_mode.is_none() { trace!("low power: not ready to stop"); } else if self.time_driver.pause_time().is_err() { trace!("low power: failed to pause time"); } else { - trace!("low power: stop"); + let stop_mode = stop_mode.unwrap(); + match stop_mode { + StopMode::Stop1 => trace!("low power: stop 1"), + StopMode::Stop2 => trace!("low power: stop 2"), + } + self.configure_stop(stop_mode); + + #[cfg(not(feature = "low-power-debug-with-sleep"))] self.scb.set_sleepdeep(); } } diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 3b19e4b9..c11a9cc6 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -181,6 +181,15 @@ pub struct Clocks { } #[cfg(feature = "low-power")] +/// Must be written within a critical section +/// +/// May be read without a critical section +pub(crate) static mut REFCOUNT_STOP1: u32 = 0; + +#[cfg(feature = "low-power")] +/// Must be written within a critical section +/// +/// May be read without a critical section pub(crate) static mut REFCOUNT_STOP2: u32 = 0; /// Frozen clock frequencies diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index e527fdfe..e94a5857 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -153,14 +153,7 @@ impl Default for RtcCalibrationCyclePeriod { impl Rtc { pub fn new(_rtc: impl Peripheral

, rtc_config: RtcConfig) -> Self { #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))] - critical_section::with(|cs| { - ::enable_and_reset_with_cs(cs); - - #[cfg(feature = "low-power")] - unsafe { - crate::rcc::REFCOUNT_STOP2 -= 1 - }; - }); + ::enable_and_reset(); let mut this = Self { #[cfg(feature = "low-power")] diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 14f27678..4b769b1c 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -33,7 +33,7 @@ stm32wl55jc = ["embassy-stm32/stm32wl55jc-cm4", "not-gpdma", "rng", "chrono"] eth = [] rng = [] sdmmc = [] -stop = ["embassy-stm32/low-power"] +stop = ["embassy-stm32/low-power", "embassy-stm32/low-power-debug-with-sleep"] chrono = ["embassy-stm32/chrono", "dep:chrono"] can = [] ble = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/ble"]