diff options
| -rw-r--r-- | embassy-stm32/src/low_power.rs | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/bd.rs | 39 | ||||
| -rw-r--r-- | embassy-stm32/src/rtc/mod.rs | 60 | ||||
| -rw-r--r-- | embassy-stm32/src/rtc/v2.rs | 37 | ||||
| -rw-r--r-- | tests/stm32/src/bin/stop.rs | 6 |
5 files changed, 64 insertions, 82 deletions
diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 65b93f8a4..7e678d323 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs | |||
| @@ -6,7 +6,6 @@ use embassy_executor::*; | |||
| 6 | 6 | ||
| 7 | use crate::interrupt; | 7 | use crate::interrupt; |
| 8 | use crate::interrupt::typelevel::Interrupt; | 8 | use crate::interrupt::typelevel::Interrupt; |
| 9 | use crate::pac::EXTI; | ||
| 10 | use crate::rcc::low_power_ready; | 9 | use crate::rcc::low_power_ready; |
| 11 | use crate::time_driver::{get_driver, RtcDriver}; | 10 | use crate::time_driver::{get_driver, RtcDriver}; |
| 12 | 11 | ||
| @@ -99,8 +98,7 @@ impl Executor { | |||
| 99 | crate::interrupt::typelevel::RTC_WKUP::unpend(); | 98 | crate::interrupt::typelevel::RTC_WKUP::unpend(); |
| 100 | unsafe { crate::interrupt::typelevel::RTC_WKUP::enable() }; | 99 | unsafe { crate::interrupt::typelevel::RTC_WKUP::enable() }; |
| 101 | 100 | ||
| 102 | EXTI.rtsr(0).modify(|w| w.set_line(22, true)); | 101 | rtc.enable_wakeup_line(); |
| 103 | EXTI.imr(0).modify(|w| w.set_line(22, true)); | ||
| 104 | } | 102 | } |
| 105 | 103 | ||
| 106 | fn configure_pwr(&mut self) { | 104 | fn configure_pwr(&mut self) { |
diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index 0fc116ed8..4d8ed82aa 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs | |||
| @@ -87,13 +87,14 @@ impl BackupDomain { | |||
| 87 | } | 87 | } |
| 88 | 88 | ||
| 89 | #[cfg(any( | 89 | #[cfg(any( |
| 90 | rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb | 90 | rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, |
| 91 | rtc_v3u5 | ||
| 91 | ))] | 92 | ))] |
| 92 | #[allow(dead_code)] | 93 | #[allow(dead_code)] |
| 93 | pub fn enable_rtc() { | 94 | pub fn enable_rtc() { |
| 94 | let reg = Self::read(); | 95 | let reg = Self::read(); |
| 95 | 96 | ||
| 96 | #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb))] | 97 | #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] |
| 97 | assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); | 98 | assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); |
| 98 | 99 | ||
| 99 | if !reg.rtcen() { | 100 | if !reg.rtcen() { |
| @@ -102,47 +103,21 @@ impl BackupDomain { | |||
| 102 | 103 | ||
| 103 | Self::modify(|w| { | 104 | Self::modify(|w| { |
| 104 | // Reset | 105 | // Reset |
| 105 | #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] | 106 | #[cfg(not(any(rtc_v2l0, rtc_v2l1, rtc_v2f2)))] |
| 106 | w.set_bdrst(false); | 107 | w.set_bdrst(false); |
| 107 | 108 | ||
| 108 | w.set_rtcen(true); | 109 | w.set_rtcen(true); |
| 109 | w.set_rtcsel(reg.rtcsel()); | 110 | w.set_rtcsel(reg.rtcsel()); |
| 110 | 111 | ||
| 111 | // Restore bcdr | 112 | // Restore bcdr |
| 112 | #[cfg(any(rtc_v2l4, rtc_v2wb))] | 113 | #[cfg(any(rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] |
| 113 | w.set_lscosel(reg.lscosel()); | 114 | w.set_lscosel(reg.lscosel()); |
| 114 | #[cfg(any(rtc_v2l4, rtc_v2wb))] | 115 | #[cfg(any(rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] |
| 115 | w.set_lscoen(reg.lscoen()); | 116 | w.set_lscoen(reg.lscoen()); |
| 116 | 117 | ||
| 117 | w.set_lseon(reg.lseon()); | 118 | w.set_lseon(reg.lseon()); |
| 118 | 119 | ||
| 119 | #[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))] | 120 | #[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] |
| 120 | w.set_lsedrv(reg.lsedrv()); | ||
| 121 | w.set_lsebyp(reg.lsebyp()); | ||
| 122 | }); | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 | #[cfg(any(rtc_v3, rtc_v3u5))] | ||
| 127 | #[allow(dead_code)] | ||
| 128 | pub fn enable_rtc() { | ||
| 129 | let reg = Self::read(); | ||
| 130 | assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); | ||
| 131 | |||
| 132 | if !reg.rtcen() { | ||
| 133 | Self::modify(|w| w.set_bdrst(true)); | ||
| 134 | |||
| 135 | Self::modify(|w| { | ||
| 136 | w.set_bdrst(false); | ||
| 137 | |||
| 138 | w.set_rtcen(true); | ||
| 139 | w.set_rtcsel(reg.rtcsel()); | ||
| 140 | |||
| 141 | // Restore bcdr | ||
| 142 | w.set_lscosel(reg.lscosel()); | ||
| 143 | w.set_lscoen(reg.lscoen()); | ||
| 144 | |||
| 145 | w.set_lseon(reg.lseon()); | ||
| 146 | w.set_lsedrv(reg.lsedrv()); | 121 | w.set_lsedrv(reg.lsedrv()); |
| 147 | w.set_lsebyp(reg.lsebyp()); | 122 | w.set_lsebyp(reg.lsebyp()); |
| 148 | }); | 123 | }); |
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index c408b2d61..796fd7d96 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs | |||
| @@ -47,28 +47,15 @@ struct RtcInstant { | |||
| 47 | subsecond: u16, | 47 | subsecond: u16, |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | #[cfg(feature = "low-power")] | 50 | #[cfg(all(feature = "low-power", feature = "defmt"))] |
| 51 | impl RtcInstant { | 51 | impl defmt::Format for RtcInstant { |
| 52 | pub fn now() -> Self { | 52 | fn format(&self, fmt: defmt::Formatter) { |
| 53 | let tr = RTC::regs().tr().read(); | 53 | defmt::write!( |
| 54 | let tr2 = RTC::regs().tr().read(); | 54 | fmt, |
| 55 | let ssr = RTC::regs().ssr().read().ss(); | 55 | "{}:{}", |
| 56 | let ssr2 = RTC::regs().ssr().read().ss(); | 56 | self.second, |
| 57 | 57 | RTC::regs().prer().read().prediv_s() - self.subsecond, | |
| 58 | let st = bcd2_to_byte((tr.st(), tr.su())); | 58 | ) |
| 59 | let st2 = bcd2_to_byte((tr2.st(), tr2.su())); | ||
| 60 | |||
| 61 | assert!(st == st2); | ||
| 62 | assert!(ssr == ssr2); | ||
| 63 | |||
| 64 | let _ = RTC::regs().dr().read(); | ||
| 65 | |||
| 66 | let subsecond = ssr; | ||
| 67 | let second = st; | ||
| 68 | |||
| 69 | // trace!("rtc: instant now: st, ssr: {}, {}", st, ssr); | ||
| 70 | |||
| 71 | Self { second, subsecond } | ||
| 72 | } | 59 | } |
| 73 | } | 60 | } |
| 74 | 61 | ||
| @@ -85,20 +72,13 @@ impl core::ops::Sub for RtcInstant { | |||
| 85 | self.second | 72 | self.second |
| 86 | }; | 73 | }; |
| 87 | 74 | ||
| 88 | // TODO: read prescaler | 75 | let psc = RTC::regs().prer().read().prediv_s() as u32; |
| 89 | 76 | ||
| 90 | let self_ticks = second as u32 * 256 + (255 - self.subsecond as u32); | 77 | let self_ticks = second as u32 * (psc + 1) + (psc - self.subsecond as u32); |
| 91 | let other_ticks = rhs.second as u32 * 256 + (255 - rhs.subsecond as u32); | 78 | let other_ticks = rhs.second as u32 * (psc + 1) + (psc - rhs.subsecond as u32); |
| 92 | let rtc_ticks = self_ticks - other_ticks; | 79 | let rtc_ticks = self_ticks - other_ticks; |
| 93 | 80 | ||
| 94 | // trace!( | 81 | Duration::from_ticks(((rtc_ticks * TICK_HZ as u32) / (psc + 1)) as u64) |
| 95 | // "rtc: instant sub: self, other, rtc ticks: {}, {}, {}", | ||
| 96 | // self_ticks, | ||
| 97 | // other_ticks, | ||
| 98 | // rtc_ticks | ||
| 99 | // ); | ||
| 100 | |||
| 101 | Duration::from_ticks(((rtc_ticks * TICK_HZ as u32) / 256u32) as u64) | ||
| 102 | } | 82 | } |
| 103 | } | 83 | } |
| 104 | 84 | ||
| @@ -198,6 +178,20 @@ impl Rtc { | |||
| 198 | Ok(()) | 178 | Ok(()) |
| 199 | } | 179 | } |
| 200 | 180 | ||
| 181 | #[cfg(feature = "low-power")] | ||
| 182 | /// Return the current instant. | ||
| 183 | fn instant(&self) -> RtcInstant { | ||
| 184 | let r = RTC::regs(); | ||
| 185 | let tr = r.tr().read(); | ||
| 186 | let subsecond = r.ssr().read().ss(); | ||
| 187 | let second = bcd2_to_byte((tr.st(), tr.su())); | ||
| 188 | |||
| 189 | // Unlock the registers | ||
| 190 | r.dr().read(); | ||
| 191 | |||
| 192 | RtcInstant { second, subsecond } | ||
| 193 | } | ||
| 194 | |||
| 201 | /// Return the current datetime. | 195 | /// Return the current datetime. |
| 202 | /// | 196 | /// |
| 203 | /// # Errors | 197 | /// # Errors |
diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 1e0ca9b48..49f66e957 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs | |||
| @@ -1,7 +1,5 @@ | |||
| 1 | use stm32_metapac::rtc::vals::{Init, Osel, Pol}; | 1 | use stm32_metapac::rtc::vals::{Init, Osel, Pol}; |
| 2 | 2 | ||
| 3 | #[cfg(feature = "low-power")] | ||
| 4 | use super::RtcInstant; | ||
| 5 | use super::{sealed, RtcConfig}; | 3 | use super::{sealed, RtcConfig}; |
| 6 | use crate::pac::rtc::Rtc; | 4 | use crate::pac::rtc::Rtc; |
| 7 | use crate::peripherals::RTC; | 5 | use crate::peripherals::RTC; |
| @@ -86,17 +84,14 @@ impl super::Rtc { | |||
| 86 | let rtc_ticks = requested_duration.as_ticks() * rtc_hz / TICK_HZ; | 84 | let rtc_ticks = requested_duration.as_ticks() * rtc_hz / TICK_HZ; |
| 87 | let prescaler = WakeupPrescaler::compute_min((rtc_ticks / u16::MAX as u64) as u32); | 85 | let prescaler = WakeupPrescaler::compute_min((rtc_ticks / u16::MAX as u64) as u32); |
| 88 | 86 | ||
| 89 | // adjust the rtc ticks to the prescaler | 87 | // adjust the rtc ticks to the prescaler and subtract one rtc tick |
| 90 | let rtc_ticks = rtc_ticks / (<WakeupPrescaler as Into<u32>>::into(prescaler) as u64); | 88 | let rtc_ticks = rtc_ticks / (<WakeupPrescaler as Into<u32>>::into(prescaler) as u64); |
| 91 | let rtc_ticks = if rtc_ticks >= u16::MAX as u64 { | 89 | let rtc_ticks = if rtc_ticks >= u16::MAX as u64 { |
| 92 | u16::MAX - 1 | 90 | u16::MAX - 1 |
| 93 | } else { | 91 | } else { |
| 94 | rtc_ticks as u16 | 92 | rtc_ticks as u16 |
| 95 | }; | 93 | } |
| 96 | 94 | .saturating_sub(1); | |
| 97 | let duration = Duration::from_ticks( | ||
| 98 | rtc_ticks as u64 * TICK_HZ * (<WakeupPrescaler as Into<u32>>::into(prescaler) as u64) / rtc_hz, | ||
| 99 | ); | ||
| 100 | 95 | ||
| 101 | self.write(false, |regs| { | 96 | self.write(false, |regs| { |
| 102 | regs.cr().modify(|w| w.set_wute(false)); | 97 | regs.cr().modify(|w| w.set_wute(false)); |
| @@ -104,13 +99,31 @@ impl super::Rtc { | |||
| 104 | while !regs.isr().read().wutwf() {} | 99 | while !regs.isr().read().wutwf() {} |
| 105 | 100 | ||
| 106 | regs.cr().modify(|w| w.set_wucksel(prescaler.into())); | 101 | regs.cr().modify(|w| w.set_wucksel(prescaler.into())); |
| 102 | regs.wutr().write(|w| w.set_wut(rtc_ticks)); | ||
| 107 | regs.cr().modify(|w| w.set_wute(true)); | 103 | regs.cr().modify(|w| w.set_wute(true)); |
| 108 | regs.cr().modify(|w| w.set_wutie(true)); | 104 | regs.cr().modify(|w| w.set_wutie(true)); |
| 109 | }); | 105 | }); |
| 110 | 106 | ||
| 111 | trace!("rtc: start wakeup alarm for {} ms", duration.as_millis()); | 107 | trace!( |
| 108 | "rtc: start wakeup alarm for {} ms (psc: {}, ticks: {}) at {}", | ||
| 109 | Duration::from_ticks( | ||
| 110 | rtc_ticks as u64 * TICK_HZ * (<WakeupPrescaler as Into<u32>>::into(prescaler) as u64) / rtc_hz, | ||
| 111 | ) | ||
| 112 | .as_millis(), | ||
| 113 | <WakeupPrescaler as Into<u32>>::into(prescaler), | ||
| 114 | rtc_ticks, | ||
| 115 | self.instant(), | ||
| 116 | ); | ||
| 117 | |||
| 118 | critical_section::with(|cs| assert!(self.stop_time.borrow(cs).replace(Some(self.instant())).is_none())) | ||
| 119 | } | ||
| 120 | |||
| 121 | #[cfg(feature = "low-power")] | ||
| 122 | pub(crate) fn enable_wakeup_line(&self) { | ||
| 123 | use crate::pac::EXTI; | ||
| 112 | 124 | ||
| 113 | critical_section::with(|cs| assert!(self.stop_time.borrow(cs).replace(Some(RtcInstant::now())).is_none())) | 125 | EXTI.rtsr(0).modify(|w| w.set_line(22, true)); |
| 126 | EXTI.imr(0).modify(|w| w.set_line(22, true)); | ||
| 114 | } | 127 | } |
| 115 | 128 | ||
| 116 | #[cfg(feature = "low-power")] | 129 | #[cfg(feature = "low-power")] |
| @@ -119,7 +132,7 @@ impl super::Rtc { | |||
| 119 | pub(crate) fn stop_wakeup_alarm(&self) -> Option<embassy_time::Duration> { | 132 | pub(crate) fn stop_wakeup_alarm(&self) -> Option<embassy_time::Duration> { |
| 120 | use crate::interrupt::typelevel::Interrupt; | 133 | use crate::interrupt::typelevel::Interrupt; |
| 121 | 134 | ||
| 122 | trace!("rtc: stop wakeup alarm..."); | 135 | trace!("rtc: stop wakeup alarm at {}", self.instant()); |
| 123 | 136 | ||
| 124 | self.write(false, |regs| { | 137 | self.write(false, |regs| { |
| 125 | regs.cr().modify(|w| w.set_wutie(false)); | 138 | regs.cr().modify(|w| w.set_wutie(false)); |
| @@ -132,7 +145,7 @@ impl super::Rtc { | |||
| 132 | 145 | ||
| 133 | critical_section::with(|cs| { | 146 | critical_section::with(|cs| { |
| 134 | if let Some(stop_time) = self.stop_time.borrow(cs).take() { | 147 | if let Some(stop_time) = self.stop_time.borrow(cs).take() { |
| 135 | Some(RtcInstant::now() - stop_time) | 148 | Some(self.instant() - stop_time) |
| 136 | } else { | 149 | } else { |
| 137 | None | 150 | None |
| 138 | } | 151 | } |
diff --git a/tests/stm32/src/bin/stop.rs b/tests/stm32/src/bin/stop.rs index 0b3f4a300..a490d7b8c 100644 --- a/tests/stm32/src/bin/stop.rs +++ b/tests/stm32/src/bin/stop.rs | |||
| @@ -46,8 +46,10 @@ async fn async_main(_spawner: Spawner) { | |||
| 46 | 46 | ||
| 47 | stop_with_rtc(rtc); | 47 | stop_with_rtc(rtc); |
| 48 | 48 | ||
| 49 | info!("Waiting 5 seconds"); | 49 | info!("Waiting..."); |
| 50 | Timer::after(Duration::from_secs(5)).await; | 50 | Timer::after(Duration::from_secs(2)).await; |
| 51 | info!("Waiting..."); | ||
| 52 | Timer::after(Duration::from_secs(3)).await; | ||
| 51 | 53 | ||
| 52 | info!("Test OK"); | 54 | info!("Test OK"); |
| 53 | cortex_m::asm::bkpt(); | 55 | cortex_m::asm::bkpt(); |
