1//! Working with timer counter hardware
2use core::convert::Infallible;
34use atsamd_hal_macros::hal_cfg;
5use fugit::NanosDurationU32;
67use crate::ehal_02::timer::{CountDown, Periodic};
8use crate::pac::tc0::Count16 as Count16Reg;
9use crate::pac::{Mclk, Tc2, Tc3};
10#[hal_cfg(all("tc4", "tc5"))]
11use crate::pac::{Tc4, Tc5};
12#[hal_cfg(all("tc6", "tc7"))]
13use crate::pac::{Tc6, Tc7};
14use crate::timer_params::TimerParams;
15use crate::timer_traits::InterruptDrivenTimer;
1617use crate::clock;
18use crate::time::{Hertz, Nanoseconds};
1920#[cfg(feature = "async")]
21mod async_api;
2223#[cfg(feature = "async")]
24pub use async_api::*;
2526// Note:
27// TC3 + TC4 can be paired to make a 32-bit counter
28// TC5 + TC6 can be paired to make a 32-bit counter
2930/// A generic hardware timer counter.
31///
32/// The counters are exposed in 16-bit mode only.
33/// The hardware allows configuring the 8-bit mode
34/// and pairing up some instances to run in 32-bit
35/// mode, but that functionality is not currently
36/// exposed by this hal implementation.
37/// TimerCounter implements both the `Periodic` and
38/// the `CountDown` embedded_hal timer traits.
39/// Before a hardware timer can be used, it must first
40/// have a clock configured.
41pub struct TimerCounter<TC> {
42 freq: Hertz,
43 tc: TC,
44}
4546/// This is a helper trait to make it easier to make most of the
47/// TimerCounter impl generic. It doesn't make too much sense to
48/// to try to implement this trait outside of this module.
49pub trait Count16 {
50fn count_16(&self) -> &Count16Reg;
51}
5253impl<TC> Periodic for TimerCounter<TC> {}
54impl<TC> CountDown for TimerCounter<TC>
55where
56TC: Count16,
57{
58type Time = Nanoseconds;
5960fn start<T>(&mut self, timeout: T)
61where
62T: Into<Self::Time>,
63 {
64 <Self as InterruptDrivenTimer>::start(self, timeout);
65 }
6667fn wait(&mut self) -> nb::Result<(), void::Void> {
68nb::block! {
69 <Self as InterruptDrivenTimer>::wait(self)
70 }
71 .unwrap(); // wait() is Infallible
72Ok(())
73 }
74}
7576impl<TC> InterruptDrivenTimer for TimerCounter<TC>
77where
78TC: Count16,
79{
80/// Enable the interrupt generation for this hardware timer.
81 /// This method only sets the clock configuration to trigger
82 /// the interrupt; it does not configure the interrupt controller
83 /// or define an interrupt handler.
84fn enable_interrupt(&mut self) {
85self.tc.count_16().intenset().write(|w| w.ovf().set_bit());
86 }
8788fn start<T>(&mut self, timeout: T)
89where
90T: Into<NanosDurationU32>,
91 {
92let params = TimerParams::new_ns(timeout.into(), self.freq);
93let divider = params.divider;
94let cycles = params.cycles;
95let count = self.tc.count_16();
9697// Disable the timer while we reconfigure it
98count.ctrla().modify(|_, w| w.enable().clear_bit());
99while count.syncbusy().read().enable().bit_is_set() {}
100101// Now that we have a clock routed to the peripheral, we
102 // can ask it to perform a reset.
103count.ctrla().write(|w| w.swrst().set_bit());
104while count.syncbusy().read().swrst().bit_is_set() {}
105106 count.ctrlbset().write(|w| {
107// Count up when the direction bit is zero
108w.dir().clear_bit();
109// Periodic
110w.oneshot().clear_bit()
111 });
112113// Set TOP value for mfrq mode
114count.cc(0).write(|w| unsafe { w.cc().bits(cycles as u16) });
115116// Enable Match Frequency Waveform generation
117count.wave().modify(|_, w| w.wavegen().mfrq());
118119 count.ctrla().modify(|_, w| {
120match divider {
1211 => w.prescaler().div1(),
1222 => w.prescaler().div2(),
1234 => w.prescaler().div4(),
1248 => w.prescaler().div8(),
12516 => w.prescaler().div16(),
12664 => w.prescaler().div64(),
127256 => w.prescaler().div256(),
1281024 => w.prescaler().div1024(),
129_ => unreachable!(),
130 };
131 w.enable().set_bit();
132 w.runstdby().set_bit()
133 });
134 }
135136fn wait(&mut self) -> nb::Result<(), Infallible> {
137let count = self.tc.count_16();
138if count.intflag().read().ovf().bit_is_set() {
139// Writing a 1 clears the flag
140count.intflag().modify(|_, w| w.ovf().set_bit());
141Ok(())
142 } else {
143Err(nb::Error::WouldBlock)
144 }
145 }
146147/// Disables interrupt generation for this hardware timer.
148 /// This method only sets the clock configuration to prevent
149 /// triggering the interrupt; it does not configure the interrupt
150 /// controller.
151fn disable_interrupt(&mut self) {
152self.tc.count_16().intenclr().write(|w| w.ovf().set_bit());
153 }
154}
155156macro_rules! tc {
157 ($($TYPE:ident: ($TC:ident, $mclk:ident, $clock:ident, $apmask:ident),)+) => {
158 $(
159pub type $TYPE = TimerCounter<$TC>;
160161impl Count16 for $TC {
162fn count_16(&self) -> &Count16Reg {
163self.count16()
164 }
165}
166167impl TimerCounter<$TC>
168{
169/// Configure this timer counter instance.
170 /// The clock is obtained from the `GenericClockController` instance
171 /// and its frequency impacts the resolution and maximum range of
172 /// the timeout values that can be passed to the `start` method.
173 /// Note that some hardware timer instances share the same clock
174 /// generator instance and thus will be clocked at the same rate.
175pub fn $mclk(clock: &clock::$clock, tc: $TC, mclk: &mut Mclk) -> Self {
176// this is safe because we're constrained to just the tc3 bit
177mclk.$apmask().modify(|_, w| w.$mclk().set_bit());
178 {
179let count = tc.count16();
180181// Disable the timer while we reconfigure it
182count.ctrla().modify(|_, w| w.enable().clear_bit());
183while count.syncbusy().read().enable().bit_is_set() {}
184 }
185Self {
186 freq: clock.freq(),
187 tc,
188 }
189 }
190}
191 )+
192 }
193}
194195tc! {
196 TimerCounter2: (Tc2, tc2_, Tc2Tc3Clock, apbbmask),
197 TimerCounter3: (Tc3, tc3_, Tc2Tc3Clock, apbbmask),
198}
199200#[hal_cfg(all("tc4", "tc5"))]
201tc! {
202 TimerCounter4: (Tc4, tc4_, Tc4Tc5Clock, apbcmask),
203 TimerCounter5: (Tc5, tc5_, Tc4Tc5Clock, apbcmask),
204}
205206#[hal_cfg(all("tc6", "tc7"))]
207tc! {
208 TimerCounter6: (Tc6, tc6_, Tc6Tc7Clock, apbdmask),
209 TimerCounter7: (Tc7, tc7_, Tc6Tc7Clock, apbdmask),
210}