atsamd_hal/peripherals/timer/
d5x.rs

1//! Working with timer counter hardware
2use atsamd_hal_macros::hal_cfg;
3
4use crate::pac::tc0::Count16 as Count16Reg;
5use crate::pac::{Mclk, Tc2, Tc3};
6#[hal_cfg(all("tc4", "tc5"))]
7use crate::pac::{Tc4, Tc5};
8#[hal_cfg(all("tc6", "tc7"))]
9use crate::pac::{Tc6, Tc7};
10
11use crate::clock;
12use crate::time::Hertz;
13
14mod common;
15pub use common::Count16;
16
17#[cfg(feature = "async")]
18mod async_api;
19
20#[cfg(feature = "async")]
21pub use async_api::*;
22
23// Note:
24// TC3 + TC4 can be paired to make a 32-bit counter
25// TC5 + TC6 can be paired to make a 32-bit counter
26
27/// A generic hardware timer counter.
28///
29/// The counters are exposed in 16-bit mode only.
30/// The hardware allows configuring the 8-bit mode
31/// and pairing up some instances to run in 32-bit
32/// mode, but that functionality is not currently
33/// exposed by this hal implementation.
34/// TimerCounter implements both the `Periodic` and
35/// the `CountDown` embedded_hal timer traits.
36/// Before a hardware timer can be used, it must first
37/// have a clock configured.
38pub struct TimerCounter<TC> {
39    freq: Hertz,
40    tc: TC,
41}
42impl<TC> TimerCounter<TC>
43where
44    TC: Count16,
45{
46    /// Starts the 16-bit timer, counting up in periodic mode.
47    fn start_timer(&mut self, divider: u16, cycles: u16) {
48        // Disable the timer while we reconfigure it
49        self.disable();
50
51        let count = self.tc.count_16();
52
53        // Now that we have a clock routed to the peripheral, we
54        // can ask it to perform a reset.
55        count.ctrla().write(|w| w.swrst().set_bit());
56        while count.syncbusy().read().swrst().bit_is_set() {}
57
58        count.ctrlbset().write(|w| {
59            // Count up when the direction bit is zero
60            w.dir().clear_bit();
61            // Periodic
62            w.oneshot().clear_bit()
63        });
64
65        // Set TOP value for mfrq mode
66        count.cc(0).write(|w| unsafe { w.cc().bits(cycles) });
67
68        // Enable Match Frequency Waveform generation
69        count.wave().modify(|_, w| w.wavegen().mfrq());
70
71        count.ctrla().modify(|_, w| {
72            match divider {
73                1 => w.prescaler().div1(),
74                2 => w.prescaler().div2(),
75                4 => w.prescaler().div4(),
76                8 => w.prescaler().div8(),
77                16 => w.prescaler().div16(),
78                64 => w.prescaler().div64(),
79                256 => w.prescaler().div256(),
80                1024 => w.prescaler().div1024(),
81                _ => unreachable!(),
82            };
83            w.enable().set_bit();
84            w.runstdby().set_bit()
85        });
86    }
87
88    /// Disable the timer
89    fn disable(&mut self) {
90        let count = self.tc.count_16();
91
92        count.ctrla().modify(|_, w| w.enable().clear_bit());
93        while count.syncbusy().read().enable().bit_is_set() {}
94    }
95}
96
97macro_rules! tc {
98    ($($TYPE:ident: ($TC:ident, $mclk:ident, $clock:ident, $apmask:ident),)+) => {
99        $(
100pub type $TYPE = TimerCounter<$TC>;
101
102impl Count16 for $TC {
103    fn count_16(&self) -> &Count16Reg {
104        self.count16()
105    }
106}
107
108impl TimerCounter<$TC>
109{
110    /// Configure this timer counter instance.
111    /// The clock is obtained from the `GenericClockController` instance
112    /// and its frequency impacts the resolution and maximum range of
113    /// the timeout values that can be passed to the `start` method.
114    /// Note that some hardware timer instances share the same clock
115    /// generator instance and thus will be clocked at the same rate.
116    pub fn $mclk(clock: &clock::$clock, tc: $TC, mclk: &mut Mclk) -> Self {
117        // this is safe because we're constrained to just the tc3 bit
118        mclk.$apmask().modify(|_, w| w.$mclk().set_bit());
119        {
120            let count = tc.count16();
121
122            // Disable the timer while we reconfigure it
123            count.ctrla().modify(|_, w| w.enable().clear_bit());
124            while count.syncbusy().read().enable().bit_is_set()  {}
125        }
126        Self {
127            freq: clock.freq(),
128            tc,
129        }
130    }
131}
132        )+
133    }
134}
135
136tc! {
137    TimerCounter2: (Tc2, tc2_, Tc2Tc3Clock, apbbmask),
138    TimerCounter3: (Tc3, tc3_, Tc2Tc3Clock, apbbmask),
139}
140
141#[hal_cfg(all("tc4", "tc5"))]
142tc! {
143    TimerCounter4: (Tc4, tc4_, Tc4Tc5Clock, apbcmask),
144    TimerCounter5: (Tc5, tc5_, Tc4Tc5Clock, apbcmask),
145}
146
147#[hal_cfg(all("tc6", "tc7"))]
148tc! {
149    TimerCounter6: (Tc6, tc6_, Tc6Tc7Clock, apbdmask),
150    TimerCounter7: (Tc7, tc7_, Tc6Tc7Clock, apbdmask),
151}