aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxoviat <[email protected]>2023-09-21 19:32:48 -0500
committerxoviat <[email protected]>2023-09-21 19:32:48 -0500
commit7cf327130e97f2569e1be73054a778ba5bf39d5b (patch)
treec2ab9527d56f0541fa8e7b91cc7b5e001116adce
parent02b05231992af4fec3c92d0cc6ce99ae6508bc41 (diff)
stm32/low-power: create one critical-section for all time ops
-rw-r--r--embassy-stm32/src/rtc/v2.rs46
-rw-r--r--embassy-stm32/src/time_driver.rs104
-rw-r--r--tests/stm32/src/bin/stop.rs33
3 files changed, 101 insertions, 82 deletions
diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs
index aa3c31ee1..d139f2f47 100644
--- a/embassy-stm32/src/rtc/v2.rs
+++ b/embassy-stm32/src/rtc/v2.rs
@@ -64,7 +64,11 @@ impl super::Rtc {
64 #[cfg(feature = "low-power")] 64 #[cfg(feature = "low-power")]
65 /// start the wakeup alarm and wtih a duration that is as close to but less than 65 /// start the wakeup alarm and wtih a duration that is as close to but less than
66 /// the requested duration, and record the instant the wakeup alarm was started 66 /// the requested duration, and record the instant the wakeup alarm was started
67 pub(crate) fn start_wakeup_alarm(&self, requested_duration: embassy_time::Duration) { 67 pub(crate) fn start_wakeup_alarm(
68 &self,
69 requested_duration: embassy_time::Duration,
70 cs: critical_section::CriticalSection,
71 ) {
68 use embassy_time::{Duration, TICK_HZ}; 72 use embassy_time::{Duration, TICK_HZ};
69 73
70 #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] 74 #[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
@@ -102,25 +106,13 @@ impl super::Rtc {
102 self.instant(), 106 self.instant(),
103 ); 107 );
104 108
105 critical_section::with(|cs| assert!(self.stop_time.borrow(cs).replace(Some(self.instant())).is_none())) 109 assert!(self.stop_time.borrow(cs).replace(Some(self.instant())).is_none())
106 }
107
108 #[cfg(feature = "low-power")]
109 pub(crate) fn enable_wakeup_line(&self) {
110 use crate::interrupt::typelevel::Interrupt;
111 use crate::pac::EXTI;
112
113 <RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::unpend();
114 unsafe { <RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::enable() };
115
116 EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
117 EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
118 } 110 }
119 111
120 #[cfg(feature = "low-power")] 112 #[cfg(feature = "low-power")]
121 /// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm` 113 /// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm`
122 /// was called, otherwise none 114 /// was called, otherwise none
123 pub(crate) fn stop_wakeup_alarm(&self) -> Option<embassy_time::Duration> { 115 pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option<embassy_time::Duration> {
124 use crate::interrupt::typelevel::Interrupt; 116 use crate::interrupt::typelevel::Interrupt;
125 117
126 trace!("rtc: stop wakeup alarm at {}", self.instant()); 118 trace!("rtc: stop wakeup alarm at {}", self.instant());
@@ -137,13 +129,23 @@ impl super::Rtc {
137 <RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::unpend(); 129 <RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::unpend();
138 }); 130 });
139 131
140 critical_section::with(|cs| { 132 if let Some(stop_time) = self.stop_time.borrow(cs).take() {
141 if let Some(stop_time) = self.stop_time.borrow(cs).take() { 133 Some(self.instant() - stop_time)
142 Some(self.instant() - stop_time) 134 } else {
143 } else { 135 None
144 None 136 }
145 } 137 }
146 }) 138
139 #[cfg(feature = "low-power")]
140 pub(crate) fn enable_wakeup_line(&self) {
141 use crate::interrupt::typelevel::Interrupt;
142 use crate::pac::EXTI;
143
144 <RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::unpend();
145 unsafe { <RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::enable() };
146
147 EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
148 EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
147 } 149 }
148 150
149 /// Applies the RTC config 151 /// Applies the RTC config
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs
index 887e54f65..5b01937f5 100644
--- a/embassy-stm32/src/time_driver.rs
+++ b/embassy-stm32/src/time_driver.rs
@@ -266,32 +266,28 @@ impl RtcDriver {
266 f(alarm.ctx.get()); 266 f(alarm.ctx.get());
267 } 267 }
268 268
269 #[cfg(feature = "low-power")] 269 /*
270 /// Set the rtc but panic if it's already been set 270 Low-power private functions: all operate within a critical seciton
271 pub(crate) fn set_rtc(&self, rtc: &'static Rtc) { 271 */
272 critical_section::with(|cs| assert!(self.rtc.borrow(cs).replace(Some(rtc)).is_none()));
273 }
274 272
275 #[cfg(feature = "low-power")] 273 #[cfg(feature = "low-power")]
276 /// Compute the approximate amount of time until the next alarm 274 /// Compute the approximate amount of time until the next alarm
277 fn time_until_next_alarm(&self) -> embassy_time::Duration { 275 fn time_until_next_alarm(&self, cs: CriticalSection) -> embassy_time::Duration {
278 critical_section::with(|cs| { 276 let now = self.now() + 32;
279 let now = self.now() + 32; 277
280 278 embassy_time::Duration::from_ticks(
281 embassy_time::Duration::from_ticks( 279 self.alarms
282 self.alarms 280 .borrow(cs)
283 .borrow(cs) 281 .iter()
284 .iter() 282 .map(|alarm: &AlarmState| alarm.timestamp.get().saturating_sub(now))
285 .map(|alarm: &AlarmState| alarm.timestamp.get().saturating_sub(now)) 283 .min()
286 .min() 284 .unwrap_or(u64::MAX),
287 .unwrap_or(u64::MAX), 285 )
288 )
289 })
290 } 286 }
291 287
292 #[cfg(feature = "low-power")] 288 #[cfg(feature = "low-power")]
293 /// Add the given offset to the current time 289 /// Add the given offset to the current time
294 fn add_time(&self, offset: embassy_time::Duration) { 290 fn add_time(&self, offset: embassy_time::Duration, cs: CriticalSection) {
295 let offset = offset.as_ticks(); 291 let offset = offset.as_ticks();
296 let cnt = T::regs_gp16().cnt().read().cnt() as u32; 292 let cnt = T::regs_gp16().cnt().read().cnt() as u32;
297 let period = self.period.load(Ordering::SeqCst); 293 let period = self.period.load(Ordering::SeqCst);
@@ -322,51 +318,57 @@ impl RtcDriver {
322 T::regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16)); 318 T::regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16));
323 319
324 // Now, recompute all alarms 320 // Now, recompute all alarms
325 critical_section::with(|cs| { 321 for i in 0..ALARM_COUNT {
326 for i in 0..ALARM_COUNT { 322 let alarm_handle = unsafe { AlarmHandle::new(i as u8) };
327 let alarm_handle = unsafe { AlarmHandle::new(i as u8) }; 323 let alarm = self.get_alarm(cs, alarm_handle);
328 let alarm = self.get_alarm(cs, alarm_handle);
329 324
330 self.set_alarm(alarm_handle, alarm.timestamp.get()); 325 self.set_alarm(alarm_handle, alarm.timestamp.get());
331 } 326 }
332 })
333 } 327 }
334 328
335 #[cfg(feature = "low-power")] 329 #[cfg(feature = "low-power")]
336 /// Stop the wakeup alarm, if enabled, and add the appropriate offset 330 /// Stop the wakeup alarm, if enabled, and add the appropriate offset
337 fn stop_wakeup_alarm(&self) { 331 fn stop_wakeup_alarm(&self, cs: CriticalSection) {
338 critical_section::with(|cs| { 332 if let Some(offset) = self.rtc.borrow(cs).get().unwrap().stop_wakeup_alarm(cs) {
339 if let Some(offset) = self.rtc.borrow(cs).get().unwrap().stop_wakeup_alarm() { 333 self.add_time(offset, cs);
340 self.add_time(offset); 334 }
341 } 335 }
342 }); 336
337 /*
338 Low-power public functions: all create a critical section
339 */
340 #[cfg(feature = "low-power")]
341 /// Set the rtc but panic if it's already been set
342 pub(crate) fn set_rtc(&self, rtc: &'static Rtc) {
343 critical_section::with(|cs| assert!(self.rtc.borrow(cs).replace(Some(rtc)).is_none()));
343 } 344 }
344 345
345 #[cfg(feature = "low-power")] 346 #[cfg(feature = "low-power")]
346 /// Pause the timer if ready; return err if not 347 /// Pause the timer if ready; return err if not
347 pub(crate) fn pause_time(&self) -> Result<(), ()> { 348 pub(crate) fn pause_time(&self) -> Result<(), ()> {
348 /* 349 critical_section::with(|cs| {
349 If the wakeup timer is currently running, then we need to stop it and 350 /*
350 add the elapsed time to the current time 351 If the wakeup timer is currently running, then we need to stop it and
351 */ 352 add the elapsed time to the current time, as this will impact the result
352 self.stop_wakeup_alarm(); 353 of `time_until_next_alarm`.
353 354 */
354 let time_until_next_alarm = self.time_until_next_alarm(); 355 self.stop_wakeup_alarm(cs);
355 if time_until_next_alarm < embassy_time::Duration::from_millis(250) { 356
356 Err(()) 357 let time_until_next_alarm = self.time_until_next_alarm(cs);
357 } else { 358 if time_until_next_alarm < embassy_time::Duration::from_millis(250) {
358 critical_section::with(|cs| { 359 Err(())
360 } else {
359 self.rtc 361 self.rtc
360 .borrow(cs) 362 .borrow(cs)
361 .get() 363 .get()
362 .unwrap() 364 .unwrap()
363 .start_wakeup_alarm(time_until_next_alarm); 365 .start_wakeup_alarm(time_until_next_alarm, cs);
364 });
365 366
366 T::regs_gp16().cr1().modify(|w| w.set_cen(false)); 367 T::regs_gp16().cr1().modify(|w| w.set_cen(false));
367 368
368 Ok(()) 369 Ok(())
369 } 370 }
371 })
370 } 372 }
371 373
372 #[cfg(feature = "low-power")] 374 #[cfg(feature = "low-power")]
@@ -378,9 +380,11 @@ impl RtcDriver {
378 return; 380 return;
379 } 381 }
380 382
381 self.stop_wakeup_alarm(); 383 critical_section::with(|cs| {
384 self.stop_wakeup_alarm(cs);
382 385
383 T::regs_gp16().cr1().modify(|w| w.set_cen(true)); 386 T::regs_gp16().cr1().modify(|w| w.set_cen(true));
387 })
384 } 388 }
385} 389}
386 390
diff --git a/tests/stm32/src/bin/stop.rs b/tests/stm32/src/bin/stop.rs
index f60ab271a..48d59b794 100644
--- a/tests/stm32/src/bin/stop.rs
+++ b/tests/stm32/src/bin/stop.rs
@@ -19,14 +19,32 @@ use static_cell::make_static;
19 19
20#[entry] 20#[entry]
21fn main() -> ! { 21fn main() -> ! {
22 let executor = Executor::take(); 22 Executor::take().run(|spawner| {
23 executor.run(|spawner| {
24 unwrap!(spawner.spawn(async_main(spawner))); 23 unwrap!(spawner.spawn(async_main(spawner)));
25 }); 24 });
26} 25}
27 26
28#[embassy_executor::task] 27#[embassy_executor::task]
29async fn async_main(_spawner: Spawner) { 28async fn task_1() {
29 for _ in 0..9 {
30 info!("task 1: waiting for 500ms...");
31 Timer::after(Duration::from_millis(500)).await;
32 }
33}
34
35#[embassy_executor::task]
36async fn task_2() {
37 for _ in 0..5 {
38 info!("task 2: waiting for 1000ms...");
39 Timer::after(Duration::from_millis(1000)).await;
40 }
41
42 info!("Test OK");
43 cortex_m::asm::bkpt();
44}
45
46#[embassy_executor::task]
47async fn async_main(spawner: Spawner) {
30 let mut config = config(); 48 let mut config = config();
31 49
32 config.rcc.lse = Some(Hertz(32_768)); 50 config.rcc.lse = Some(Hertz(32_768));
@@ -48,11 +66,6 @@ async fn async_main(_spawner: Spawner) {
48 66
49 stop_with_rtc(rtc); 67 stop_with_rtc(rtc);
50 68
51 info!("Waiting..."); 69 spawner.spawn(task_1()).unwrap();
52 Timer::after(Duration::from_secs(2)).await; 70 spawner.spawn(task_2()).unwrap();
53 info!("Waiting...");
54 Timer::after(Duration::from_secs(3)).await;
55
56 info!("Test OK");
57 cortex_m::asm::bkpt();
58} 71}