Merge pull request #2140 from xoviat/low-power

stm32: compute stop mode and workaround rtt test bug
This commit is contained in:
xoviat 2023-11-04 18:57:44 +00:00 committed by GitHub
commit 056c409443
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 71 additions and 23 deletions

2
ci.sh
View File

@ -218,8 +218,6 @@ cargo batch \
rm out/tests/stm32wb55rg/wpan_mac
rm out/tests/stm32wb55rg/wpan_ble
# unstable
rm out/tests/stm32f429zi/stop
# unstable, I think it's running out of RAM?
rm out/tests/stm32f207zg/eth

View File

@ -90,6 +90,7 @@ defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-emb
exti = []
low-power = [ "dep:embassy-executor", "embassy-executor/arch-cortex-m" ]
low-power-debug-with-sleep = []
embassy-executor = []
## Automatically generate `memory.x` file using [`stm32-metapac`](https://docs.rs/stm32-metapac/)

View File

@ -556,6 +556,32 @@ fn main() {
},
};
/*
If LP and non-LP peripherals share the same RCC enable bit, then a refcount leak will result.
This should be checked in stm32-data-gen.
*/
let stop_refcount = if p.name.starts_with("LP") {
quote! { REFCOUNT_STOP2 }
} else {
quote! { REFCOUNT_STOP1 }
};
let (incr_stop_refcount, decr_stop_refcount) = if p.name != "RTC" {
(
quote! {
#[cfg(feature = "low-power")]
unsafe { crate::rcc::#stop_refcount += 1 };
},
quote! {
#[cfg(feature = "low-power")]
unsafe { crate::rcc::#stop_refcount -= 1 };
},
)
} else {
(quote! {}, quote! {})
};
g.extend(quote! {
impl crate::rcc::sealed::RccPeripheral for peripherals::#pname {
fn frequency() -> crate::time::Hertz {
@ -563,8 +589,7 @@ fn main() {
}
fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) {
#before_enable
#[cfg(feature = "low-power")]
unsafe { crate::rcc::REFCOUNT_STOP2 += 1 };
#incr_stop_refcount
crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true));
#after_enable
#rst
@ -572,8 +597,7 @@ fn main() {
fn disable_with_cs(_cs: critical_section::CriticalSection) {
#before_disable
crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false));
#[cfg(feature = "low-power")]
unsafe { crate::rcc::REFCOUNT_STOP2 -= 1 };
#decr_stop_refcount
}
}

View File

@ -228,8 +228,9 @@ pub fn init(config: Config) -> Peripherals {
#[cfg(feature = "low-power")]
{
crate::rcc::REFCOUNT_STOP2 = 0
};
crate::rcc::REFCOUNT_STOP2 = 0;
crate::rcc::REFCOUNT_STOP1 = 0;
}
}
p

View File

@ -80,11 +80,17 @@ pub fn stop_with_rtc(rtc: &'static Rtc) {
}
pub fn stop_ready(stop_mode: StopMode) -> bool {
unsafe { EXECUTOR.as_mut().unwrap() }.stop_ready(stop_mode)
match unsafe { EXECUTOR.as_mut().unwrap() }.stop_mode() {
Some(StopMode::Stop2) => true,
Some(StopMode::Stop1) => stop_mode == StopMode::Stop1,
None => false,
}
}
#[non_exhaustive]
#[derive(PartialEq)]
pub enum StopMode {
Stop1,
Stop2,
}
@ -135,23 +141,39 @@ impl Executor {
trace!("low power: stop with rtc configured");
}
fn stop_ready(&self, stop_mode: StopMode) -> bool {
match stop_mode {
StopMode::Stop2 => unsafe { crate::rcc::REFCOUNT_STOP2 == 0 },
fn stop_mode(&self) -> Option<StopMode> {
if unsafe { crate::rcc::REFCOUNT_STOP2 == 0 } && unsafe { crate::rcc::REFCOUNT_STOP1 == 0 } {
Some(StopMode::Stop2)
} else if unsafe { crate::rcc::REFCOUNT_STOP1 == 0 } {
Some(StopMode::Stop1)
} else {
None
}
}
fn configure_stop(&mut self, _stop_mode: StopMode) {
// TODO: configure chip-specific settings for stop
}
fn configure_pwr(&mut self) {
self.scb.clear_sleepdeep();
compiler_fence(Ordering::SeqCst);
if !self.stop_ready(StopMode::Stop2) {
let stop_mode = self.stop_mode();
if stop_mode.is_none() {
trace!("low power: not ready to stop");
} else if self.time_driver.pause_time().is_err() {
trace!("low power: failed to pause time");
} else {
trace!("low power: stop");
let stop_mode = stop_mode.unwrap();
match stop_mode {
StopMode::Stop1 => trace!("low power: stop 1"),
StopMode::Stop2 => trace!("low power: stop 2"),
}
self.configure_stop(stop_mode);
#[cfg(not(feature = "low-power-debug-with-sleep"))]
self.scb.set_sleepdeep();
}
}

View File

@ -181,6 +181,15 @@ pub struct Clocks {
}
#[cfg(feature = "low-power")]
/// Must be written within a critical section
///
/// May be read without a critical section
pub(crate) static mut REFCOUNT_STOP1: u32 = 0;
#[cfg(feature = "low-power")]
/// Must be written within a critical section
///
/// May be read without a critical section
pub(crate) static mut REFCOUNT_STOP2: u32 = 0;
/// Frozen clock frequencies

View File

@ -153,14 +153,7 @@ impl Default for RtcCalibrationCyclePeriod {
impl Rtc {
pub fn new(_rtc: impl Peripheral<P = RTC>, rtc_config: RtcConfig) -> Self {
#[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))]
critical_section::with(|cs| {
<RTC as crate::rcc::sealed::RccPeripheral>::enable_and_reset_with_cs(cs);
#[cfg(feature = "low-power")]
unsafe {
crate::rcc::REFCOUNT_STOP2 -= 1
};
});
<RTC as crate::rcc::sealed::RccPeripheral>::enable_and_reset();
let mut this = Self {
#[cfg(feature = "low-power")]

View File

@ -33,7 +33,7 @@ stm32wl55jc = ["embassy-stm32/stm32wl55jc-cm4", "not-gpdma", "rng", "chrono"]
eth = []
rng = []
sdmmc = []
stop = ["embassy-stm32/low-power"]
stop = ["embassy-stm32/low-power", "embassy-stm32/low-power-debug-with-sleep"]
chrono = ["embassy-stm32/chrono", "dep:chrono"]
can = []
ble = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/ble"]