diff options
| -rw-r--r-- | embassy-stm32/Cargo.toml | 3 | ||||
| -rw-r--r-- | embassy-stm32/src/low_power.rs | 43 |
2 files changed, 36 insertions, 10 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 718da9a34..e96933b78 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml | |||
| @@ -241,7 +241,8 @@ log = ["dep:log"] | |||
| 241 | chrono = ["dep:chrono"] | 241 | chrono = ["dep:chrono"] |
| 242 | 242 | ||
| 243 | exti = [] | 243 | exti = [] |
| 244 | low-power = [ "dep:embassy-executor", "embassy-executor?/arch-cortex-m", "time" ] | 244 | low-power = [ "dep:embassy-executor", "time" ] |
| 245 | low-power-pender = [ ] | ||
| 245 | low-power-debug-with-sleep = [] | 246 | low-power-debug-with-sleep = [] |
| 246 | 247 | ||
| 247 | ## Automatically generate `memory.x` file based on the memory map from [`stm32-metapac`](https://docs.rs/stm32-metapac/) | 248 | ## Automatically generate `memory.x` file based on the memory map from [`stm32-metapac`](https://docs.rs/stm32-metapac/) |
diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 2388abe3c..9b7d733c6 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs | |||
| @@ -43,7 +43,7 @@ | |||
| 43 | use core::arch::asm; | 43 | use core::arch::asm; |
| 44 | use core::marker::PhantomData; | 44 | use core::marker::PhantomData; |
| 45 | use core::mem; | 45 | use core::mem; |
| 46 | use core::sync::atomic::{Ordering, compiler_fence}; | 46 | use core::sync::atomic::{AtomicBool, Ordering, compiler_fence}; |
| 47 | 47 | ||
| 48 | use cortex_m::peripheral::SCB; | 48 | use cortex_m::peripheral::SCB; |
| 49 | use critical_section::CriticalSection; | 49 | use critical_section::CriticalSection; |
| @@ -56,7 +56,27 @@ use crate::time_driver::get_driver; | |||
| 56 | 56 | ||
| 57 | const THREAD_PENDER: usize = usize::MAX; | 57 | const THREAD_PENDER: usize = usize::MAX; |
| 58 | 58 | ||
| 59 | static mut EXECUTOR_TAKEN: bool = false; | 59 | static EXECUTOR_TAKEN: AtomicBool = AtomicBool::new(false); |
| 60 | #[cfg(feature = "low-power-pender")] | ||
| 61 | static TASKS_PENDING: AtomicBool = AtomicBool::new(false); | ||
| 62 | |||
| 63 | #[cfg(feature = "low-power-pender")] | ||
| 64 | #[unsafe(export_name = "__pender")] | ||
| 65 | fn __pender(context: *mut ()) { | ||
| 66 | unsafe { | ||
| 67 | // Safety: `context` is either `usize::MAX` created by `Executor::run`, or a valid interrupt | ||
| 68 | // request number given to `InterruptExecutor::start`. | ||
| 69 | |||
| 70 | let context = context as usize; | ||
| 71 | |||
| 72 | // Try to make Rust optimize the branching away if we only use thread mode. | ||
| 73 | if context == THREAD_PENDER { | ||
| 74 | TASKS_PENDING.store(true, Ordering::Release); | ||
| 75 | core::arch::asm!("sev"); | ||
| 76 | return; | ||
| 77 | } | ||
| 78 | } | ||
| 79 | } | ||
| 60 | 80 | ||
| 61 | /// Prevent the device from going into the stop mode if held | 81 | /// Prevent the device from going into the stop mode if held |
| 62 | pub struct DeviceBusy { | 82 | pub struct DeviceBusy { |
| @@ -150,12 +170,10 @@ pub struct Executor { | |||
| 150 | impl Executor { | 170 | impl Executor { |
| 151 | /// Create a new Executor. | 171 | /// Create a new Executor. |
| 152 | pub fn new() -> Self { | 172 | pub fn new() -> Self { |
| 153 | unsafe { | 173 | if EXECUTOR_TAKEN.load(Ordering::Acquire) { |
| 154 | if EXECUTOR_TAKEN { | 174 | panic!("Low power executor can only be taken once."); |
| 155 | panic!("Low power executor can only be taken once."); | 175 | } else { |
| 156 | } else { | 176 | EXECUTOR_TAKEN.store(true, Ordering::Release); |
| 157 | EXECUTOR_TAKEN = true; | ||
| 158 | } | ||
| 159 | } | 177 | } |
| 160 | 178 | ||
| 161 | Self { | 179 | Self { |
| @@ -304,7 +322,14 @@ impl Executor { | |||
| 304 | w.set_c1cssf(true); | 322 | w.set_c1cssf(true); |
| 305 | }); | 323 | }); |
| 306 | 324 | ||
| 307 | compiler_fence(Ordering::SeqCst); | 325 | #[cfg(feature = "low-power-pender")] |
| 326 | if TASKS_PENDING.load(Ordering::Acquire) { | ||
| 327 | TASKS_PENDING.store(false, Ordering::Release); | ||
| 328 | |||
| 329 | return; | ||
| 330 | } | ||
| 331 | |||
| 332 | compiler_fence(Ordering::Acquire); | ||
| 308 | 333 | ||
| 309 | critical_section::with(|cs| { | 334 | critical_section::with(|cs| { |
| 310 | let _ = unsafe { RCC_CONFIG }?; | 335 | let _ = unsafe { RCC_CONFIG }?; |
