stm32: compute stop mode and workaround rtt test bug

This commit is contained in:
xoviat 2023-11-04 13:49:54 -05:00
parent 2765f0978f
commit dc467e89a0
8 changed files with 71 additions and 22 deletions

2
ci.sh
View file

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

View file

@ -90,6 +90,7 @@ defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-emb
exti = [] exti = []
low-power = [ "dep:embassy-executor", "embassy-executor/arch-cortex-m" ] low-power = [ "dep:embassy-executor", "embassy-executor/arch-cortex-m" ]
low-power-debug-with-sleep = []
embassy-executor = [] embassy-executor = []
## Automatically generate `memory.x` file using [`stm32-metapac`](https://docs.rs/stm32-metapac/) ## 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! { g.extend(quote! {
impl crate::rcc::sealed::RccPeripheral for peripherals::#pname { impl crate::rcc::sealed::RccPeripheral for peripherals::#pname {
fn frequency() -> crate::time::Hertz { fn frequency() -> crate::time::Hertz {
@ -563,8 +589,7 @@ fn main() {
} }
fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) { fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) {
#before_enable #before_enable
#[cfg(feature = "low-power")] #incr_stop_refcount
unsafe { crate::rcc::REFCOUNT_STOP2 += 1 };
crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true)); crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true));
#after_enable #after_enable
#rst #rst
@ -572,8 +597,7 @@ fn main() {
fn disable_with_cs(_cs: critical_section::CriticalSection) { fn disable_with_cs(_cs: critical_section::CriticalSection) {
#before_disable #before_disable
crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false)); crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false));
#[cfg(feature = "low-power")] #decr_stop_refcount
unsafe { crate::rcc::REFCOUNT_STOP2 -= 1 };
} }
} }

View file

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

View file

@ -33,11 +33,17 @@ pub fn stop_with_rtc(rtc: &'static Rtc) {
} }
pub fn stop_ready(stop_mode: StopMode) -> bool { 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] #[non_exhaustive]
#[derive(PartialEq)]
pub enum StopMode { pub enum StopMode {
Stop1,
Stop2, Stop2,
} }
@ -88,23 +94,39 @@ impl Executor {
trace!("low power: stop with rtc configured"); trace!("low power: stop with rtc configured");
} }
fn stop_ready(&self, stop_mode: StopMode) -> bool { fn stop_mode(&self) -> Option<StopMode> {
match stop_mode { if unsafe { crate::rcc::REFCOUNT_STOP2 == 0 } && unsafe { crate::rcc::REFCOUNT_STOP1 == 0 } {
StopMode::Stop2 => unsafe { crate::rcc::REFCOUNT_STOP2 == 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) { fn configure_pwr(&mut self) {
self.scb.clear_sleepdeep(); self.scb.clear_sleepdeep();
compiler_fence(Ordering::SeqCst); 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"); trace!("low power: not ready to stop");
} else if self.time_driver.pause_time().is_err() { } else if self.time_driver.pause_time().is_err() {
trace!("low power: failed to pause time"); trace!("low power: failed to pause time");
} else { } 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(); self.scb.set_sleepdeep();
} }
} }

View file

@ -181,6 +181,15 @@ pub struct Clocks {
} }
#[cfg(feature = "low-power")] #[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; pub(crate) static mut REFCOUNT_STOP2: u32 = 0;
/// Frozen clock frequencies /// Frozen clock frequencies

View file

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

View file

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