Skip to main content

msp430fr2x5x_hal/
timer.rs

1//! Countdown timers
2//!
3//! Configures the board's TimerB peripherals into periodic countdown timers. Each peripheral
4//! consists of a main timer and multiple "sub-timers". Sub-timers have their own thresholds and
5//! interrupts but share their countdowns with their main timer.
6//!
7//! This module also contains traits used by other HAL modules that depend on TimerB, such as
8//! `Capture` and `Pwm`.
9
10use crate::clock::{Aclk, Smclk};
11use crate::hw_traits::timer_base::{CCRn, RunningMode, Tbssel, TimerBase};
12use core::convert::Infallible;
13use core::marker::PhantomData;
14
15pub use crate::hw_traits::timer_base::{
16    TimerDiv, TimerExDiv, CCR0, CCR1, CCR2, CCR3, CCR4, CCR5, CCR6,
17};
18
19// Trait effectively sealed by CCRn
20/// Trait indicating that the peripheral can be used as a sub-timer, PWM, or capture
21pub trait CapCmp<C>: CCRn<C> {}
22impl<T: CCRn<C>, C> CapCmp<C> for T {}
23
24// Trait effectively sealed by TimerB
25/// Trait indicating that the peripheral can be used as a timer
26pub trait TimerPeriph: TimerBase + CapCmp<CCR0> {
27    /// Pin type used for external TBxCLK of this timer
28    type Tbxclk;
29}
30
31// Traits effectively sealed by CCRn
32/// Trait indicating that the peripheral has 3 capture compare registers
33pub trait CapCmpTimer3: TimerPeriph + CapCmp<CCR1> + CapCmp<CCR2> {}
34/// Trait indicating that the peripheral has 7 capture compare registers
35pub trait CapCmpTimer7:
36    TimerPeriph
37    + CapCmp<CCR1>
38    + CapCmp<CCR2>
39    + CapCmp<CCR3>
40    + CapCmp<CCR4>
41    + CapCmp<CCR5>
42    + CapCmp<CCR6>
43{
44}
45
46/// Configuration object for the TimerB peripheral
47///
48/// Used to configure `Timer`, `Capture`, and `Pwm`, which all use the TimerB peripheral.
49pub struct TimerConfig<T: TimerPeriph> {
50    _timer: PhantomData<T>,
51    sel: Tbssel,
52    div: TimerDiv,
53    ex_div: TimerExDiv,
54}
55
56impl<T: TimerPeriph> TimerConfig<T> {
57    /// Configure timer clock source to ACLK
58    #[inline]
59    pub fn aclk(_aclk: &Aclk) -> Self {
60        TimerConfig {
61            _timer: PhantomData,
62            sel: Tbssel::Aclk,
63            div: TimerDiv::_1,
64            ex_div: TimerExDiv::_1,
65        }
66    }
67
68    /// Configure timer clock source to SMCLK
69    #[inline]
70    pub fn smclk(_smclk: &Smclk) -> Self {
71        TimerConfig {
72            _timer: PhantomData,
73            sel: Tbssel::Smclk,
74            div: TimerDiv::_1,
75            ex_div: TimerExDiv::_1,
76        }
77    }
78
79    /// Configure timer clock source to TBCLK
80    #[inline]
81    pub fn tbclk(_pin: T::Tbxclk) -> Self {
82        TimerConfig {
83            _timer: PhantomData,
84            sel: Tbssel::Tbxclk,
85            div: TimerDiv::_1,
86            ex_div: TimerExDiv::_1,
87        }
88    }
89
90    /// Configure the normal clock divider and expansion clock divider settings
91    #[inline]
92    pub fn clk_div(self, div: TimerDiv, ex_div: TimerExDiv) -> Self {
93        TimerConfig {
94            _timer: PhantomData,
95            sel: self.sel,
96            div,
97            ex_div,
98        }
99    }
100
101    #[inline]
102    pub(crate) fn write_regs(self, timer: &T) {
103        timer.reset();
104        timer.set_tbidex(self.ex_div);
105        timer.config_clock(self.sel, self.div);
106    }
107}
108
109/// Main timer and sub-timers for timer peripherals with 3 capture-compare registers
110pub struct TimerParts3<T: CapCmpTimer3> {
111    /// Main timer
112    pub timer: Timer<T>,
113    /// Timer interrupt vector
114    pub tbxiv: TBxIV<T>,
115    /// Sub-timer 1 (derived from CCR1 register)
116    pub subtimer1: SubTimer<T, CCR1>,
117    /// Sub-timer 2 (derived from CCR2 register)
118    pub subtimer2: SubTimer<T, CCR2>,
119}
120
121impl<T: CapCmpTimer3> TimerParts3<T> {
122    /// Create new set of timers out of a TBx peripheral
123    #[inline(always)]
124    pub fn new(_timer: T, config: TimerConfig<T>) -> Self {
125        config.write_regs(unsafe { &T::steal() });
126        Self {
127            timer: Timer::new(),
128            tbxiv: TBxIV(PhantomData),
129            subtimer1: SubTimer::new(),
130            subtimer2: SubTimer::new(),
131        }
132    }
133}
134
135/// Main timer and sub-timers for timer peripherals with 7 capture-compare registers
136pub struct TimerParts7<T: CapCmpTimer7> {
137    /// Main timer
138    pub timer: Timer<T>,
139    /// Timer interrupt vector
140    pub tbxiv: TBxIV<T>,
141    /// Sub-timer 1 (derived from CCR1 register)
142    pub subtimer1: SubTimer<T, CCR1>,
143    /// Sub-timer 2 (derived from CCR2 register)
144    pub subtimer2: SubTimer<T, CCR2>,
145    /// Sub-timer 3 (derived from CCR3 register)
146    pub subtimer3: SubTimer<T, CCR3>,
147    /// Sub-timer 4 (derived from CCR4 register)
148    pub subtimer4: SubTimer<T, CCR4>,
149    /// Sub-timer 5 (derived from CCR5 register)
150    pub subtimer5: SubTimer<T, CCR5>,
151    /// Sub-timer 6 (derived from CCR6 register)
152    pub subtimer6: SubTimer<T, CCR6>,
153}
154
155impl<T: CapCmpTimer7> TimerParts7<T> {
156    /// Create new set of timers out of a TBx peripheral
157    #[inline(always)]
158    pub fn new(_timer: T, config: TimerConfig<T>) -> Self {
159        config.write_regs(unsafe { &T::steal() });
160        Self {
161            timer: Timer::new(),
162            tbxiv: TBxIV(PhantomData),
163            subtimer1: SubTimer::new(),
164            subtimer2: SubTimer::new(),
165            subtimer3: SubTimer::new(),
166            subtimer4: SubTimer::new(),
167            subtimer5: SubTimer::new(),
168            subtimer6: SubTimer::new(),
169        }
170    }
171}
172
173/// Main periodic countdown timer
174pub struct Timer<T: TimerPeriph>(PhantomData<T>);
175
176impl<T: TimerPeriph> Timer<T> {
177    fn new() -> Self {
178        Self(PhantomData)
179    }
180}
181
182/// Sub-timer associated with a main timer
183///
184/// Each sub-timer has its own interrupt mechanism and threshold, but shares its countdown value
185/// with its main timer.
186pub struct SubTimer<T: CapCmp<C>, C>(PhantomData<T>, PhantomData<C>);
187
188impl<T: CapCmp<C>, C> SubTimer<T, C> {
189    fn new() -> Self {
190        Self(PhantomData, PhantomData)
191    }
192}
193
194/// Indicates which sub/main timer caused the interrupt to fire
195pub enum TimerVector {
196    /// No pending interrupt
197    NoInterrupt,
198    /// Interrupt caused by sub-timer 1
199    SubTimer1,
200    /// Interrupt caused by sub-timer 2
201    SubTimer2,
202    /// Interrupt caused by sub-timer 3
203    SubTimer3,
204    /// Interrupt caused by sub-timer 4
205    SubTimer4,
206    /// Interrupt caused by sub-timer 5
207    SubTimer5,
208    /// Interrupt caused by sub-timer 6
209    SubTimer6,
210    /// Interrupt caused by main timer overflow
211    MainTimer,
212}
213
214#[inline]
215pub(crate) fn read_tbxiv<T: TimerBase>(timer: &T) -> TimerVector {
216    match timer.tbxiv_rd() {
217        0 => TimerVector::NoInterrupt,
218        2 => TimerVector::SubTimer1,
219        4 => TimerVector::SubTimer2,
220        6 => TimerVector::SubTimer3,
221        8 => TimerVector::SubTimer4,
222        10 => TimerVector::SubTimer5,
223        12 => TimerVector::SubTimer6,
224        14 => TimerVector::MainTimer,
225        _ => unsafe { core::hint::unreachable_unchecked() },
226    }
227}
228
229/// Interrupt vector register for determining which timer caused an ISR
230pub struct TBxIV<T>(PhantomData<T>);
231
232impl<T: TimerBase> TBxIV<T> {
233    #[inline]
234    /// Read the timer interrupt vector. Automatically resets corresponding interrupt flag.
235    pub fn interrupt_vector(&mut self) -> TimerVector {
236        let timer = unsafe { T::steal() };
237        read_tbxiv(&timer)
238    }
239}
240
241impl<T: TimerPeriph> Timer<T> {
242    /// Enable timer countdown expiration interrupts
243    #[inline(always)]
244    pub fn enable_interrupts(&mut self) {
245        let timer = unsafe { T::steal() };
246        timer.tbie_set();
247    }
248
249    /// Disable timer countdown expiration interrupts
250    #[inline(always)]
251    pub fn disable_interrupts(&mut self) {
252        let timer = unsafe { T::steal() };
253        timer.tbie_clr();
254    }
255
256    #[inline]
257    /// Clears the timer, sets the count, and starts the timer in upcounting mode.
258    pub fn start(&mut self, count: u16) {
259        let timer = unsafe { T::steal() };
260        timer.stop();
261        timer.set_ccrn(count);
262        timer.upmode();
263    }
264
265    #[inline]
266    /// Checks if the timer has reached the target value. Returns `Ok(())` if so, otherwise `WouldBlock`.
267    pub fn wait(&mut self) -> nb::Result<(), Infallible> {
268        let timer = unsafe { T::steal() };
269        if timer.tbifg_rd() {
270            timer.tbifg_clr();
271            Ok(())
272        } else {
273            Err(nb::Error::WouldBlock)
274        }
275    }
276
277    #[inline]
278    /// Pause the timer at the current value
279    pub fn pause(&mut self) {
280        let timer = unsafe { T::steal() };
281        timer.stop();
282    }
283
284    #[inline]
285    /// Resume counting from the current value
286    pub fn resume(&mut self) {
287        let timer = unsafe { T::steal() };
288        timer.resume(RunningMode::Up);
289    }
290
291    #[inline]
292    /// Get the current timer value
293    pub fn count(&mut self) -> u16 {
294        let timer = unsafe { T::steal() };
295        timer.get_tbxr()
296    }
297}
298
299impl<T: CapCmp<C>, C> SubTimer<T, C> {
300    #[inline]
301    /// Set the threshold for one of the sub-timers. Once the main timer counts to this threshold
302    /// the sub-timer will fire. Note that the main timer resets once it counts to its own
303    /// threshold, not the sub-timer thresholds. It follows that the sub-timer threshold must be
304    /// less than the main threshold for it to fire.
305    pub fn set_count(&mut self, count: u16) {
306        let timer = unsafe { T::steal() };
307        timer.set_ccrn(count);
308        timer.ccifg_clr();
309    }
310
311    #[inline]
312    /// Wait for the sub-timer to fire
313    pub fn wait(&mut self) -> nb::Result<(), Infallible> {
314        let timer = unsafe { T::steal() };
315        if timer.ccifg_rd() {
316            timer.ccifg_clr();
317            Ok(())
318        } else {
319            Err(nb::Error::WouldBlock)
320        }
321    }
322
323    #[inline(always)]
324    /// Enable the sub-timer interrupts
325    pub fn enable_interrupts(&mut self) {
326        let timer = unsafe { T::steal() };
327        timer.ccie_set();
328    }
329
330    #[inline(always)]
331    /// Disable the sub-timer interrupts
332    pub fn disable_interrupts(&mut self) {
333        let timer = unsafe { T::steal() };
334        timer.ccie_clr();
335    }
336}
337
338#[cfg(feature = "embedded-hal-02")]
339mod ehal02 {
340    use super::*;
341    use embedded_hal_02::timer::{Cancel, CountDown, Periodic};
342
343    impl<T: TimerPeriph + CapCmp<CCR0>> CountDown for Timer<T> {
344        type Time = u16;
345
346        #[inline]
347        fn start<U: Into<Self::Time>>(&mut self, count: U) {
348            self.start(count.into())
349        }
350
351        #[inline]
352        fn wait(&mut self) -> nb::Result<(), void::Void> {
353            self.wait().map_err(|_| nb::Error::WouldBlock)
354        }
355    }
356
357    impl<T: TimerPeriph + CapCmp<CCR0>> Cancel for Timer<T> {
358        type Error = void::Void;
359
360        #[inline(always)]
361        fn cancel(&mut self) -> Result<(), Self::Error> {
362            self.pause();
363            Ok(())
364        }
365    }
366
367    impl<T: TimerPeriph> Periodic for Timer<T> {}
368}