diff options
| -rw-r--r-- | embassy-stm32/src/low_power.rs | 126 | ||||
| -rw-r--r-- | embassy-stm32/src/rtc/v2.rs | 55 | ||||
| -rw-r--r-- | embassy-stm32/src/time_driver.rs | 107 |
3 files changed, 196 insertions, 92 deletions
diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index cf12a1ea5..964819abb 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs | |||
| @@ -9,12 +9,11 @@ use crate::interrupt; | |||
| 9 | use crate::interrupt::typelevel::Interrupt; | 9 | use crate::interrupt::typelevel::Interrupt; |
| 10 | use crate::pac::EXTI; | 10 | use crate::pac::EXTI; |
| 11 | use crate::rcc::low_power_ready; | 11 | use crate::rcc::low_power_ready; |
| 12 | use crate::time_driver::{pause_time, resume_time, time_until_next_alarm}; | 12 | use crate::time_driver::{get_driver, RtcDriver}; |
| 13 | 13 | ||
| 14 | const THREAD_PENDER: usize = usize::MAX; | 14 | const THREAD_PENDER: usize = usize::MAX; |
| 15 | const THRESHOLD: Duration = Duration::from_millis(500); | ||
| 16 | 15 | ||
| 17 | use crate::rtc::{Rtc, RtcInstant}; | 16 | use crate::rtc::Rtc; |
| 18 | 17 | ||
| 19 | static mut EXECUTOR: Option<Executor> = None; | 18 | static mut EXECUTOR: Option<Executor> = None; |
| 20 | 19 | ||
| @@ -27,20 +26,30 @@ foreach_interrupt! { | |||
| 27 | }; | 26 | }; |
| 28 | } | 27 | } |
| 29 | 28 | ||
| 29 | // pub fn timer_driver_pause_time() { | ||
| 30 | // pause_time(); | ||
| 31 | // } | ||
| 32 | |||
| 30 | pub fn stop_with_rtc(rtc: &'static Rtc) { | 33 | pub fn stop_with_rtc(rtc: &'static Rtc) { |
| 31 | unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc) | 34 | unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc) |
| 32 | } | 35 | } |
| 33 | 36 | ||
| 34 | pub fn start_wakeup_alarm(requested_duration: embassy_time::Duration) -> RtcInstant { | 37 | // pub fn start_wakeup_alarm(requested_duration: embassy_time::Duration) { |
| 35 | unsafe { EXECUTOR.as_mut().unwrap() } | 38 | // let rtc_instant = unsafe { EXECUTOR.as_mut().unwrap() } |
| 36 | .rtc | 39 | // .rtc |
| 37 | .unwrap() | 40 | // .unwrap() |
| 38 | .start_wakeup_alarm(requested_duration) | 41 | // .start_wakeup_alarm(requested_duration); |
| 39 | } | 42 | // |
| 40 | 43 | // unsafe { EXECUTOR.as_mut().unwrap() }.last_stop = Some(rtc_instant); | |
| 41 | pub fn stop_wakeup_alarm() -> RtcInstant { | 44 | // } |
| 42 | unsafe { EXECUTOR.as_mut().unwrap() }.rtc.unwrap().stop_wakeup_alarm() | 45 | // |
| 43 | } | 46 | // pub fn set_sleepdeep() { |
| 47 | // unsafe { EXECUTOR.as_mut().unwrap() }.scb.set_sleepdeep(); | ||
| 48 | // } | ||
| 49 | // | ||
| 50 | // pub fn stop_wakeup_alarm() -> RtcInstant { | ||
| 51 | // unsafe { EXECUTOR.as_mut().unwrap() }.rtc.unwrap().stop_wakeup_alarm() | ||
| 52 | // } | ||
| 44 | 53 | ||
| 45 | /// Thread mode executor, using WFE/SEV. | 54 | /// Thread mode executor, using WFE/SEV. |
| 46 | /// | 55 | /// |
| @@ -56,15 +65,15 @@ pub struct Executor { | |||
| 56 | inner: raw::Executor, | 65 | inner: raw::Executor, |
| 57 | not_send: PhantomData<*mut ()>, | 66 | not_send: PhantomData<*mut ()>, |
| 58 | scb: SCB, | 67 | scb: SCB, |
| 59 | pub(self) rtc: Option<&'static Rtc>, | 68 | time_driver: &'static RtcDriver, |
| 60 | stop_time: embassy_time::Duration, | 69 | stop_time: embassy_time::Duration, |
| 61 | next_alarm: embassy_time::Duration, | 70 | next_alarm: embassy_time::Duration, |
| 62 | last_stop: Option<crate::rtc::RtcInstant>, | 71 | wfe: u8, |
| 63 | } | 72 | } |
| 64 | 73 | ||
| 65 | impl Executor { | 74 | impl Executor { |
| 66 | /// Create a new Executor. | 75 | /// Create a new Executor. |
| 67 | pub fn new() -> &'static mut Self { | 76 | pub fn take() -> &'static mut Self { |
| 68 | unsafe { | 77 | unsafe { |
| 69 | assert!(EXECUTOR.is_none()); | 78 | assert!(EXECUTOR.is_none()); |
| 70 | 79 | ||
| @@ -72,10 +81,10 @@ impl Executor { | |||
| 72 | inner: raw::Executor::new(THREAD_PENDER as *mut ()), | 81 | inner: raw::Executor::new(THREAD_PENDER as *mut ()), |
| 73 | not_send: PhantomData, | 82 | not_send: PhantomData, |
| 74 | scb: cortex_m::Peripherals::steal().SCB, | 83 | scb: cortex_m::Peripherals::steal().SCB, |
| 75 | rtc: None, | 84 | time_driver: get_driver(), |
| 76 | stop_time: Duration::from_ticks(0), | 85 | stop_time: Duration::from_ticks(0), |
| 77 | next_alarm: Duration::from_ticks(u64::MAX), | 86 | next_alarm: Duration::from_ticks(u64::MAX), |
| 78 | last_stop: None, | 87 | wfe: 0, |
| 79 | }); | 88 | }); |
| 80 | 89 | ||
| 81 | EXECUTOR.as_mut().unwrap() | 90 | EXECUTOR.as_mut().unwrap() |
| @@ -83,9 +92,31 @@ impl Executor { | |||
| 83 | } | 92 | } |
| 84 | 93 | ||
| 85 | unsafe fn on_wakeup_irq(&mut self) { | 94 | unsafe fn on_wakeup_irq(&mut self) { |
| 86 | trace!("low power: one wakekup irq"); | 95 | trace!("low power: on wakeup irq"); |
| 96 | |||
| 97 | if crate::pac::RTC.isr().read().wutf() { | ||
| 98 | trace!("low power: wutf set"); | ||
| 99 | } else { | ||
| 100 | trace!("low power: wutf not set"); | ||
| 101 | } | ||
| 102 | |||
| 103 | self.time_driver.resume_time(); | ||
| 104 | trace!("low power: resume time"); | ||
| 87 | 105 | ||
| 88 | self.rtc.unwrap().clear_wakeup_alarm(); | 106 | crate::interrupt::typelevel::RTC_WKUP::disable(); |
| 107 | |||
| 108 | // cortex_m::asm::bkpt(); | ||
| 109 | |||
| 110 | // let time_elasped = self.rtc.unwrap().stop_wakeup_alarm() - self.last_stop.take().unwrap(); | ||
| 111 | // | ||
| 112 | // trace!("low power: {} ms elapsed", time_elasped.as_millis()); | ||
| 113 | // | ||
| 114 | // resume_time(time_elasped); | ||
| 115 | // trace!("low power: resume time"); | ||
| 116 | // | ||
| 117 | // self.scb.clear_sleepdeep(); | ||
| 118 | |||
| 119 | // cortex_m::asm::bkpt(); | ||
| 89 | // Self::get_scb().set_sleeponexit(); | 120 | // Self::get_scb().set_sleeponexit(); |
| 90 | // | 121 | // |
| 91 | // return; | 122 | // return; |
| @@ -110,48 +141,33 @@ impl Executor { | |||
| 110 | } | 141 | } |
| 111 | 142 | ||
| 112 | pub(self) fn stop_with_rtc(&mut self, rtc: &'static Rtc) { | 143 | pub(self) fn stop_with_rtc(&mut self, rtc: &'static Rtc) { |
| 113 | assert!(self.rtc.is_none()); | 144 | trace!("low power: stop with rtc configured"); |
| 145 | |||
| 146 | self.time_driver.set_rtc(rtc); | ||
| 114 | 147 | ||
| 115 | crate::interrupt::typelevel::RTC_WKUP::unpend(); | 148 | crate::interrupt::typelevel::RTC_WKUP::unpend(); |
| 116 | unsafe { crate::interrupt::typelevel::RTC_WKUP::enable() }; | 149 | unsafe { crate::interrupt::typelevel::RTC_WKUP::enable() }; |
| 117 | 150 | ||
| 118 | EXTI.rtsr(0).modify(|w| w.set_line(22, true)); | 151 | EXTI.rtsr(0).modify(|w| w.set_line(22, true)); |
| 119 | EXTI.imr(0).modify(|w| w.set_line(22, true)); | 152 | EXTI.imr(0).modify(|w| w.set_line(22, true)); |
| 120 | |||
| 121 | self.rtc = Some(rtc); | ||
| 122 | } | 153 | } |
| 123 | 154 | ||
| 124 | fn configure_pwr(&self) { | 155 | fn configure_pwr(&mut self) { |
| 125 | // defeat the borrow checker | 156 | trace!("low power: configure_pwr"); |
| 126 | let s = unsafe { EXECUTOR.as_mut().unwrap() }; | ||
| 127 | 157 | ||
| 128 | // trace!("configure_pwr"); | 158 | self.scb.clear_sleepdeep(); |
| 129 | // | 159 | if !low_power_ready() { |
| 130 | // if !low_power_ready() { | 160 | trace!("low power: configure_pwr: low power not ready"); |
| 131 | // trace!("configure_pwr: low power not ready"); | 161 | return; |
| 132 | // return; | 162 | } |
| 133 | // } | 163 | |
| 134 | // | 164 | if self.time_driver.pause_time().is_err() { |
| 135 | // let time_until_next_alarm = time_until_next_alarm(); | 165 | trace!("low power: configure_pwr: time driver failed to pause"); |
| 136 | // if time_until_next_alarm < THRESHOLD { | 166 | return; |
| 137 | // trace!("configure_pwr: not enough time until next alarm"); | 167 | } |
| 138 | // return; | 168 | |
| 139 | // } | 169 | trace!("low power: enter stop..."); |
| 140 | // | 170 | self.scb.set_sleepdeep(); |
| 141 | // unsafe { | ||
| 142 | // NEXT_ALARM = time_until_next_alarm; | ||
| 143 | // if RTC_INSTANT.is_none() { | ||
| 144 | // RTC_INSTANT = Some(start_wakeup_alarm(time_until_next_alarm)) | ||
| 145 | // } | ||
| 146 | // }; | ||
| 147 | // | ||
| 148 | // // return; | ||
| 149 | // | ||
| 150 | // pause_time(); | ||
| 151 | // | ||
| 152 | // trace!("enter stop..."); | ||
| 153 | // | ||
| 154 | // Self::get_scb().set_sleepdeep(); | ||
| 155 | } | 171 | } |
| 156 | 172 | ||
| 157 | /// Run the executor. | 173 | /// Run the executor. |
| @@ -173,11 +189,11 @@ impl Executor { | |||
| 173 | /// | 189 | /// |
| 174 | /// This function never returns. | 190 | /// This function never returns. |
| 175 | pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { | 191 | pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { |
| 176 | init(self.inner.spawner()); | 192 | init(unsafe { EXECUTOR.as_mut().unwrap() }.inner.spawner()); |
| 177 | 193 | ||
| 178 | loop { | 194 | loop { |
| 179 | unsafe { | 195 | unsafe { |
| 180 | self.inner.poll(); | 196 | EXECUTOR.as_mut().unwrap().inner.poll(); |
| 181 | self.configure_pwr(); | 197 | self.configure_pwr(); |
| 182 | asm!("wfe"); | 198 | asm!("wfe"); |
| 183 | }; | 199 | }; |
diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 197c3b8f9..525dc45a2 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs | |||
| @@ -30,6 +30,8 @@ impl RtcInstant { | |||
| 30 | 30 | ||
| 31 | let _ = RTC::regs().dr().read(); | 31 | let _ = RTC::regs().dr().read(); |
| 32 | 32 | ||
| 33 | trace!("rtc: instant now: st, ssr: {}, {}", st, ssr); | ||
| 34 | |||
| 33 | Self { ssr, st } | 35 | Self { ssr, st } |
| 34 | } | 36 | } |
| 35 | } | 37 | } |
| @@ -146,6 +148,21 @@ impl super::Rtc { | |||
| 146 | } | 148 | } |
| 147 | } | 149 | } |
| 148 | 150 | ||
| 151 | // pub(crate) fn clear_wakeup_alarm(&self) { | ||
| 152 | // use crate::interrupt::typelevel::Interrupt; | ||
| 153 | // | ||
| 154 | // self.write(false, |regs| { | ||
| 155 | // regs.cr().modify(|w| w.set_wutie(false)); | ||
| 156 | // | ||
| 157 | // regs.isr().modify(|w| w.set_wutf(false)); | ||
| 158 | // crate::pac::PWR.cr1().modify(|w| w.set_cwuf(false)); | ||
| 159 | // crate::pac::EXTI.pr(0).modify(|w| w.set_line(22, false)); | ||
| 160 | // crate::interrupt::typelevel::RTC_WKUP::unpend(); | ||
| 161 | // | ||
| 162 | // regs.cr().modify(|w| w.set_wutie(true)); | ||
| 163 | // }); | ||
| 164 | // } | ||
| 165 | |||
| 149 | #[allow(dead_code)] | 166 | #[allow(dead_code)] |
| 150 | #[cfg(all(feature = "time", any(stm32wb, stm32f4)))] | 167 | #[cfg(all(feature = "time", any(stm32wb, stm32f4)))] |
| 151 | /// start the wakeup alarm and return the actual duration of the alarm | 168 | /// start the wakeup alarm and return the actual duration of the alarm |
| @@ -157,6 +174,7 @@ impl super::Rtc { | |||
| 157 | pub(crate) fn start_wakeup_alarm(&self, requested_duration: embassy_time::Duration) -> RtcInstant { | 174 | pub(crate) fn start_wakeup_alarm(&self, requested_duration: embassy_time::Duration) -> RtcInstant { |
| 158 | use embassy_time::{Duration, TICK_HZ}; | 175 | use embassy_time::{Duration, TICK_HZ}; |
| 159 | 176 | ||
| 177 | use crate::interrupt::typelevel::Interrupt; | ||
| 160 | use crate::rcc::get_freqs; | 178 | use crate::rcc::get_freqs; |
| 161 | 179 | ||
| 162 | let rtc_hz = unsafe { get_freqs() }.rtc.unwrap().0 as u64; | 180 | let rtc_hz = unsafe { get_freqs() }.rtc.unwrap().0 as u64; |
| @@ -176,28 +194,40 @@ impl super::Rtc { | |||
| 176 | rtc_ticks as u64 * TICK_HZ * (<WakeupPrescaler as Into<u32>>::into(prescaler) as u64) / rtc_hz, | 194 | rtc_ticks as u64 * TICK_HZ * (<WakeupPrescaler as Into<u32>>::into(prescaler) as u64) / rtc_hz, |
| 177 | ); | 195 | ); |
| 178 | 196 | ||
| 179 | trace!("rtc: set wakeup timer for {} ms", duration.as_millis()); | ||
| 180 | |||
| 181 | self.write(false, |regs| { | 197 | self.write(false, |regs| { |
| 182 | // regs.cr().modify(|w| w.set_wutie(true)); | ||
| 183 | |||
| 184 | regs.cr().modify(|w| w.set_wute(false)); | 198 | regs.cr().modify(|w| w.set_wute(false)); |
| 185 | regs.isr().modify(|w| w.set_wutf(false)); | 199 | regs.isr().modify(|w| w.set_wutf(false)); |
| 186 | while !regs.isr().read().wutwf() {} | 200 | while !regs.isr().read().wutwf() {} |
| 187 | 201 | ||
| 188 | regs.cr().modify(|w| w.set_wucksel(prescaler.into())); | 202 | regs.cr().modify(|w| w.set_wucksel(prescaler.into())); |
| 189 | regs.cr().modify(|w| w.set_wute(true)); | 203 | regs.cr().modify(|w| w.set_wute(true)); |
| 190 | }); | ||
| 191 | |||
| 192 | self.write(false, |regs| { | ||
| 193 | regs.cr().modify(|w| w.set_wutie(false)); | ||
| 194 | |||
| 195 | regs.isr().modify(|w| w.set_wutf(false)); | ||
| 196 | crate::pac::PWR.cr1().modify(|w| w.set_cwuf(false)); | ||
| 197 | |||
| 198 | regs.cr().modify(|w| w.set_wutie(true)); | 204 | regs.cr().modify(|w| w.set_wutie(true)); |
| 199 | }); | 205 | }); |
| 200 | 206 | ||
| 207 | trace!("rtc: start wakeup alarm for {} ms", duration.as_millis()); | ||
| 208 | |||
| 209 | // self.write(false, |regs| { | ||
| 210 | // regs.cr().modify(|w| w.set_wutie(false)); | ||
| 211 | // | ||
| 212 | // regs.isr().modify(|w| w.set_wutf(false)); | ||
| 213 | // | ||
| 214 | // regs.cr().modify(|w| w.set_wutie(true)); | ||
| 215 | // }); | ||
| 216 | // | ||
| 217 | // trace!("rtc: clear wuf..."); | ||
| 218 | // crate::pac::PWR.cr1().modify(|w| w.set_cwuf(true)); | ||
| 219 | // while crate::pac::PWR.csr1().read().wuf() {} | ||
| 220 | // trace!("rtc: clear wuf...done"); | ||
| 221 | // | ||
| 222 | // crate::pac::PWR | ||
| 223 | // .cr1() | ||
| 224 | // .modify(|w| w.set_pdds(crate::pac::pwr::vals::Pdds::STANDBY_MODE)); | ||
| 225 | // | ||
| 226 | // // crate::pac::PWR.cr1().modify(|w| w.set_lpds(true)); | ||
| 227 | // | ||
| 228 | // // crate::pac::EXTI.pr(0).modify(|w| w.set_line(22, true)); | ||
| 229 | // crate::interrupt::typelevel::RTC_WKUP::unpend(); | ||
| 230 | |||
| 201 | RtcInstant::now() | 231 | RtcInstant::now() |
| 202 | } | 232 | } |
| 203 | 233 | ||
| @@ -211,6 +241,7 @@ impl super::Rtc { | |||
| 211 | trace!("rtc: stop wakeup alarm..."); | 241 | trace!("rtc: stop wakeup alarm..."); |
| 212 | 242 | ||
| 213 | self.write(false, |regs| { | 243 | self.write(false, |regs| { |
| 244 | regs.cr().modify(|w| w.set_wutie(false)); | ||
| 214 | regs.cr().modify(|w| w.set_wute(false)); | 245 | regs.cr().modify(|w| w.set_wute(false)); |
| 215 | regs.isr().modify(|w| w.set_wutf(false)); | 246 | regs.isr().modify(|w| w.set_wutf(false)); |
| 216 | }); | 247 | }); |
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 8e05346ad..56f42aa96 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs | |||
| @@ -14,6 +14,8 @@ use stm32_metapac::timer::regs; | |||
| 14 | use crate::interrupt::typelevel::Interrupt; | 14 | use crate::interrupt::typelevel::Interrupt; |
| 15 | use crate::pac::timer::vals; | 15 | use crate::pac::timer::vals; |
| 16 | use crate::rcc::sealed::RccPeripheral; | 16 | use crate::rcc::sealed::RccPeripheral; |
| 17 | #[cfg(feature = "low-power")] | ||
| 18 | use crate::rtc::{Rtc, RtcInstant}; | ||
| 17 | use crate::timer::sealed::{Basic16bitInstance as BasicInstance, GeneralPurpose16bitInstance as Instance}; | 19 | use crate::timer::sealed::{Basic16bitInstance as BasicInstance, GeneralPurpose16bitInstance as Instance}; |
| 18 | use crate::{interrupt, peripherals}; | 20 | use crate::{interrupt, peripherals}; |
| 19 | 21 | ||
| @@ -130,12 +132,16 @@ impl AlarmState { | |||
| 130 | } | 132 | } |
| 131 | } | 133 | } |
| 132 | 134 | ||
| 133 | struct RtcDriver { | 135 | pub(crate) struct RtcDriver { |
| 134 | /// Number of 2^15 periods elapsed since boot. | 136 | /// Number of 2^15 periods elapsed since boot. |
| 135 | period: AtomicU32, | 137 | period: AtomicU32, |
| 136 | alarm_count: AtomicU8, | 138 | alarm_count: AtomicU8, |
| 137 | /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled. | 139 | /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled. |
| 138 | alarms: Mutex<CriticalSectionRawMutex, [AlarmState; ALARM_COUNT]>, | 140 | alarms: Mutex<CriticalSectionRawMutex, [AlarmState; ALARM_COUNT]>, |
| 141 | #[cfg(feature = "low-power")] | ||
| 142 | rtc: Mutex<CriticalSectionRawMutex, Cell<Option<&'static Rtc>>>, | ||
| 143 | #[cfg(feature = "low-power")] | ||
| 144 | stop_time: Mutex<CriticalSectionRawMutex, Cell<Option<RtcInstant>>>, | ||
| 139 | } | 145 | } |
| 140 | 146 | ||
| 141 | const ALARM_STATE_NEW: AlarmState = AlarmState::new(); | 147 | const ALARM_STATE_NEW: AlarmState = AlarmState::new(); |
| @@ -144,6 +150,10 @@ embassy_time::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { | |||
| 144 | period: AtomicU32::new(0), | 150 | period: AtomicU32::new(0), |
| 145 | alarm_count: AtomicU8::new(0), | 151 | alarm_count: AtomicU8::new(0), |
| 146 | alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [ALARM_STATE_NEW; ALARM_COUNT]), | 152 | alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [ALARM_STATE_NEW; ALARM_COUNT]), |
| 153 | #[cfg(feature = "low-power")] | ||
| 154 | rtc: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), | ||
| 155 | #[cfg(feature = "low-power")] | ||
| 156 | stop_time: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), | ||
| 147 | }); | 157 | }); |
| 148 | 158 | ||
| 149 | impl RtcDriver { | 159 | impl RtcDriver { |
| @@ -261,8 +271,14 @@ impl RtcDriver { | |||
| 261 | } | 271 | } |
| 262 | 272 | ||
| 263 | #[cfg(feature = "low-power")] | 273 | #[cfg(feature = "low-power")] |
| 274 | /// Set the rtc but panic if it's already been set | ||
| 275 | pub(crate) fn set_rtc(&self, rtc: &'static Rtc) { | ||
| 276 | critical_section::with(|cs| assert!(self.rtc.borrow(cs).replace(Some(rtc)).is_none())); | ||
| 277 | } | ||
| 278 | |||
| 279 | #[cfg(feature = "low-power")] | ||
| 264 | /// Compute the approximate amount of time until the next alarm | 280 | /// Compute the approximate amount of time until the next alarm |
| 265 | pub(crate) fn time_until_next_alarm(&self) -> embassy_time::Duration { | 281 | fn time_until_next_alarm(&self) -> embassy_time::Duration { |
| 266 | critical_section::with(|cs| { | 282 | critical_section::with(|cs| { |
| 267 | let now = self.now() + 32; | 283 | let now = self.now() + 32; |
| 268 | 284 | ||
| @@ -278,14 +294,8 @@ impl RtcDriver { | |||
| 278 | } | 294 | } |
| 279 | 295 | ||
| 280 | #[cfg(feature = "low-power")] | 296 | #[cfg(feature = "low-power")] |
| 281 | /// Pause the timer | 297 | /// Add the given offset to the current time |
| 282 | pub(crate) fn pause_time(&self) { | 298 | fn add_time(&self, offset: embassy_time::Duration) { |
| 283 | T::regs_gp16().cr1().modify(|w| w.set_cen(false)); | ||
| 284 | } | ||
| 285 | |||
| 286 | #[cfg(feature = "low-power")] | ||
| 287 | /// Resume the timer with the given offset | ||
| 288 | pub(crate) fn resume_time(&self, offset: embassy_time::Duration) { | ||
| 289 | let offset = offset.as_ticks(); | 299 | let offset = offset.as_ticks(); |
| 290 | let cnt = T::regs_gp16().cnt().read().cnt() as u32; | 300 | let cnt = T::regs_gp16().cnt().read().cnt() as u32; |
| 291 | let period = self.period.load(Ordering::SeqCst); | 301 | let period = self.period.load(Ordering::SeqCst); |
| @@ -315,6 +325,66 @@ impl RtcDriver { | |||
| 315 | self.period.store(period, Ordering::SeqCst); | 325 | self.period.store(period, Ordering::SeqCst); |
| 316 | T::regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16)); | 326 | T::regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16)); |
| 317 | 327 | ||
| 328 | // Now, recompute all alarms | ||
| 329 | critical_section::with(|cs| { | ||
| 330 | for i in 0..ALARM_COUNT { | ||
| 331 | let alarm_handle = unsafe { AlarmHandle::new(i as u8) }; | ||
| 332 | let alarm = self.get_alarm(cs, alarm_handle); | ||
| 333 | |||
| 334 | self.set_alarm(alarm_handle, alarm.timestamp.get()); | ||
| 335 | } | ||
| 336 | }) | ||
| 337 | } | ||
| 338 | |||
| 339 | #[cfg(feature = "low-power")] | ||
| 340 | /// Stop the wakeup alarm, if enabled, and add the appropriate offset | ||
| 341 | fn stop_wakeup_alarm(&self) { | ||
| 342 | critical_section::with(|cs| { | ||
| 343 | if let Some(stop_time) = self.stop_time.borrow(cs).take() { | ||
| 344 | let current_time = self.rtc.borrow(cs).get().unwrap().stop_wakeup_alarm(); | ||
| 345 | self.add_time(current_time - stop_time); | ||
| 346 | } | ||
| 347 | }); | ||
| 348 | } | ||
| 349 | |||
| 350 | #[cfg(feature = "low-power")] | ||
| 351 | /// Pause the timer if ready; return err if not | ||
| 352 | pub(crate) fn pause_time(&self) -> Result<(), ()> { | ||
| 353 | /* | ||
| 354 | If the wakeup timer is currently running, then we need to stop it and | ||
| 355 | add the elapsed time to the current time | ||
| 356 | */ | ||
| 357 | self.stop_wakeup_alarm(); | ||
| 358 | |||
| 359 | let time_until_next_alarm = self.time_until_next_alarm(); | ||
| 360 | if time_until_next_alarm < embassy_time::Duration::from_millis(250) { | ||
| 361 | Err(()) | ||
| 362 | } else { | ||
| 363 | critical_section::with(|cs| { | ||
| 364 | assert!(self | ||
| 365 | .stop_time | ||
| 366 | .borrow(cs) | ||
| 367 | .replace(Some( | ||
| 368 | self.rtc | ||
| 369 | .borrow(cs) | ||
| 370 | .get() | ||
| 371 | .unwrap() | ||
| 372 | .start_wakeup_alarm(time_until_next_alarm) | ||
| 373 | )) | ||
| 374 | .is_none()); | ||
| 375 | }); | ||
| 376 | |||
| 377 | T::regs_gp16().cr1().modify(|w| w.set_cen(false)); | ||
| 378 | |||
| 379 | Ok(()) | ||
| 380 | } | ||
| 381 | } | ||
| 382 | |||
| 383 | #[cfg(feature = "low-power")] | ||
| 384 | /// Resume the timer with the given offset | ||
| 385 | pub(crate) fn resume_time(&self) { | ||
| 386 | self.stop_wakeup_alarm(); | ||
| 387 | |||
| 318 | T::regs_gp16().cr1().modify(|w| w.set_cen(true)); | 388 | T::regs_gp16().cr1().modify(|w| w.set_cen(true)); |
| 319 | } | 389 | } |
| 320 | } | 390 | } |
| @@ -388,21 +458,8 @@ impl Driver for RtcDriver { | |||
| 388 | } | 458 | } |
| 389 | 459 | ||
| 390 | #[cfg(feature = "low-power")] | 460 | #[cfg(feature = "low-power")] |
| 391 | /// Compute the approximate amount of time until the next alarm | 461 | pub(crate) fn get_driver() -> &'static RtcDriver { |
| 392 | pub(crate) fn time_until_next_alarm() -> embassy_time::Duration { | 462 | &DRIVER |
| 393 | DRIVER.time_until_next_alarm() | ||
| 394 | } | ||
| 395 | |||
| 396 | #[cfg(feature = "low-power")] | ||
| 397 | /// Pause the timer | ||
| 398 | pub(crate) fn pause_time() { | ||
| 399 | DRIVER.pause_time(); | ||
| 400 | } | ||
| 401 | |||
| 402 | #[cfg(feature = "low-power")] | ||
| 403 | /// Resume the timer with the given offset | ||
| 404 | pub(crate) fn resume_time(offset: embassy_time::Duration) { | ||
| 405 | DRIVER.resume_time(offset); | ||
| 406 | } | 463 | } |
| 407 | 464 | ||
| 408 | pub(crate) fn init() { | 465 | pub(crate) fn init() { |
