atsamd_hal/peripherals/timer/
common.rs

1//! Common items for timer hardware for all chips.
2use core::convert::Infallible;
3use fugit::NanosDurationU32;
4
5use crate::ehal::delay::DelayNs;
6use crate::ehal_02::timer::{CountDown, Periodic};
7use crate::time::Nanoseconds;
8use crate::timer_params::TimerParams;
9use crate::timer_traits::InterruptDrivenTimer;
10
11use super::{Count16Reg, TimerCounter};
12
13/// This is a helper trait to make it easier to make most of the
14/// TimerCounter impl generic.  It doesn't make too much sense to
15/// to try to implement this trait outside of this module.
16pub trait Count16 {
17    fn count_16(&self) -> &Count16Reg;
18}
19
20impl<TC> InterruptDrivenTimer for TimerCounter<TC>
21where
22    TC: Count16,
23{
24    /// Enable the interrupt generation for this hardware timer.
25    /// This method only sets the clock configuration to trigger
26    /// the interrupt; it does not configure the interrupt controller
27    /// or define an interrupt handler.
28    fn enable_interrupt(&mut self) {
29        self.tc.count_16().intenset().write(|w| w.ovf().set_bit());
30    }
31
32    /// Starts the countdown of the timer.
33    ///
34    /// You should call [Self::enable_interrupt] after calling start
35    /// in order to enable the interrupt generation
36    fn start<T>(&mut self, timeout: T)
37    where
38        T: Into<NanosDurationU32>,
39    {
40        let params = TimerParams::new_ns(timeout.into(), self.freq);
41        self.start_timer(params.divider, params.check_cycles_u16());
42    }
43
44    fn wait(&mut self) -> nb::Result<(), Infallible> {
45        let count = self.tc.count_16();
46        if count.intflag().read().ovf().bit_is_set() {
47            // Writing a 1 clears the flag
48            count.intflag().modify(|_, w| w.ovf().set_bit());
49            Ok(())
50        } else {
51            Err(nb::Error::WouldBlock)
52        }
53    }
54
55    /// Disables interrupt generation for this hardware timer.
56    /// This method only sets the clock configuration to prevent
57    /// triggering the interrupt; it does not configure the interrupt
58    /// controller.
59    fn disable_interrupt(&mut self) {
60        self.tc.count_16().intenclr().write(|w| w.ovf().set_bit());
61    }
62}
63
64impl<TC> Periodic for TimerCounter<TC> {}
65impl<TC> CountDown for TimerCounter<TC>
66where
67    TC: Count16,
68{
69    type Time = Nanoseconds;
70
71    fn start<T>(&mut self, timeout: T)
72    where
73        T: Into<Self::Time>,
74    {
75        <Self as InterruptDrivenTimer>::start(self, timeout);
76    }
77
78    fn wait(&mut self) -> nb::Result<(), void::Void> {
79        nb::block! {
80            <Self as InterruptDrivenTimer>::wait(self)
81        }
82        .unwrap(); // wait() is Infallible
83        Ok(())
84    }
85}
86
87impl<TC> DelayNs for TimerCounter<TC>
88where
89    TC: Count16,
90{
91    fn delay_ns(&mut self, ns: u32) {
92        let ticks: u32 = (ns as u64 * self.freq.to_Hz() as u64 / 1_000_000_000_u64) as u32;
93        let params = TimerParams::new_from_ticks(ticks);
94
95        // The timer is is only 16 bits, so we may need to run it multiple times.
96        let mut cycles = params.cycles;
97        if cycles > u16::MAX as u32 {
98            self.start_timer(params.divider, u16::MAX);
99            while cycles > u16::MAX as u32 {
100                let _ = nb::block!(InterruptDrivenTimer::wait(self));
101                cycles -= u16::MAX as u32;
102            }
103        }
104
105        // Wait more if there are any leftover cycles
106        if cycles > 0 {
107            self.start_timer(params.divider, cycles as u16);
108            let _ = nb::block!(InterruptDrivenTimer::wait(self));
109        }
110
111        self.disable();
112    }
113}