1414//!
1515//! Since entering and leaving low-power modes typically incurs a significant latency, the
1616//! low-power executor will only attempt to enter when the next timer event is at least
17- //! [`time_driver::MIN_STOP_PAUSE `] in the future.
17+ //! [`time_driver::min_stop_pause `] in the future.
1818//!
1919//! Currently there is no macro analogous to `embassy_executor::main` for this executor;
2020//! consequently one must define their entrypoint manually. Moreover, you must relinquish control
2121//! of the `RTC` peripheral to the executor. This will typically look like
2222//!
2323//! ```rust,no_run
2424//! use embassy_executor::Spawner;
25- //! use embassy_stm32::low_power::Executor ;
25+ //! use embassy_stm32::low_power;
2626//! use embassy_stm32::rtc::{Rtc, RtcConfig};
27- //! use static_cell::StaticCell ;
27+ //! use embassy_time::Duration ;
2828//!
29- //! #[cortex_m_rt::entry]
30- //! fn main() -> ! {
31- //! Executor::take().run(|spawner| {
32- //! spawner.spawn(unwrap!(async_main(spawner)));
33- //! });
34- //! }
35- //!
36- //! #[embassy_executor::task]
29+ //! #[embassy_executor::main(executor = "low_power::Executor")]
3730//! async fn async_main(spawner: Spawner) {
3831//! // initialize the platform...
3932//! let mut config = embassy_stm32::Config::default();
33+ //! // the default value, but can be adjusted
34+ //! config.min_stop_pause = Duration::from_millis(250);
4035//! // when enabled the power-consumption is much higher during stop, but debugging and RTT is working
4136//! config.enable_debug_during_sleep = false;
4237//! let p = embassy_stm32::init(config);
4540//! }
4641//! ```
4742
48- // TODO: Usage of `static mut` here is unsound. Fix then remove this `allow`.`
49- #![ allow( static_mut_refs) ]
50-
5143use core:: arch:: asm;
5244use core:: marker:: PhantomData ;
45+ use core:: mem;
5346use core:: sync:: atomic:: { Ordering , compiler_fence} ;
5447
5548use cortex_m:: peripheral:: SCB ;
5649use critical_section:: CriticalSection ;
5750use embassy_executor:: * ;
5851
5952use crate :: interrupt;
53+ use crate :: rcc:: { REFCOUNT_STOP1 , REFCOUNT_STOP2 } ;
6054use crate :: time_driver:: get_driver;
6155
6256const THREAD_PENDER : usize = usize:: MAX ;
6357
64- static mut EXECUTOR : Option < Executor > = None ;
58+ static mut EXECUTOR_TAKEN : bool = false ;
6559
6660/// Prevent the device from going into the stop mode if held
6761pub struct DeviceBusy ( StopMode ) ;
@@ -182,42 +176,47 @@ impl Into<Lpms> for StopMode {
182176pub struct Executor {
183177 inner : raw:: Executor ,
184178 not_send : PhantomData < * mut ( ) > ,
185- scb : SCB ,
186179}
187180
188181impl Executor {
189182 /// Create a new Executor.
190- pub fn take ( ) -> & ' static mut Self {
191- critical_section:: with ( |_| unsafe {
192- assert ! ( EXECUTOR . is_none( ) ) ;
193-
194- EXECUTOR = Some ( Self {
195- inner : raw:: Executor :: new ( THREAD_PENDER as * mut ( ) ) ,
196- not_send : PhantomData ,
197- scb : cortex_m:: Peripherals :: steal ( ) . SCB ,
198- } ) ;
199-
200- let executor = EXECUTOR . as_mut ( ) . unwrap ( ) ;
183+ pub fn new ( ) -> Self {
184+ unsafe {
185+ if EXECUTOR_TAKEN {
186+ panic ! ( "Low power executor can only be taken once." ) ;
187+ } else {
188+ EXECUTOR_TAKEN = true ;
189+ }
190+ }
201191
202- executor
203- } )
192+ Self {
193+ inner : raw:: Executor :: new ( THREAD_PENDER as * mut ( ) ) ,
194+ not_send : PhantomData ,
195+ }
204196 }
205197
206198 pub ( crate ) unsafe fn on_wakeup_irq ( ) {
207199 critical_section:: with ( |cs| {
208200 #[ cfg( stm32wlex) ]
209201 {
210- let extscr = crate :: pac:: PWR . extscr ( ) . read ( ) ;
202+ use crate :: pac:: rcc:: vals:: Sw ;
203+ use crate :: pac:: { PWR , RCC } ;
204+ use crate :: rcc:: { RCC_CONFIG , init as init_rcc} ;
205+
206+ let extscr = PWR . extscr ( ) . read ( ) ;
211207 if extscr. c1stop2f ( ) || extscr. c1stopf ( ) {
212208 // when we wake from any stop mode we need to re-initialize the rcc
213- crate :: rcc:: apply_resume_config ( ) ;
209+ while RCC . cfgr ( ) . read ( ) . sws ( ) != Sw :: MSI { }
210+
211+ init_rcc ( RCC_CONFIG . unwrap ( ) ) ;
212+
214213 if extscr. c1stop2f ( ) {
215214 // when we wake from STOP2, we need to re-initialize the time driver
216- crate :: time_driver :: init_timer ( cs) ;
215+ get_driver ( ) . init_timer ( cs) ;
217216 // reset the refcounts for STOP2 and STOP1 (initializing the time driver will increment one of them for the timer)
218217 // and given that we just woke from STOP2, we can reset them
219- crate :: rcc :: REFCOUNT_STOP2 = 0 ;
220- crate :: rcc :: REFCOUNT_STOP1 = 0 ;
218+ REFCOUNT_STOP2 = 0 ;
219+ REFCOUNT_STOP1 = 0 ;
221220 }
222221 }
223222 }
@@ -226,11 +225,15 @@ impl Executor {
226225 } ) ;
227226 }
228227
228+ const fn get_scb ( ) -> SCB {
229+ unsafe { mem:: transmute ( ( ) ) }
230+ }
231+
229232 fn stop_mode ( _cs : CriticalSection ) -> Option < StopMode > {
230- if unsafe { crate :: rcc :: REFCOUNT_STOP2 == 0 && crate :: rcc :: REFCOUNT_STOP1 == 0 } {
233+ if unsafe { REFCOUNT_STOP2 == 0 && REFCOUNT_STOP1 == 0 } {
231234 trace ! ( "low power: stop 2" ) ;
232235 Some ( StopMode :: Stop2 )
233- } else if unsafe { crate :: rcc :: REFCOUNT_STOP1 == 0 } {
236+ } else if unsafe { REFCOUNT_STOP1 == 0 } {
234237 trace ! ( "low power: stop 1" ) ;
235238 Some ( StopMode :: Stop1 )
236239 } else {
@@ -240,7 +243,7 @@ impl Executor {
240243 }
241244
242245 #[ allow( unused_variables) ]
243- fn configure_stop ( & mut self , stop_mode : StopMode ) {
246+ fn configure_stop ( & self , stop_mode : StopMode ) {
244247 #[ cfg( any( stm32l4, stm32l5, stm32u5, stm32u0, stm32wba, stm32wlex) ) ]
245248 crate :: pac:: PWR . cr1 ( ) . modify ( |m| m. set_lpms ( stop_mode. into ( ) ) ) ;
246249 #[ cfg( stm32h5) ]
@@ -251,8 +254,8 @@ impl Executor {
251254 } ) ;
252255 }
253256
254- fn configure_pwr ( & mut self ) {
255- self . scb . clear_sleepdeep ( ) ;
257+ fn configure_pwr ( & self ) {
258+ Self :: get_scb ( ) . clear_sleepdeep ( ) ;
256259 // Clear any previous stop flags
257260 #[ cfg( stm32wlex) ]
258261 crate :: pac:: PWR . extscr ( ) . modify ( |w| {
@@ -271,7 +274,7 @@ impl Executor {
271274 self . configure_stop ( stop_mode) ;
272275
273276 #[ cfg( not( feature = "low-power-debug-with-sleep" ) ) ]
274- self . scb . set_sleepdeep ( ) ;
277+ Self :: get_scb ( ) . set_sleepdeep ( ) ;
275278 } ) ;
276279 }
277280
@@ -294,12 +297,11 @@ impl Executor {
294297 ///
295298 /// This function never returns.
296299 pub fn run ( & ' static mut self , init : impl FnOnce ( Spawner ) ) -> ! {
297- let executor = unsafe { EXECUTOR . as_mut ( ) . unwrap ( ) } ;
298- init ( executor. inner . spawner ( ) ) ;
300+ init ( self . inner . spawner ( ) ) ;
299301
300302 loop {
301303 unsafe {
302- executor . inner . poll ( ) ;
304+ self . inner . poll ( ) ;
303305 self . configure_pwr ( ) ;
304306 asm ! ( "wfe" ) ;
305307 #[ cfg( stm32wlex) ]
0 commit comments