Skip to content

Commit 5b03773

Browse files
authored
Merge pull request #4899 from xoviat/low-power
low_power: misc cleanups and allow main macro
2 parents a51533c + 29d4ade commit 5b03773

File tree

14 files changed

+72
-170
lines changed

14 files changed

+72
-170
lines changed

embassy-stm32/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## Unreleased - ReleaseDate
99

10+
- feat: allow embassy_executor::main for low power
1011
- feat: Add waveform methods to ComplementaryPwm
1112
- fix: Avoid generating timer update events when updating the frequency ([#4890](https://github.com/embassy-rs/embassy/pull/4890))
1213
- chore: cleanup low-power add time

embassy-stm32/src/lib.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -649,10 +649,7 @@ fn init_hw(config: Config) -> Peripherals {
649649
rcc::init_rcc(cs, config.rcc);
650650

651651
#[cfg(feature = "low-power")]
652-
crate::rtc::init_rtc(cs, config.rtc);
653-
654-
#[cfg(feature = "low-power")]
655-
crate::time_driver::get_driver().set_min_stop_pause(cs, config.min_stop_pause);
652+
rtc::init_rtc(cs, config.rtc, config.min_stop_pause);
656653
}
657654

658655
p

embassy-stm32/src/low_power.rs

Lines changed: 45 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -14,29 +14,24 @@
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);
@@ -45,23 +40,22 @@
4540
//! }
4641
//! ```
4742
48-
// TODO: Usage of `static mut` here is unsound. Fix then remove this `allow`.`
49-
#![allow(static_mut_refs)]
50-
5143
use core::arch::asm;
5244
use core::marker::PhantomData;
45+
use core::mem;
5346
use core::sync::atomic::{Ordering, compiler_fence};
5447

5548
use cortex_m::peripheral::SCB;
5649
use critical_section::CriticalSection;
5750
use embassy_executor::*;
5851

5952
use crate::interrupt;
53+
use crate::rcc::{REFCOUNT_STOP1, REFCOUNT_STOP2};
6054
use crate::time_driver::get_driver;
6155

6256
const 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
6761
pub struct DeviceBusy(StopMode);
@@ -182,42 +176,47 @@ impl Into<Lpms> for StopMode {
182176
pub struct Executor {
183177
inner: raw::Executor,
184178
not_send: PhantomData<*mut ()>,
185-
scb: SCB,
186179
}
187180

188181
impl 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)]

embassy-stm32/src/rcc/l.rs

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
#[cfg(all(feature = "low-power", stm32wlex))]
2-
use core::mem::MaybeUninit;
3-
41
#[cfg(any(stm32l0, stm32l1))]
52
pub use crate::pac::pwr::vals::Vos as VoltageScale;
63
use crate::pac::rcc::regs::Cfgr;
@@ -14,42 +11,6 @@ use crate::time::Hertz;
1411
/// HSI speed
1512
pub const HSI_FREQ: Hertz = Hertz(16_000_000);
1613

