atsamd_hal/
sleeping_delay.rs
1use core::sync::atomic;
3use cortex_m::asm;
4use fugit::ExtU32;
5
6use crate::ehal::delay::DelayNs;
7use crate::ehal_02;
8use crate::timer_traits::InterruptDrivenTimer;
9
10const NUM_NS_IN_S: u32 = 1_000_000_000;
11
12pub struct SleepingDelay<TIM> {
14 timer: TIM,
15 interrupt_fired: &'static atomic::AtomicBool,
16}
17
18impl<TIM> SleepingDelay<TIM>
19where
20 TIM: InterruptDrivenTimer,
21{
22 pub fn new(timer: TIM, interrupt_fired: &'static atomic::AtomicBool) -> SleepingDelay<TIM>
24 where
25 TIM: InterruptDrivenTimer,
26 {
27 SleepingDelay {
28 timer,
29 interrupt_fired,
30 }
31 }
32
33 pub fn free(self) -> TIM {
35 self.timer
36 }
37}
38
39impl<TIM, TYPE> ehal_02::blocking::delay::DelayUs<TYPE> for SleepingDelay<TIM>
40where
41 TIM: InterruptDrivenTimer,
42 TYPE: Into<u32>,
43{
44 fn delay_us(&mut self, us: TYPE) {
45 <Self as DelayNs>::delay_us(self, us.into());
46 }
47}
48
49impl<TIM, TYPE> ehal_02::blocking::delay::DelayMs<TYPE> for SleepingDelay<TIM>
50where
51 TIM: InterruptDrivenTimer,
52 TYPE: Into<u32>,
53{
54 fn delay_ms(&mut self, ms: TYPE) {
55 <Self as DelayNs>::delay_ms(self, ms.into());
56 }
57}
58
59impl<TIM: InterruptDrivenTimer> DelayNs for SleepingDelay<TIM> {
60 fn delay_ns(&mut self, ns: u32) {
61 let mut loop_counter: u32 = 1 + (ns / NUM_NS_IN_S);
65
66 self.timer.start((ns / loop_counter).nanos());
68 self.timer.enable_interrupt();
69 loop {
70 asm::wfi();
71 if self.timer.wait().is_ok() || self.interrupt_fired.load(atomic::Ordering::Relaxed) {
72 self.interrupt_fired.store(false, atomic::Ordering::Relaxed);
73 loop_counter -= 1;
74 if loop_counter == 0 {
75 break;
76 }
77 }
78 }
79 self.timer.disable_interrupt();
80 }
81}