diff options
| author | xoviat <[email protected]> | 2025-11-04 11:35:27 -0600 |
|---|---|---|
| committer | xoviat <[email protected]> | 2025-11-04 11:35:27 -0600 |
| commit | 871189d198b4c8876e8dba36b9cf43bbfd64391c (patch) | |
| tree | 37db6ae864fbc52b44e549d1c0d291f63966790a /embassy-stm32/src | |
| parent | b867072c7eefdd2cf0a19bacd86f4be820624ed9 (diff) | |
stm32/low-power: cleanup and improve
Diffstat (limited to 'embassy-stm32/src')
| -rw-r--r-- | embassy-stm32/src/adc/v3.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/i2c/v2.rs | 10 | ||||
| -rw-r--r-- | embassy-stm32/src/low_power.rs | 161 | ||||
| -rw-r--r-- | embassy-stm32/src/time_driver.rs | 8 |
4 files changed, 98 insertions, 83 deletions
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 62c2da557..170b08a25 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs | |||
| @@ -463,7 +463,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 463 | ); | 463 | ); |
| 464 | 464 | ||
| 465 | #[cfg(all(feature = "low-power", stm32wlex))] | 465 | #[cfg(all(feature = "low-power", stm32wlex))] |
| 466 | let _device_busy = crate::low_power::DeviceBusy::new(); | 466 | let _device_busy = crate::low_power::DeviceBusy::new_stop1(); |
| 467 | 467 | ||
| 468 | // Ensure no conversions are ongoing and ADC is enabled. | 468 | // Ensure no conversions are ongoing and ADC is enabled. |
| 469 | Self::cancel_conversions(); | 469 | Self::cancel_conversions(); |
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 6f2d03bd1..978a401d5 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs | |||
| @@ -820,7 +820,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { | |||
| 820 | /// Write. | 820 | /// Write. |
| 821 | pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { | 821 | pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { |
| 822 | #[cfg(all(feature = "low-power", stm32wlex))] | 822 | #[cfg(all(feature = "low-power", stm32wlex))] |
| 823 | let _device_busy = crate::low_power::DeviceBusy::new(); | 823 | let _device_busy = crate::low_power::DeviceBusy::new_stop1(); |
| 824 | let timeout = self.timeout(); | 824 | let timeout = self.timeout(); |
| 825 | if write.is_empty() { | 825 | if write.is_empty() { |
| 826 | self.write_internal(address.into(), write, true, timeout) | 826 | self.write_internal(address.into(), write, true, timeout) |
| @@ -836,7 +836,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { | |||
| 836 | /// The buffers are concatenated in a single write transaction. | 836 | /// The buffers are concatenated in a single write transaction. |
| 837 | pub async fn write_vectored(&mut self, address: Address, write: &[&[u8]]) -> Result<(), Error> { | 837 | pub async fn write_vectored(&mut self, address: Address, write: &[&[u8]]) -> Result<(), Error> { |
| 838 | #[cfg(all(feature = "low-power", stm32wlex))] | 838 | #[cfg(all(feature = "low-power", stm32wlex))] |
| 839 | let _device_busy = crate::low_power::DeviceBusy::new(); | 839 | let _device_busy = crate::low_power::DeviceBusy::new_stop1(); |
| 840 | let timeout = self.timeout(); | 840 | let timeout = self.timeout(); |
| 841 | 841 | ||
| 842 | if write.is_empty() { | 842 | if write.is_empty() { |
| @@ -861,7 +861,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { | |||
| 861 | /// Read. | 861 | /// Read. |
| 862 | pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { | 862 | pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { |
| 863 | #[cfg(all(feature = "low-power", stm32wlex))] | 863 | #[cfg(all(feature = "low-power", stm32wlex))] |
| 864 | let _device_busy = crate::low_power::DeviceBusy::new(); | 864 | let _device_busy = crate::low_power::DeviceBusy::new_stop1(); |
| 865 | let timeout = self.timeout(); | 865 | let timeout = self.timeout(); |
| 866 | 866 | ||
| 867 | if buffer.is_empty() { | 867 | if buffer.is_empty() { |
| @@ -875,7 +875,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { | |||
| 875 | /// Write, restart, read. | 875 | /// Write, restart, read. |
| 876 | pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { | 876 | pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { |
| 877 | #[cfg(all(feature = "low-power", stm32wlex))] | 877 | #[cfg(all(feature = "low-power", stm32wlex))] |
| 878 | let _device_busy = crate::low_power::DeviceBusy::new(); | 878 | let _device_busy = crate::low_power::DeviceBusy::new_stop1(); |
| 879 | let timeout = self.timeout(); | 879 | let timeout = self.timeout(); |
| 880 | 880 | ||
| 881 | if write.is_empty() { | 881 | if write.is_empty() { |
| @@ -902,7 +902,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { | |||
| 902 | /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction | 902 | /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction |
| 903 | pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { | 903 | pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { |
| 904 | #[cfg(all(feature = "low-power", stm32wlex))] | 904 | #[cfg(all(feature = "low-power", stm32wlex))] |
| 905 | let _device_busy = crate::low_power::DeviceBusy::new(); | 905 | let _device_busy = crate::low_power::DeviceBusy::new_stop1(); |
| 906 | let _ = addr; | 906 | let _ = addr; |
| 907 | let _ = operations; | 907 | let _ = operations; |
| 908 | todo!() | 908 | todo!() |
diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index cde3153f6..938db2686 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs | |||
| @@ -57,10 +57,11 @@ use core::marker::PhantomData; | |||
| 57 | use core::sync::atomic::{Ordering, compiler_fence}; | 57 | use core::sync::atomic::{Ordering, compiler_fence}; |
| 58 | 58 | ||
| 59 | use cortex_m::peripheral::SCB; | 59 | use cortex_m::peripheral::SCB; |
| 60 | use critical_section::CriticalSection; | ||
| 60 | use embassy_executor::*; | 61 | use embassy_executor::*; |
| 61 | 62 | ||
| 62 | use crate::interrupt; | 63 | use crate::interrupt; |
| 63 | use crate::time_driver::{RtcDriver, get_driver}; | 64 | use crate::time_driver::get_driver; |
| 64 | 65 | ||
| 65 | const THREAD_PENDER: usize = usize::MAX; | 66 | const THREAD_PENDER: usize = usize::MAX; |
| 66 | 67 | ||
| @@ -68,46 +69,59 @@ use crate::rtc::Rtc; | |||
| 68 | 69 | ||
| 69 | static mut EXECUTOR: Option<Executor> = None; | 70 | static mut EXECUTOR: Option<Executor> = None; |
| 70 | 71 | ||
| 71 | #[cfg(stm32wlex)] | 72 | /// Prevent the device from going into the stop mode if held |
| 72 | pub(crate) use self::busy::DeviceBusy; | 73 | pub struct DeviceBusy(StopMode); |
| 73 | #[cfg(stm32wlex)] | ||
| 74 | mod busy { | ||
| 75 | use core::sync::atomic::{AtomicU32, Ordering}; | ||
| 76 | 74 | ||
| 77 | // Count of devices blocking STOP | 75 | impl DeviceBusy { |
| 78 | static STOP_BLOCKED: AtomicU32 = AtomicU32::new(0); | 76 | /// Create a new DeviceBusy with stop1. |
| 77 | pub fn new_stop1() -> Self { | ||
| 78 | Self::new(StopMode::Stop1) | ||
| 79 | } | ||
| 79 | 80 | ||
| 80 | /// Check if STOP1 is blocked. | 81 | /// Create a new DeviceBusy with stop2. |
| 81 | pub(crate) fn stop_blocked() -> bool { | 82 | pub fn new_stop2() -> Self { |
| 82 | STOP_BLOCKED.load(Ordering::SeqCst) > 0 | 83 | Self::new(StopMode::Stop2) |
| 83 | } | 84 | } |
| 84 | 85 | ||
| 85 | /// When ca device goes busy it will construct one of these where it will be dropped when the device goes idle. | 86 | /// Create a new DeviceBusy. |
| 86 | pub(crate) struct DeviceBusy {} | 87 | pub fn new(stop_mode: StopMode) -> Self { |
| 88 | critical_section::with(|_| unsafe { | ||
| 89 | match stop_mode { | ||
| 90 | StopMode::Stop1 => { | ||
| 91 | crate::rcc::REFCOUNT_STOP1 += 1; | ||
| 92 | } | ||
| 93 | StopMode::Stop2 => { | ||
| 94 | crate::rcc::REFCOUNT_STOP2 += 1; | ||
| 95 | } | ||
| 96 | } | ||
| 97 | }); | ||
| 87 | 98 | ||
| 88 | impl DeviceBusy { | 99 | Self(stop_mode) |
| 89 | /// Create a new DeviceBusy. | ||
| 90 | pub(crate) fn new() -> Self { | ||
| 91 | STOP_BLOCKED.fetch_add(1, Ordering::SeqCst); | ||
| 92 | trace!("low power: device busy: Stop:{}", STOP_BLOCKED.load(Ordering::SeqCst)); | ||
| 93 | Self {} | ||
| 94 | } | ||
| 95 | } | 100 | } |
| 101 | } | ||
| 96 | 102 | ||
| 97 | impl Drop for DeviceBusy { | 103 | impl Drop for DeviceBusy { |
| 98 | fn drop(&mut self) { | 104 | fn drop(&mut self) { |
| 99 | STOP_BLOCKED.fetch_sub(1, Ordering::SeqCst); | 105 | critical_section::with(|_| unsafe { |
| 100 | trace!("low power: device idle: Stop:{}", STOP_BLOCKED.load(Ordering::SeqCst)); | 106 | match self.0 { |
| 101 | } | 107 | StopMode::Stop1 => { |
| 108 | crate::rcc::REFCOUNT_STOP1 -= 1; | ||
| 109 | } | ||
| 110 | StopMode::Stop2 => { | ||
| 111 | crate::rcc::REFCOUNT_STOP2 -= 1; | ||
| 112 | } | ||
| 113 | } | ||
| 114 | }); | ||
| 102 | } | 115 | } |
| 103 | } | 116 | } |
| 117 | |||
| 104 | #[cfg(not(stm32u0))] | 118 | #[cfg(not(stm32u0))] |
| 105 | foreach_interrupt! { | 119 | foreach_interrupt! { |
| 106 | (RTC, rtc, $block:ident, WKUP, $irq:ident) => { | 120 | (RTC, rtc, $block:ident, WKUP, $irq:ident) => { |
| 107 | #[interrupt] | 121 | #[interrupt] |
| 108 | #[allow(non_snake_case)] | 122 | #[allow(non_snake_case)] |
| 109 | unsafe fn $irq() { | 123 | unsafe fn $irq() { |
| 110 | EXECUTOR.as_mut().unwrap().on_wakeup_irq(); | 124 | Executor::on_wakeup_irq(); |
| 111 | } | 125 | } |
| 112 | }; | 126 | }; |
| 113 | } | 127 | } |
| @@ -118,27 +132,28 @@ foreach_interrupt! { | |||
| 118 | #[interrupt] | 132 | #[interrupt] |
| 119 | #[allow(non_snake_case)] | 133 | #[allow(non_snake_case)] |
| 120 | unsafe fn $irq() { | 134 | unsafe fn $irq() { |
| 121 | EXECUTOR.as_mut().unwrap().on_wakeup_irq(); | 135 | Executor::on_wakeup_irq(); |
| 122 | } | 136 | } |
| 123 | }; | 137 | }; |
| 124 | } | 138 | } |
| 125 | 139 | ||
| 126 | #[allow(dead_code)] | 140 | #[allow(dead_code)] |
| 127 | pub(crate) unsafe fn on_wakeup_irq() { | 141 | pub(crate) unsafe fn on_wakeup_irq() { |
| 128 | if EXECUTOR.is_some() { | 142 | Executor::on_wakeup_irq(); |
| 129 | trace!("low power: wakeup irq"); | ||
| 130 | EXECUTOR.as_mut().unwrap().on_wakeup_irq(); | ||
| 131 | } | ||
| 132 | } | 143 | } |
| 133 | 144 | ||
| 134 | /// Configure STOP mode with RTC. | 145 | /// Configure STOP mode with RTC. |
| 135 | pub fn stop_with_rtc(rtc: Rtc) { | 146 | pub fn stop_with_rtc(rtc: Rtc) { |
| 136 | unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc) | 147 | assert!(unsafe { EXECUTOR.is_some() }); |
| 148 | |||
| 149 | Executor::stop_with_rtc(rtc) | ||
| 137 | } | 150 | } |
| 138 | 151 | ||
| 139 | /// Reconfigure the RTC, if set. | 152 | /// Reconfigure the RTC, if set. |
| 140 | pub fn reconfigure_rtc(f: impl FnOnce(&mut Rtc)) { | 153 | pub fn reconfigure_rtc(f: impl FnOnce(&mut Rtc)) { |
| 141 | unsafe { EXECUTOR.as_mut().unwrap() }.reconfigure_rtc(f); | 154 | assert!(unsafe { EXECUTOR.is_some() }); |
| 155 | |||
| 156 | Executor::reconfigure_rtc(f); | ||
| 142 | } | 157 | } |
| 143 | 158 | ||
| 144 | /// Get whether the core is ready to enter the given stop mode. | 159 | /// Get whether the core is ready to enter the given stop mode. |
| @@ -146,11 +161,11 @@ pub fn reconfigure_rtc(f: impl FnOnce(&mut Rtc)) { | |||
| 146 | /// This will return false if some peripheral driver is in use that | 161 | /// This will return false if some peripheral driver is in use that |
| 147 | /// prevents entering the given stop mode. | 162 | /// prevents entering the given stop mode. |
| 148 | pub fn stop_ready(stop_mode: StopMode) -> bool { | 163 | pub fn stop_ready(stop_mode: StopMode) -> bool { |
| 149 | match unsafe { EXECUTOR.as_mut().unwrap() }.stop_mode() { | 164 | critical_section::with(|cs| match Executor::stop_mode(cs) { |
| 150 | Some(StopMode::Stop2) => true, | 165 | Some(StopMode::Stop2) => true, |
| 151 | Some(StopMode::Stop1) => stop_mode == StopMode::Stop1, | 166 | Some(StopMode::Stop1) => stop_mode == StopMode::Stop1, |
| 152 | None => false, | 167 | None => false, |
| 153 | } | 168 | }) |
| 154 | } | 169 | } |
| 155 | 170 | ||
| 156 | /// Available Stop modes. | 171 | /// Available Stop modes. |
| @@ -193,7 +208,6 @@ pub struct Executor { | |||
| 193 | inner: raw::Executor, | 208 | inner: raw::Executor, |
| 194 | not_send: PhantomData<*mut ()>, | 209 | not_send: PhantomData<*mut ()>, |
| 195 | scb: SCB, | 210 | scb: SCB, |
| 196 | time_driver: &'static RtcDriver, | ||
| 197 | } | 211 | } |
| 198 | 212 | ||
| 199 | impl Executor { | 213 | impl Executor { |
| @@ -206,7 +220,6 @@ impl Executor { | |||
| 206 | inner: raw::Executor::new(THREAD_PENDER as *mut ()), | 220 | inner: raw::Executor::new(THREAD_PENDER as *mut ()), |
| 207 | not_send: PhantomData, | 221 | not_send: PhantomData, |
| 208 | scb: cortex_m::Peripherals::steal().SCB, | 222 | scb: cortex_m::Peripherals::steal().SCB, |
| 209 | time_driver: get_driver(), | ||
| 210 | }); | 223 | }); |
| 211 | 224 | ||
| 212 | let executor = EXECUTOR.as_mut().unwrap(); | 225 | let executor = EXECUTOR.as_mut().unwrap(); |
| @@ -215,54 +228,50 @@ impl Executor { | |||
| 215 | }) | 228 | }) |
| 216 | } | 229 | } |
| 217 | 230 | ||
| 218 | unsafe fn on_wakeup_irq(&mut self) { | 231 | pub(self) unsafe fn on_wakeup_irq() { |
| 219 | #[cfg(stm32wlex)] | 232 | critical_section::with(|cs| { |
| 220 | { | 233 | if !get_driver().is_rtc_set(cs) { |
| 221 | let extscr = crate::pac::PWR.extscr().read(); | 234 | trace!("low power: wakeup irq; rtc not set"); |
| 222 | if extscr.c1stop2f() || extscr.c1stopf() { | 235 | |
| 223 | // when we wake from any stop mode we need to re-initialize the rcc | 236 | return; |
| 224 | crate::rcc::apply_resume_config(); | 237 | } |
| 225 | if extscr.c1stop2f() { | 238 | |
| 226 | // when we wake from STOP2, we need to re-initialize the time driver | 239 | #[cfg(stm32wlex)] |
| 227 | critical_section::with(|cs| crate::time_driver::init_timer(cs)); | 240 | { |
| 228 | // reset the refcounts for STOP2 and STOP1 (initializing the time driver will increment one of them for the timer) | 241 | let extscr = crate::pac::PWR.extscr().read(); |
| 229 | // and given that we just woke from STOP2, we can reset them | 242 | if extscr.c1stop2f() || extscr.c1stopf() { |
| 230 | crate::rcc::REFCOUNT_STOP2 = 0; | 243 | // when we wake from any stop mode we need to re-initialize the rcc |
| 231 | crate::rcc::REFCOUNT_STOP1 = 0; | 244 | crate::rcc::apply_resume_config(); |
| 245 | if extscr.c1stop2f() { | ||
| 246 | // when we wake from STOP2, we need to re-initialize the time driver | ||
| 247 | crate::time_driver::init_timer(cs); | ||
| 248 | // reset the refcounts for STOP2 and STOP1 (initializing the time driver will increment one of them for the timer) | ||
| 249 | // and given that we just woke from STOP2, we can reset them | ||
| 250 | crate::rcc::REFCOUNT_STOP2 = 0; | ||
| 251 | crate::rcc::REFCOUNT_STOP1 = 0; | ||
| 252 | } | ||
| 232 | } | 253 | } |
| 233 | } | 254 | } |
| 234 | } | 255 | get_driver().resume_time(); |
| 235 | self.time_driver.resume_time(); | 256 | trace!("low power: resume"); |
| 236 | trace!("low power: resume"); | 257 | }); |
| 237 | } | 258 | } |
| 238 | 259 | ||
| 239 | pub(self) fn stop_with_rtc(&mut self, rtc: Rtc) { | 260 | pub(self) fn stop_with_rtc(rtc: Rtc) { |
| 240 | self.time_driver.set_rtc(rtc); | 261 | get_driver().set_rtc(rtc); |
| 241 | self.time_driver.reconfigure_rtc(|rtc| rtc.enable_wakeup_line()); | 262 | get_driver().reconfigure_rtc(|rtc| rtc.enable_wakeup_line()); |
| 242 | 263 | ||
| 243 | trace!("low power: stop with rtc configured"); | 264 | trace!("low power: stop with rtc configured"); |
| 244 | } | 265 | } |
| 245 | 266 | ||
| 246 | pub(self) fn reconfigure_rtc(&mut self, f: impl FnOnce(&mut Rtc)) { | 267 | pub(self) fn reconfigure_rtc(f: impl FnOnce(&mut Rtc)) { |
| 247 | self.time_driver.reconfigure_rtc(f); | 268 | get_driver().reconfigure_rtc(f); |
| 248 | } | ||
| 249 | |||
| 250 | fn stop1_ok_to_enter(&self) -> bool { | ||
| 251 | #[cfg(stm32wlex)] | ||
| 252 | if self::busy::stop_blocked() { | ||
| 253 | return false; | ||
| 254 | } | ||
| 255 | unsafe { crate::rcc::REFCOUNT_STOP1 == 0 } | ||
| 256 | } | ||
| 257 | |||
| 258 | fn stop2_ok_to_enter(&self) -> bool { | ||
| 259 | self.stop1_ok_to_enter() && unsafe { crate::rcc::REFCOUNT_STOP2 == 0 } | ||
| 260 | } | 269 | } |
| 261 | 270 | ||
| 262 | fn stop_mode(&self) -> Option<StopMode> { | 271 | fn stop_mode(_cs: CriticalSection) -> Option<StopMode> { |
| 263 | if self.stop2_ok_to_enter() { | 272 | if unsafe { crate::rcc::REFCOUNT_STOP2 == 0 && crate::rcc::REFCOUNT_STOP1 == 0 } { |
| 264 | Some(StopMode::Stop2) | 273 | Some(StopMode::Stop2) |
| 265 | } else if self.stop1_ok_to_enter() { | 274 | } else if unsafe { crate::rcc::REFCOUNT_STOP1 == 0 } { |
| 266 | Some(StopMode::Stop1) | 275 | Some(StopMode::Stop1) |
| 267 | } else { | 276 | } else { |
| 268 | None | 277 | None |
| @@ -291,14 +300,14 @@ impl Executor { | |||
| 291 | 300 | ||
| 292 | compiler_fence(Ordering::SeqCst); | 301 | compiler_fence(Ordering::SeqCst); |
| 293 | 302 | ||
| 294 | let stop_mode = self.stop_mode(); | 303 | let stop_mode = critical_section::with(|cs| Self::stop_mode(cs)); |
| 295 | 304 | ||
| 296 | if stop_mode.is_none() { | 305 | if stop_mode.is_none() { |
| 297 | trace!("low power: not ready to stop"); | 306 | trace!("low power: not ready to stop"); |
| 298 | return; | 307 | return; |
| 299 | } | 308 | } |
| 300 | 309 | ||
| 301 | if self.time_driver.pause_time().is_err() { | 310 | if get_driver().pause_time().is_err() { |
| 302 | trace!("low power: failed to pause time"); | 311 | trace!("low power: failed to pause time"); |
| 303 | return; | 312 | return; |
| 304 | } | 313 | } |
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 4956d1f68..152d3d22e 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs | |||
| @@ -413,6 +413,12 @@ impl RtcDriver { | |||
| 413 | } | 413 | } |
| 414 | 414 | ||
| 415 | #[cfg(feature = "low-power")] | 415 | #[cfg(feature = "low-power")] |
| 416 | /// Has the rtc been set? | ||
| 417 | pub(crate) fn is_rtc_set(&self, cs: CriticalSection) -> bool { | ||
| 418 | self.rtc.borrow(cs).borrow().is_some() | ||
| 419 | } | ||
| 420 | |||
| 421 | #[cfg(feature = "low-power")] | ||
| 416 | /// Set the rtc but panic if it's already been set | 422 | /// Set the rtc but panic if it's already been set |
| 417 | pub(crate) fn reconfigure_rtc(&self, f: impl FnOnce(&mut Rtc)) { | 423 | pub(crate) fn reconfigure_rtc(&self, f: impl FnOnce(&mut Rtc)) { |
| 418 | critical_section::with(|cs| f(self.rtc.borrow(cs).borrow_mut().as_mut().unwrap())); | 424 | critical_section::with(|cs| f(self.rtc.borrow(cs).borrow_mut().as_mut().unwrap())); |
| @@ -543,7 +549,7 @@ impl Driver for RtcDriver { | |||
| 543 | } | 549 | } |
| 544 | 550 | ||
| 545 | #[cfg(feature = "low-power")] | 551 | #[cfg(feature = "low-power")] |
| 546 | pub(crate) fn get_driver() -> &'static RtcDriver { | 552 | pub(crate) const fn get_driver() -> &'static RtcDriver { |
| 547 | &DRIVER | 553 | &DRIVER |
| 548 | } | 554 | } |
| 549 | 555 | ||