17-
/// Saved RCC Config
18-
///
19-
/// Used when exiting STOP2 to re-enable clocks to their last configured state
20-
/// for chips that need it.
21-
#[cfg(all(feature = "low-power", stm32wlex))]
22-
static mut RESUME_RCC_CONFIG: MaybeUninit<Config> = MaybeUninit::uninit();
23-
24-
/// Set the rcc config to be restored when exiting STOP2
25-
///
26-
/// Safety: Sets a mutable global.
27-
#[cfg(all(feature = "low-power", stm32wlex))]
28-
pub(crate) unsafe fn set_resume_config(config: Config) {
29-
trace!("rcc set_resume_config()");
30-
RESUME_RCC_CONFIG = MaybeUninit::new(config);
31-
}
32-
33-
/// Get the rcc config to be restored when exiting STOP2
34-
///
35-
/// Safety: Reads a mutable global.
36-
#[cfg(all(feature = "low-power", stm32wlex))]
37-
pub(crate) unsafe fn get_resume_config() -> Config {
38-
*(*core::ptr::addr_of_mut!(RESUME_RCC_CONFIG)).assume_init_ref()
39-
}
40-
41-
#[cfg(all(feature = "low-power", stm32wlex))]
42-
/// Safety: should only be called from low power executable just after resuming from STOP2
43-
pub(crate) unsafe fn apply_resume_config() {
44-
trace!("rcc apply_resume_config()");
45-
46-
while RCC.cfgr().read().sws() != Sysclk::MSI {}
47-
48-
let config = get_resume_config();
49-
50-
init(config);
51-
}
52-
5314
#[derive(Clone, Copy, Eq, PartialEq)]
5415
pub enum HseMode {
5516
/// crystal/ceramic oscillator (HSEBYP=0)
@@ -193,10 +154,6 @@ fn msi_enable(range: MSIRange) {
193154
}
194155

195156
pub(crate) unsafe fn init(config: Config) {
196-
// save the rcc config because if we enter stop 2 we need to re-apply it on wakeup
197-
#[cfg(all(feature = "low-power", stm32wlex))]
198-
set_resume_config(config);
199-
200157
// Switch to MSI to prevent problems with PLL configuration.
201158
if !RCC.cr().read().msion() {
202159
// Turn on MSI and configure it to 4MHz.

embassy-stm32/src/rcc/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ pub(crate) static mut REFCOUNT_STOP1: u32 = 0;
4949
/// May be read without a critical section
5050
pub(crate) static mut REFCOUNT_STOP2: u32 = 0;
5151

52+
#[cfg(feature = "low-power")]
53+
pub(crate) static mut RCC_CONFIG: Option<Config> = None;
54+
5255
#[cfg(backup_sram)]
5356
pub(crate) static mut BKSRAM_RETAINED: bool = false;
5457

@@ -408,6 +411,7 @@ pub(crate) fn init_rcc(_cs: CriticalSection, config: Config) {
408411

409412
#[cfg(feature = "low-power")]
410413
{
414+
RCC_CONFIG = Some(config);
411415
REFCOUNT_STOP2 = 0;
412416
REFCOUNT_STOP1 = 0;
413417
}

embassy-stm32/src/rtc/mod.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -379,13 +379,16 @@ trait SealedInstance {
379379
}
380380

381381
#[cfg(feature = "low-power")]
382-
pub(crate) fn init_rtc(cs: CriticalSection, config: RtcConfig) {
382+
pub(crate) fn init_rtc(cs: CriticalSection, config: RtcConfig, min_stop_pause: embassy_time::Duration) {
383+
use crate::time_driver::get_driver;
384+
383385
#[cfg(feature = "_allow-disable-rtc")]
384386
if config._disable_rtc {
385387
return;
386388
}
387389

388-
crate::time_driver::get_driver().set_rtc(cs, Rtc::new_inner(config));
390+
get_driver().set_rtc(cs, Rtc::new_inner(config));
391+
get_driver().set_min_stop_pause(cs, min_stop_pause);
389392

390393
trace!("low power: stop with rtc configured");
391394
}

embassy-stm32/src/time_driver.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
245245
impl RtcDriver {
246246
/// initialize the timer, but don't start it. Used for chips like stm32wle5
247247
/// for low power where the timer config is lost in STOP2.
248-
fn init_timer(&'static self, cs: critical_section::CriticalSection) {
248+
pub(crate) fn init_timer(&'static self, cs: critical_section::CriticalSection) {
249249
let r = regs_gp16();
250250

251251
rcc::enable_and_reset_with_cs::<T>(cs);
@@ -516,8 +516,3 @@ pub(crate) const fn get_driver() -> &'static RtcDriver {
516516
pub(crate) fn init(cs: CriticalSection) {
517517
DRIVER.init(cs)
518518
}
519-
520-
#[cfg(all(feature = "low-power", stm32wlex))]
521-
pub(crate) fn init_timer(cs: CriticalSection) {
522-
DRIVER.init_timer(cs)
523-
}

examples/stm32h5/src/bin/stop.rs

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,12 @@
77
use defmt::*;
88
use embassy_executor::Spawner;
99
use embassy_stm32::gpio::{AnyPin, Level, Output, Speed};
10-
use embassy_stm32::low_power::Executor;
1110
use embassy_stm32::rcc::{HSIPrescaler, LsConfig};
12-
use embassy_stm32::{Config, Peri};
11+
use embassy_stm32::{Config, Peri, low_power};
1312
use embassy_time::Timer;
1413
use {defmt_rtt as _, panic_probe as _};
1514

16-
#[cortex_m_rt::entry]
17-
fn main() -> ! {
18-
Executor::take().run(|spawner| {
19-
spawner.spawn(unwrap!(async_main(spawner)));
20-
})
21-
}
22-
23-
#[embassy_executor::task]
15+
#[embassy_executor::main(executor = "low_power::Executor")]
2416
async fn async_main(spawner: Spawner) {
2517
defmt::info!("Program Start");
2618

examples/stm32l5/src/bin/stop.rs

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,12 @@
44
use defmt::*;
55
use embassy_executor::Spawner;
66
use embassy_stm32::gpio::{AnyPin, Level, Output, Speed};
7-
use embassy_stm32::low_power::Executor;
87
use embassy_stm32::rcc::LsConfig;
9-
use embassy_stm32::{Config, Peri};
8+
use embassy_stm32::{Config, Peri, low_power};
109
use embassy_time::Timer;
1110
use {defmt_rtt as _, panic_probe as _};
1211

13-
#[cortex_m_rt::entry]
14-
fn main() -> ! {
15-
Executor::take().run(|spawner| {
16-
spawner.spawn(unwrap!(async_main(spawner)));
17-
})
18-
}
19-
20-
#[embassy_executor::task]
12+
#[embassy_executor::main(executor = "low_power::Executor")]
2113
async fn async_main(spawner: Spawner) {
2214
let mut config = Config::default();
2315
config.rcc.ls = LsConfig::default_lsi();

examples/stm32wle5/src/bin/adc.rs

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,12 @@ use defmt::*;
66
use defmt_rtt as _;
77
use embassy_executor::Spawner;
88
use embassy_stm32::adc::{Adc, SampleTime};
9-
use embassy_stm32::low_power::Executor;
9+
use embassy_stm32::low_power;
1010
use embassy_time::Timer;
1111
use panic_probe as _;
1212
use static_cell::StaticCell;
1313

14-
#[cortex_m_rt::entry]
15-
fn main() -> ! {
16-
info!("main: Starting!");
17-
Executor::take().run(|spawner| {
18-
spawner.spawn(unwrap!(async_main(spawner)));
19-
});
20-
}
21-
22-
#[embassy_executor::task]
14+
#[embassy_executor::main(executor = "low_power::Executor")]
2315
async fn async_main(_spawner: Spawner) {
2416
let mut config = embassy_stm32::Config::default();
2517
// enable HSI clock

0 commit comments

Comments
 (0)