aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/low_power.rs4
-rw-r--r--embassy-stm32/src/rcc/bd.rs39
-rw-r--r--embassy-stm32/src/rtc/mod.rs60
-rw-r--r--embassy-stm32/src/rtc/v2.rs37
-rw-r--r--tests/stm32/src/bin/stop.rs6
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
7use crate::interrupt; 7use crate::interrupt;
8use crate::interrupt::typelevel::Interrupt; 8use crate::interrupt::typelevel::Interrupt;
9use crate::pac::EXTI;
10use crate::rcc::low_power_ready; 9use crate::rcc::low_power_ready;
11use crate::time_driver::{get_driver, RtcDriver}; 10use 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"))]
51impl RtcInstant { 51impl 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 @@
1use stm32_metapac::rtc::vals::{Init, Osel, Pol}; 1use stm32_metapac::rtc::vals::{Init, Osel, Pol};
2 2
3#[cfg(feature = "low-power")]
4use super::RtcInstant;
5use super::{sealed, RtcConfig}; 3use super::{sealed, RtcConfig};
6use crate::pac::rtc::Rtc; 4use crate::pac::rtc::Rtc;
7use crate::peripherals::RTC; 5use 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();