aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxoviat <[email protected]>2025-12-16 11:14:21 -0600
committerxoviat <[email protected]>2025-12-16 11:14:21 -0600
commita02d74c78f1a8192da701965575fe975092aaf9e (patch)
tree923b733403e82e0a8efa5c023e2076b48b19bec3
parent5ae6e060ec1c90561719aabdc29d5b6e7b8b0a82 (diff)
stm32: add low power pender
-rw-r--r--embassy-stm32/Cargo.toml3
-rw-r--r--embassy-stm32/src/low_power.rs43
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"]
241chrono = ["dep:chrono"] 241chrono = ["dep:chrono"]
242 242
243exti = [] 243exti = []
244low-power = [ "dep:embassy-executor", "embassy-executor?/arch-cortex-m", "time" ] 244low-power = [ "dep:embassy-executor", "time" ]
245low-power-pender = [ ]
245low-power-debug-with-sleep = [] 246low-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 @@
43use core::arch::asm; 43use core::arch::asm;
44use core::marker::PhantomData; 44use core::marker::PhantomData;
45use core::mem; 45use core::mem;
46use core::sync::atomic::{Ordering, compiler_fence}; 46use core::sync::atomic::{AtomicBool, Ordering, compiler_fence};
47 47
48use cortex_m::peripheral::SCB; 48use cortex_m::peripheral::SCB;
49use critical_section::CriticalSection; 49use critical_section::CriticalSection;
@@ -56,7 +56,27 @@ use crate::time_driver::get_driver;
56 56
57const THREAD_PENDER: usize = usize::MAX; 57const THREAD_PENDER: usize = usize::MAX;
58 58
59static mut EXECUTOR_TAKEN: bool = false; 59static EXECUTOR_TAKEN: AtomicBool = AtomicBool::new(false);
60#[cfg(feature = "low-power-pender")]
61static TASKS_PENDING: AtomicBool = AtomicBool::new(false);
62
63#[cfg(feature = "low-power-pender")]
64#[unsafe(export_name = "__pender")]
65fn __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
62pub struct DeviceBusy { 82pub struct DeviceBusy {
@@ -150,12 +170,10 @@ pub struct Executor {
150impl Executor { 170impl 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 }?;