atsamd_hal/peripherals/timer/
d11.rs

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