atsamd_hal/
delay.rs

1//! Delays
2
3use atsamd_hal_macros::hal_cfg;
4use cortex_m::peripheral::syst::SystClkSource;
5use cortex_m::peripheral::SYST;
6
7use crate::clock::GenericClockController;
8use crate::ehal::delay::DelayNs;
9use crate::ehal_02;
10use crate::time::Hertz;
11
12#[hal_cfg("rtc-d5x")]
13use crate::typelevel::Increment;
14
15#[hal_cfg("rtc-d5x")]
16use crate::clock::v2::{gclk::Gclk0Id, Source};
17
18/// System timer (SysTick) as a delay provider
19pub struct Delay {
20    sysclock: Hertz,
21    syst: SYST,
22}
23
24impl Delay {
25    /// Configures the system timer (SysTick) as a delay provider
26    pub fn new(mut syst: SYST, clocks: &mut GenericClockController) -> Self {
27        syst.set_clock_source(SystClkSource::Core);
28
29        Delay {
30            syst,
31            sysclock: clocks.gclk0().into(),
32        }
33    }
34
35    #[hal_cfg("rtc-d5x")]
36    /// Configures the system timer (SysTick) as a delay provide, compatible
37    /// with the V2 clocking API
38    pub fn new_with_source<S>(mut syst: SYST, gclk0: S) -> (Self, S::Inc)
39    where
40        S: Source<Id = Gclk0Id> + Increment,
41    {
42        syst.set_clock_source(SystClkSource::Core);
43        (
44            Delay {
45                syst,
46                sysclock: gclk0.freq(),
47            },
48            gclk0.inc(),
49        )
50    }
51
52    /// Releases the system timer (SysTick) resource
53    pub fn free(self) -> SYST {
54        self.syst
55    }
56}
57
58impl DelayNs for Delay {
59    // The default method is delay_ns. If we don't provide implementations for
60    // delay_us and delay_ms, the trait impl will use delay_ns to implement the
61    // other two methods. As the delay implementation is actually defined in terms
62    // of microseconds, we need to provide implementations for all three methods.
63    fn delay_ns(&mut self, ns: u32) {
64        self.delay_us(ns / 1000);
65    }
66
67    fn delay_us(&mut self, us: u32) {
68        // The SysTick Reload Value register supports values between 1 and 0x00FFFFFF.
69        const MAX_RVR: u32 = 0x00FF_FFFF;
70
71        let mut total_rvr = us * (self.sysclock.to_Hz() / 1_000_000);
72
73        while total_rvr != 0 {
74            let current_rvr = if total_rvr <= MAX_RVR {
75                total_rvr
76            } else {
77                MAX_RVR
78            };
79
80            self.syst.set_reload(current_rvr);
81            self.syst.clear_current();
82            self.syst.enable_counter();
83
84            // Update the tracking variable while we are waiting...
85            total_rvr -= current_rvr;
86
87            while !self.syst.has_wrapped() {}
88
89            self.syst.disable_counter();
90        }
91    }
92
93    fn delay_ms(&mut self, ms: u32) {
94        self.delay_us(ms * 1000);
95    }
96}
97
98impl ehal_02::blocking::delay::DelayMs<u32> for Delay {
99    fn delay_ms(&mut self, ms: u32) {
100        <Self as DelayNs>::delay_us(self, ms * 1_000);
101    }
102}
103
104impl ehal_02::blocking::delay::DelayMs<u16> for Delay {
105    fn delay_ms(&mut self, ms: u16) {
106        <Self as ehal_02::blocking::delay::DelayMs<u32>>::delay_ms(self, ms as u32);
107    }
108}
109
110impl ehal_02::blocking::delay::DelayMs<u8> for Delay {
111    fn delay_ms(&mut self, ms: u8) {
112        <Self as ehal_02::blocking::delay::DelayMs<u32>>::delay_ms(self, ms as u32);
113    }
114}
115
116impl ehal_02::blocking::delay::DelayUs<u32> for Delay {
117    fn delay_us(&mut self, us: u32) {
118        <Self as DelayNs>::delay_us(self, us);
119    }
120}
121
122impl ehal_02::blocking::delay::DelayUs<u16> for Delay {
123    fn delay_us(&mut self, us: u16) {
124        <Self as ehal_02::blocking::delay::DelayUs<u32>>::delay_us(self, us as u32);
125    }
126}
127
128impl ehal_02::blocking::delay::DelayUs<u8> for Delay {
129    fn delay_us(&mut self, us: u8) {
130        <Self as ehal_02::blocking::delay::DelayUs<u32>>::delay_us(self, us as u32);
131    }
132}