atsamd_hal/
sleeping_delay.rs1use 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}