diff options
| author | xoviat <[email protected]> | 2025-11-16 07:50:49 -0600 |
|---|---|---|
| committer | xoviat <[email protected]> | 2025-11-16 07:50:49 -0600 |
| commit | 29d4ade2866e6c8d2114b393853354ded1e61db7 (patch) | |
| tree | 13d38bc6cce8f71ceccbde7877ffe66a8643e30d /embassy-stm32/src | |
| parent | a51533c0b4edd551a1b9587b9272026b0b256d54 (diff) | |
low_power: misc cleanups and allow main macro
Diffstat (limited to 'embassy-stm32/src')
| -rw-r--r-- | embassy-stm32/src/lib.rs | 5 | ||||
| -rw-r--r-- | embassy-stm32/src/low_power.rs | 88 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/l.rs | 43 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/mod.rs | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/rtc/mod.rs | 7 | ||||
| -rw-r--r-- | embassy-stm32/src/time_driver.rs | 7 |
6 files changed, 56 insertions, 98 deletions
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 6e492946a..7c3770643 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs | |||
| @@ -649,10 +649,7 @@ fn init_hw(config: Config) -> Peripherals { | |||
| 649 | rcc::init_rcc(cs, config.rcc); | 649 | rcc::init_rcc(cs, config.rcc); |
| 650 | 650 | ||
| 651 | #[cfg(feature = "low-power")] | 651 | #[cfg(feature = "low-power")] |
| 652 | crate::rtc::init_rtc(cs, config.rtc); | 652 | rtc::init_rtc(cs, config.rtc, config.min_stop_pause); |
| 653 | |||
| 654 | #[cfg(feature = "low-power")] | ||
| 655 | crate::time_driver::get_driver().set_min_stop_pause(cs, config.min_stop_pause); | ||
| 656 | } | 653 | } |
| 657 | 654 | ||
| 658 | p | 655 | p |
diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 36c7e2242..cf8f2b393 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs | |||
| @@ -14,7 +14,7 @@ | |||
| 14 | //! | 14 | //! |
| 15 | //! Since entering and leaving low-power modes typically incurs a significant latency, the | 15 | //! Since entering and leaving low-power modes typically incurs a significant latency, the |
| 16 | //! low-power executor will only attempt to enter when the next timer event is at least | 16 | //! 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. |
| 18 | //! | 18 | //! |
| 19 | //! Currently there is no macro analogous to `embassy_executor::main` for this executor; | 19 | //! Currently there is no macro analogous to `embassy_executor::main` for this executor; |
| 20 | //! consequently one must define their entrypoint manually. Moreover, you must relinquish control | 20 | //! consequently one must define their entrypoint manually. Moreover, you must relinquish control |
| @@ -22,21 +22,16 @@ | |||
| 22 | //! | 22 | //! |
| 23 | //! ```rust,no_run | 23 | //! ```rust,no_run |
| 24 | //! use embassy_executor::Spawner; | 24 | //! use embassy_executor::Spawner; |
| 25 | //! use embassy_stm32::low_power::Executor; | 25 | //! use embassy_stm32::low_power; |
| 26 | //! use embassy_stm32::rtc::{Rtc, RtcConfig}; | 26 | //! use embassy_stm32::rtc::{Rtc, RtcConfig}; |
| 27 | //! use static_cell::StaticCell; | 27 | //! use embassy_time::Duration; |
| 28 | //! | 28 | //! |
| 29 | //! #[cortex_m_rt::entry] | 29 | //! #[embassy_executor::main(executor = "low_power::Executor")] |
| 30 | //! fn main() -> ! { | ||
| 31 | //! Executor::take().run(|spawner| { | ||
| 32 | //! spawner.spawn(unwrap!(async_main(spawner))); | ||
| 33 | //! }); | ||
| 34 | //! } | ||
| 35 | //! | ||
| 36 | //! #[embassy_executor::task] | ||
| 37 | //! async fn async_main(spawner: Spawner) { | 30 | //! async fn async_main(spawner: Spawner) { |
| 38 | //! // initialize the platform... | 31 | //! // initialize the platform... |
| 39 | //! let mut config = embassy_stm32::Config::default(); | 32 | //! let mut config = embassy_stm32::Config::default(); |
| 33 | //! // the default value, but can be adjusted | ||
| 34 | //! config.min_stop_pause = Duration::from_millis(250); | ||
| 40 | //! // when enabled the power-consumption is much higher during stop, but debugging and RTT is working | 35 | //! // when enabled the power-consumption is much higher during stop, but debugging and RTT is working |
| 41 | //! config.enable_debug_during_sleep = false; | 36 | //! config.enable_debug_during_sleep = false; |
| 42 | //! let p = embassy_stm32::init(config); | 37 | //! let p = embassy_stm32::init(config); |
| @@ -45,11 +40,9 @@ | |||
| 45 | //! } | 40 | //! } |
| 46 | //! ``` | 41 | //! ``` |
| 47 | 42 | ||
| 48 | // TODO: Usage of `static mut` here is unsound. Fix then remove this `allow`.` | ||
| 49 | #![allow(static_mut_refs)] | ||
| 50 | |||
| 51 | use core::arch::asm; | 43 | use core::arch::asm; |
| 52 | use core::marker::PhantomData; | 44 | use core::marker::PhantomData; |
| 45 | use core::mem; | ||
| 53 | use core::sync::atomic::{Ordering, compiler_fence}; | 46 | use core::sync::atomic::{Ordering, compiler_fence}; |
| 54 | 47 | ||
| 55 | use cortex_m::peripheral::SCB; | 48 | use cortex_m::peripheral::SCB; |
| @@ -57,11 +50,12 @@ use critical_section::CriticalSection; | |||
| 57 | use embassy_executor::*; | 50 | use embassy_executor::*; |
| 58 | 51 | ||
| 59 | use crate::interrupt; | 52 | use crate::interrupt; |
| 53 | use crate::rcc::{REFCOUNT_STOP1, REFCOUNT_STOP2}; | ||
| 60 | use crate::time_driver::get_driver; | 54 | use crate::time_driver::get_driver; |
| 61 | 55 | ||
| 62 | const THREAD_PENDER: usize = usize::MAX; | 56 | const THREAD_PENDER: usize = usize::MAX; |
| 63 | 57 | ||
| 64 | static mut EXECUTOR: Option<Executor> = None; | 58 | static mut EXECUTOR_TAKEN: bool = false; |
| 65 | 59 | ||
| 66 | /// Prevent the device from going into the stop mode if held | 60 | /// Prevent the device from going into the stop mode if held |
| 67 | pub struct DeviceBusy(StopMode); | 61 | pub struct DeviceBusy(StopMode); |
| @@ -182,42 +176,47 @@ impl Into<Lpms> for StopMode { | |||
| 182 | pub struct Executor { | 176 | pub struct Executor { |
| 183 | inner: raw::Executor, | 177 | inner: raw::Executor, |
| 184 | not_send: PhantomData<*mut ()>, | 178 | not_send: PhantomData<*mut ()>, |
| 185 | scb: SCB, | ||
| 186 | } | 179 | } |
| 187 | 180 | ||
| 188 | impl Executor { | 181 | impl Executor { |
| 189 | /// Create a new Executor. | 182 | /// Create a new Executor. |
| 190 | pub fn take() -> &'static mut Self { | 183 | pub fn new() -> Self { |
| 191 | critical_section::with(|_| unsafe { | 184 | unsafe { |
| 192 | assert!(EXECUTOR.is_none()); | 185 | if EXECUTOR_TAKEN { |
| 193 | 186 | panic!("Low power executor can only be taken once."); | |
| 194 | EXECUTOR = Some(Self { | 187 | } else { |
| 195 | inner: raw::Executor::new(THREAD_PENDER as *mut ()), | 188 | EXECUTOR_TAKEN = true; |
| 196 | not_send: PhantomData, | 189 | } |
| 197 | scb: cortex_m::Peripherals::steal().SCB, | 190 | } |
| 198 | }); | ||
| 199 | |||
| 200 | let executor = EXECUTOR.as_mut().unwrap(); | ||
| 201 | 191 | ||
| 202 | executor | 192 | Self { |
| 203 | }) | 193 | inner: raw::Executor::new(THREAD_PENDER as *mut ()), |
| 194 | not_send: PhantomData, | ||
| 195 | } | ||
| 204 | } | 196 | } |
| 205 | 197 | ||
| 206 | pub(crate) unsafe fn on_wakeup_irq() { | 198 | pub(crate) unsafe fn on_wakeup_irq() { |
| 207 | critical_section::with(|cs| { | 199 | critical_section::with(|cs| { |
| 208 | #[cfg(stm32wlex)] | 200 | #[cfg(stm32wlex)] |
| 209 | { | 201 | { |
| 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(); | ||
| 211 | if extscr.c1stop2f() || extscr.c1stopf() { | 207 | if extscr.c1stop2f() || extscr.c1stopf() { |
| 212 | // when we wake from any stop mode we need to re-initialize the rcc | 208 | // 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 | |||
| 214 | if extscr.c1stop2f() { | 213 | if extscr.c1stop2f() { |
| 215 | // when we wake from STOP2, we need to re-initialize the time driver | 214 | // 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); |
| 217 | // reset the refcounts for STOP2 and STOP1 (initializing the time driver will increment one of them for the timer) | 216 | // reset the refcounts for STOP2 and STOP1 (initializing the time driver will increment one of them for the timer) |
| 218 | // and given that we just woke from STOP2, we can reset them | 217 | // and given that we just woke from STOP2, we can reset them |
| 219 | crate::rcc::REFCOUNT_STOP2 = 0; | 218 | REFCOUNT_STOP2 = 0; |
| 220 | crate::rcc::REFCOUNT_STOP1 = 0; | 219 | REFCOUNT_STOP1 = 0; |
| 221 | } | 220 | } |
| 222 | } | 221 | } |
| 223 | } | 222 | } |
| @@ -226,11 +225,15 @@ impl Executor { | |||
| 226 | }); | 225 | }); |
| 227 | } | 226 | } |
| 228 | 227 | ||
| 228 | const fn get_scb() -> SCB { | ||
| 229 | unsafe { mem::transmute(()) } | ||
| 230 | } | ||
| 231 | |||
| 229 | fn stop_mode(_cs: CriticalSection) -> Option<StopMode> { | 232 | 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 } { |
| 231 | trace!("low power: stop 2"); | 234 | trace!("low power: stop 2"); |
| 232 | Some(StopMode::Stop2) | 235 | Some(StopMode::Stop2) |
| 233 | } else if unsafe { crate::rcc::REFCOUNT_STOP1 == 0 } { | 236 | } else if unsafe { REFCOUNT_STOP1 == 0 } { |
| 234 | trace!("low power: stop 1"); | 237 | trace!("low power: stop 1"); |
| 235 | Some(StopMode::Stop1) | 238 | Some(StopMode::Stop1) |
| 236 | } else { | 239 | } else { |
| @@ -240,7 +243,7 @@ impl Executor { | |||
| 240 | } | 243 | } |
| 241 | 244 | ||
| 242 | #[allow(unused_variables)] | 245 | #[allow(unused_variables)] |
| 243 | fn configure_stop(&mut self, stop_mode: StopMode) { | 246 | fn configure_stop(&self, stop_mode: StopMode) { |
| 244 | #[cfg(any(stm32l4, stm32l5, stm32u5, stm32u0, stm32wba, stm32wlex))] | 247 | #[cfg(any(stm32l4, stm32l5, stm32u5, stm32u0, stm32wba, stm32wlex))] |
| 245 | crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into())); | 248 | crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into())); |
| 246 | #[cfg(stm32h5)] | 249 | #[cfg(stm32h5)] |
| @@ -251,8 +254,8 @@ impl Executor { | |||
| 251 | }); | 254 | }); |
| 252 | } | 255 | } |
| 253 | 256 | ||
| 254 | fn configure_pwr(&mut self) { | 257 | fn configure_pwr(&self) { |
| 255 | self.scb.clear_sleepdeep(); | 258 | Self::get_scb().clear_sleepdeep(); |
| 256 | // Clear any previous stop flags | 259 | // Clear any previous stop flags |
| 257 | #[cfg(stm32wlex)] | 260 | #[cfg(stm32wlex)] |
| 258 | crate::pac::PWR.extscr().modify(|w| { | 261 | crate::pac::PWR.extscr().modify(|w| { |
| @@ -271,7 +274,7 @@ impl Executor { | |||
| 271 | self.configure_stop(stop_mode); | 274 | self.configure_stop(stop_mode); |
| 272 | 275 | ||
| 273 | #[cfg(not(feature = "low-power-debug-with-sleep"))] | 276 | #[cfg(not(feature = "low-power-debug-with-sleep"))] |
| 274 | self.scb.set_sleepdeep(); | 277 | Self::get_scb().set_sleepdeep(); |
| 275 | }); | 278 | }); |
| 276 | } | 279 | } |
| 277 | 280 | ||
| @@ -294,12 +297,11 @@ impl Executor { | |||
| 294 | /// | 297 | /// |
| 295 | /// This function never returns. | 298 | /// This function never returns. |
| 296 | pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { | 299 | pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { |
| 297 | let executor = unsafe { EXECUTOR.as_mut().unwrap() }; | 300 | init(self.inner.spawner()); |
| 298 | init(executor.inner.spawner()); | ||
| 299 | 301 | ||
| 300 | loop { | 302 | loop { |
| 301 | unsafe { | 303 | unsafe { |
| 302 | executor.inner.poll(); | 304 | self.inner.poll(); |
| 303 | self.configure_pwr(); | 305 | self.configure_pwr(); |
| 304 | asm!("wfe"); | 306 | asm!("wfe"); |
| 305 | #[cfg(stm32wlex)] | 307 | #[cfg(stm32wlex)] |
diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs index 584957c6d..2e1cbd702 100644 --- a/embassy-stm32/src/rcc/l.rs +++ b/embassy-stm32/src/rcc/l.rs | |||
| @@ -1,6 +1,3 @@ | |||
| 1 | #[cfg(all(feature = "low-power", stm32wlex))] | ||
| 2 | use core::mem::MaybeUninit; | ||
| 3 | |||
| 4 | #[cfg(any(stm32l0, stm32l1))] | 1 | #[cfg(any(stm32l0, stm32l1))] |
| 5 | pub use crate::pac::pwr::vals::Vos as VoltageScale; | 2 | pub use crate::pac::pwr::vals::Vos as VoltageScale; |
| 6 | use crate::pac::rcc::regs::Cfgr; | 3 | use crate::pac::rcc::regs::Cfgr; |
| @@ -14,42 +11,6 @@ use crate::time::Hertz; | |||
| 14 | /// HSI speed | 11 | /// HSI speed |
| 15 | pub const HSI_FREQ: Hertz = Hertz(16_000_000); | 12 | pub const HSI_FREQ: Hertz = Hertz(16_000_000); |
| 16 | 13 | ||
| 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 | |||
| 53 | #[derive(Clone, Copy, Eq, PartialEq)] | 14 | #[derive(Clone, Copy, Eq, PartialEq)] |
| 54 | pub enum HseMode { | 15 | pub enum HseMode { |
| 55 | /// crystal/ceramic oscillator (HSEBYP=0) | 16 | /// crystal/ceramic oscillator (HSEBYP=0) |
| @@ -193,10 +154,6 @@ fn msi_enable(range: MSIRange) { | |||
| 193 | } | 154 | } |
| 194 | 155 | ||
| 195 | pub(crate) unsafe fn init(config: Config) { | 156 | 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 | |||
| 200 | // Switch to MSI to prevent problems with PLL configuration. | 157 | // Switch to MSI to prevent problems with PLL configuration. |
| 201 | if !RCC.cr().read().msion() { | 158 | if !RCC.cr().read().msion() { |
| 202 | // Turn on MSI and configure it to 4MHz. | 159 | // Turn on MSI and configure it to 4MHz. |
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index ca7c28cbc..66ee06e17 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs | |||
| @@ -49,6 +49,9 @@ pub(crate) static mut REFCOUNT_STOP1: u32 = 0; | |||
| 49 | /// May be read without a critical section | 49 | /// May be read without a critical section |
| 50 | pub(crate) static mut REFCOUNT_STOP2: u32 = 0; | 50 | pub(crate) static mut REFCOUNT_STOP2: u32 = 0; |
| 51 | 51 | ||
| 52 | #[cfg(feature = "low-power")] | ||
| 53 | pub(crate) static mut RCC_CONFIG: Option<Config> = None; | ||
| 54 | |||
| 52 | #[cfg(backup_sram)] | 55 | #[cfg(backup_sram)] |
| 53 | pub(crate) static mut BKSRAM_RETAINED: bool = false; | 56 | pub(crate) static mut BKSRAM_RETAINED: bool = false; |
| 54 | 57 | ||
| @@ -408,6 +411,7 @@ pub(crate) fn init_rcc(_cs: CriticalSection, config: Config) { | |||
| 408 | 411 | ||
| 409 | #[cfg(feature = "low-power")] | 412 | #[cfg(feature = "low-power")] |
| 410 | { | 413 | { |
| 414 | RCC_CONFIG = Some(config); | ||
| 411 | REFCOUNT_STOP2 = 0; | 415 | REFCOUNT_STOP2 = 0; |
| 412 | REFCOUNT_STOP1 = 0; | 416 | REFCOUNT_STOP1 = 0; |
| 413 | } | 417 | } |
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 116b3c7ed..e88bd7ab2 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs | |||
| @@ -379,13 +379,16 @@ trait SealedInstance { | |||
| 379 | } | 379 | } |
| 380 | 380 | ||
| 381 | #[cfg(feature = "low-power")] | 381 | #[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 | |||
| 383 | #[cfg(feature = "_allow-disable-rtc")] | 385 | #[cfg(feature = "_allow-disable-rtc")] |
| 384 | if config._disable_rtc { | 386 | if config._disable_rtc { |
| 385 | return; | 387 | return; |
| 386 | } | 388 | } |
| 387 | 389 | ||
| 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); | ||
| 389 | 392 | ||
| 390 | trace!("low power: stop with rtc configured"); | 393 | trace!("low power: stop with rtc configured"); |
| 391 | } | 394 | } |
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 6d93b430a..0b75aef92 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs | |||
| @@ -245,7 +245,7 @@ embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { | |||
| 245 | impl RtcDriver { | 245 | impl RtcDriver { |
| 246 | /// initialize the timer, but don't start it. Used for chips like stm32wle5 | 246 | /// initialize the timer, but don't start it. Used for chips like stm32wle5 |
| 247 | /// for low power where the timer config is lost in STOP2. | 247 | /// 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) { |
| 249 | let r = regs_gp16(); | 249 | let r = regs_gp16(); |
| 250 | 250 | ||
| 251 | rcc::enable_and_reset_with_cs::<T>(cs); | 251 | rcc::enable_and_reset_with_cs::<T>(cs); |
| @@ -516,8 +516,3 @@ pub(crate) const fn get_driver() -> &'static RtcDriver { | |||
| 516 | pub(crate) fn init(cs: CriticalSection) { | 516 | pub(crate) fn init(cs: CriticalSection) { |
| 517 | DRIVER.init(cs) | 517 | DRIVER.init(cs) |
| 518 | } | 518 | } |
| 519 | |||
| 520 | #[cfg(all(feature = "low-power", stm32wlex))] | ||
| 521 | pub(crate) fn init_timer(cs: CriticalSection) { | ||
| 522 | DRIVER.init_timer(cs) | ||
| 523 | } | ||
