diff options
| author | xoviat <[email protected]> | 2023-11-04 18:57:44 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-11-04 18:57:44 +0000 |
| commit | 056c409443b8280fc951669d15df2fb59521a4d8 (patch) | |
| tree | 3375dd57e07879f2d709f7547d95b2a7f757ae14 | |
| parent | 655ed3aa887fe2d9e424f239cc07db055d8f8d61 (diff) | |
| parent | 3f2abd4fd5da51d7b8a7711d0eac02c7f7b9deed (diff) | |
Merge pull request #2140 from xoviat/low-power
stm32: compute stop mode and workaround rtt test bug
| -rwxr-xr-x | ci.sh | 2 | ||||
| -rw-r--r-- | embassy-stm32/Cargo.toml | 1 | ||||
| -rw-r--r-- | embassy-stm32/build.rs | 32 | ||||
| -rw-r--r-- | embassy-stm32/src/lib.rs | 5 | ||||
| -rw-r--r-- | embassy-stm32/src/low_power.rs | 34 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/mod.rs | 9 | ||||
| -rw-r--r-- | embassy-stm32/src/rtc/mod.rs | 9 | ||||
| -rw-r--r-- | tests/stm32/Cargo.toml | 2 |
8 files changed, 71 insertions, 23 deletions
| @@ -218,8 +218,6 @@ cargo batch \ | |||
| 218 | rm out/tests/stm32wb55rg/wpan_mac | 218 | rm out/tests/stm32wb55rg/wpan_mac |
| 219 | rm out/tests/stm32wb55rg/wpan_ble | 219 | rm out/tests/stm32wb55rg/wpan_ble |
| 220 | 220 | ||
| 221 | # unstable | ||
| 222 | rm out/tests/stm32f429zi/stop | ||
| 223 | 221 | ||
| 224 | # unstable, I think it's running out of RAM? | 222 | # unstable, I think it's running out of RAM? |
| 225 | rm out/tests/stm32f207zg/eth | 223 | rm out/tests/stm32f207zg/eth |
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index bc79ab7a2..2a2df5c56 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 | |||
| 90 | 90 | ||
| 91 | exti = [] | 91 | exti = [] |
| 92 | low-power = [ "dep:embassy-executor", "embassy-executor/arch-cortex-m" ] | 92 | low-power = [ "dep:embassy-executor", "embassy-executor/arch-cortex-m" ] |
| 93 | low-power-debug-with-sleep = [] | ||
| 93 | embassy-executor = [] | 94 | embassy-executor = [] |
| 94 | 95 | ||
| 95 | ## Automatically generate `memory.x` file using [`stm32-metapac`](https://docs.rs/stm32-metapac/) | 96 | ## 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 3400529c9..276c1d637 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs | |||
| @@ -556,6 +556,32 @@ fn main() { | |||
| 556 | }, | 556 | }, |
| 557 | }; | 557 | }; |
| 558 | 558 | ||
| 559 | /* | ||
| 560 | If LP and non-LP peripherals share the same RCC enable bit, then a refcount leak will result. | ||
| 561 | |||
| 562 | This should be checked in stm32-data-gen. | ||
| 563 | */ | ||
| 564 | let stop_refcount = if p.name.starts_with("LP") { | ||
| 565 | quote! { REFCOUNT_STOP2 } | ||
| 566 | } else { | ||
| 567 | quote! { REFCOUNT_STOP1 } | ||
| 568 | }; | ||
| 569 | |||
| 570 | let (incr_stop_refcount, decr_stop_refcount) = if p.name != "RTC" { | ||
| 571 | ( | ||
| 572 | quote! { | ||
| 573 | #[cfg(feature = "low-power")] | ||
| 574 | unsafe { crate::rcc::#stop_refcount += 1 }; | ||
| 575 | }, | ||
| 576 | quote! { | ||
| 577 | #[cfg(feature = "low-power")] | ||
| 578 | unsafe { crate::rcc::#stop_refcount -= 1 }; | ||
| 579 | }, | ||
| 580 | ) | ||
| 581 | } else { | ||
| 582 | (quote! {}, quote! {}) | ||
| 583 | }; | ||
| 584 | |||
| 559 | g.extend(quote! { | 585 | g.extend(quote! { |
| 560 | impl crate::rcc::sealed::RccPeripheral for peripherals::#pname { | 586 | impl crate::rcc::sealed::RccPeripheral for peripherals::#pname { |
| 561 | fn frequency() -> crate::time::Hertz { | 587 | fn frequency() -> crate::time::Hertz { |
| @@ -563,8 +589,7 @@ fn main() { | |||
| 563 | } | 589 | } |
| 564 | fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) { | 590 | fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) { |
| 565 | #before_enable | 591 | #before_enable |
| 566 | #[cfg(feature = "low-power")] | 592 | #incr_stop_refcount |
| 567 | unsafe { crate::rcc::REFCOUNT_STOP2 += 1 }; | ||
| 568 | crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true)); | 593 | crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true)); |
| 569 | #after_enable | 594 | #after_enable |
| 570 | #rst | 595 | #rst |
| @@ -572,8 +597,7 @@ fn main() { | |||
| 572 | fn disable_with_cs(_cs: critical_section::CriticalSection) { | 597 | fn disable_with_cs(_cs: critical_section::CriticalSection) { |
| 573 | #before_disable | 598 | #before_disable |
| 574 | crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false)); | 599 | crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false)); |
| 575 | #[cfg(feature = "low-power")] | 600 | #decr_stop_refcount |
| 576 | unsafe { crate::rcc::REFCOUNT_STOP2 -= 1 }; | ||
| 577 | } | 601 | } |
| 578 | } | 602 | } |
| 579 | 603 | ||
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 23d42bae8..511da9179 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs | |||
| @@ -228,8 +228,9 @@ pub fn init(config: Config) -> Peripherals { | |||
| 228 | 228 | ||
| 229 | #[cfg(feature = "low-power")] | 229 | #[cfg(feature = "low-power")] |
| 230 | { | 230 | { |
| 231 | crate::rcc::REFCOUNT_STOP2 = 0 | 231 | crate::rcc::REFCOUNT_STOP2 = 0; |
| 232 | }; | 232 | crate::rcc::REFCOUNT_STOP1 = 0; |
| 233 | } | ||
| 233 | } | 234 | } |
| 234 | 235 | ||
| 235 | p | 236 | p |
diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index aea3a5ce3..20d8f9045 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) { | |||
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | pub fn stop_ready(stop_mode: StopMode) -> bool { | 82 | pub fn stop_ready(stop_mode: StopMode) -> bool { |
| 83 | unsafe { EXECUTOR.as_mut().unwrap() }.stop_ready(stop_mode) | 83 | match unsafe { EXECUTOR.as_mut().unwrap() }.stop_mode() { |
| 84 | Some(StopMode::Stop2) => true, | ||
| 85 | Some(StopMode::Stop1) => stop_mode == StopMode::Stop1, | ||
| 86 | None => false, | ||
| 87 | } | ||
| 84 | } | 88 | } |
| 85 | 89 | ||
| 86 | #[non_exhaustive] | 90 | #[non_exhaustive] |
| 91 | #[derive(PartialEq)] | ||
| 87 | pub enum StopMode { | 92 | pub enum StopMode { |
| 93 | Stop1, | ||
| 88 | Stop2, | 94 | Stop2, |
| 89 | } | 95 | } |
| 90 | 96 | ||
| @@ -135,23 +141,39 @@ impl Executor { | |||
| 135 | trace!("low power: stop with rtc configured"); | 141 | trace!("low power: stop with rtc configured"); |
| 136 | } | 142 | } |
| 137 | 143 | ||
| 138 | fn stop_ready(&self, stop_mode: StopMode) -> bool { | 144 | fn stop_mode(&self) -> Option<StopMode> { |
| 139 | match stop_mode { | 145 | if unsafe { crate::rcc::REFCOUNT_STOP2 == 0 } && unsafe { crate::rcc::REFCOUNT_STOP1 == 0 } { |
| 140 | StopMode::Stop2 => unsafe { crate::rcc::REFCOUNT_STOP2 == 0 }, | 146 | Some(StopMode::Stop2) |
| 147 | } else if unsafe { crate::rcc::REFCOUNT_STOP1 == 0 } { | ||
| 148 | Some(StopMode::Stop1) | ||
| 149 | } else { | ||
| 150 | None | ||
| 141 | } | 151 | } |
| 142 | } | 152 | } |
| 143 | 153 | ||
| 154 | fn configure_stop(&mut self, _stop_mode: StopMode) { | ||
| 155 | // TODO: configure chip-specific settings for stop | ||
| 156 | } | ||
| 157 | |||
| 144 | fn configure_pwr(&mut self) { | 158 | fn configure_pwr(&mut self) { |
| 145 | self.scb.clear_sleepdeep(); | 159 | self.scb.clear_sleepdeep(); |
| 146 | 160 | ||
| 147 | compiler_fence(Ordering::SeqCst); | 161 | compiler_fence(Ordering::SeqCst); |
| 148 | 162 | ||
| 149 | if !self.stop_ready(StopMode::Stop2) { | 163 | let stop_mode = self.stop_mode(); |
| 164 | if stop_mode.is_none() { | ||
| 150 | trace!("low power: not ready to stop"); | 165 | trace!("low power: not ready to stop"); |
| 151 | } else if self.time_driver.pause_time().is_err() { | 166 | } else if self.time_driver.pause_time().is_err() { |
| 152 | trace!("low power: failed to pause time"); | 167 | trace!("low power: failed to pause time"); |
| 153 | } else { | 168 | } else { |
| 154 | trace!("low power: stop"); | 169 | let stop_mode = stop_mode.unwrap(); |
| 170 | match stop_mode { | ||
| 171 | StopMode::Stop1 => trace!("low power: stop 1"), | ||
| 172 | StopMode::Stop2 => trace!("low power: stop 2"), | ||
| 173 | } | ||
| 174 | self.configure_stop(stop_mode); | ||
| 175 | |||
| 176 | #[cfg(not(feature = "low-power-debug-with-sleep"))] | ||
| 155 | self.scb.set_sleepdeep(); | 177 | self.scb.set_sleepdeep(); |
| 156 | } | 178 | } |
| 157 | } | 179 | } |
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 3b19e4b95..c11a9cc6b 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs | |||
| @@ -181,6 +181,15 @@ pub struct Clocks { | |||
| 181 | } | 181 | } |
| 182 | 182 | ||
| 183 | #[cfg(feature = "low-power")] | 183 | #[cfg(feature = "low-power")] |
| 184 | /// Must be written within a critical section | ||
| 185 | /// | ||
| 186 | /// May be read without a critical section | ||
| 187 | pub(crate) static mut REFCOUNT_STOP1: u32 = 0; | ||
| 188 | |||
| 189 | #[cfg(feature = "low-power")] | ||
| 190 | /// Must be written within a critical section | ||
| 191 | /// | ||
| 192 | /// May be read without a critical section | ||
| 184 | pub(crate) static mut REFCOUNT_STOP2: u32 = 0; | 193 | pub(crate) static mut REFCOUNT_STOP2: u32 = 0; |
| 185 | 194 | ||
| 186 | /// Frozen clock frequencies | 195 | /// Frozen clock frequencies |
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index e527fdfee..e94a58575 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs | |||
| @@ -153,14 +153,7 @@ impl Default for RtcCalibrationCyclePeriod { | |||
| 153 | impl Rtc { | 153 | impl Rtc { |
| 154 | pub fn new(_rtc: impl Peripheral<P = RTC>, rtc_config: RtcConfig) -> Self { | 154 | pub fn new(_rtc: impl Peripheral<P = RTC>, rtc_config: RtcConfig) -> Self { |
| 155 | #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))] | 155 | #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))] |
| 156 | critical_section::with(|cs| { | 156 | <RTC as crate::rcc::sealed::RccPeripheral>::enable_and_reset(); |
| 157 | <RTC as crate::rcc::sealed::RccPeripheral>::enable_and_reset_with_cs(cs); | ||
| 158 | |||
| 159 | #[cfg(feature = "low-power")] | ||
| 160 | unsafe { | ||
| 161 | crate::rcc::REFCOUNT_STOP2 -= 1 | ||
| 162 | }; | ||
| 163 | }); | ||
| 164 | 157 | ||
| 165 | let mut this = Self { | 158 | let mut this = Self { |
| 166 | #[cfg(feature = "low-power")] | 159 | #[cfg(feature = "low-power")] |
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 14f27678f..4b769b1cb 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml | |||
| @@ -33,7 +33,7 @@ stm32wl55jc = ["embassy-stm32/stm32wl55jc-cm4", "not-gpdma", "rng", "chrono"] | |||
| 33 | eth = [] | 33 | eth = [] |
| 34 | rng = [] | 34 | rng = [] |
| 35 | sdmmc = [] | 35 | sdmmc = [] |
| 36 | stop = ["embassy-stm32/low-power"] | 36 | stop = ["embassy-stm32/low-power", "embassy-stm32/low-power-debug-with-sleep"] |
| 37 | chrono = ["embassy-stm32/chrono", "dep:chrono"] | 37 | chrono = ["embassy-stm32/chrono", "dep:chrono"] |
| 38 | can = [] | 38 | can = [] |
| 39 | ble = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/ble"] | 39 | ble = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/ble"] |
