stm32f30x_hal/
timer.rs

1//! Timers
2
3use cast::{u16, u32};
4use hal::timer::{CountDown, Periodic};
5use nb;
6use stm32f30x::{TIM2, TIM3, TIM4, TIM6, TIM7};
7use void::Void;
8
9use rcc::{APB1, Clocks};
10use time::Hertz;
11
12/// Hardware timers
13pub struct Timer<TIM> {
14    clocks: Clocks,
15    tim: TIM,
16    timeout: Hertz,
17}
18
19/// Interrupt events
20pub enum Event {
21    /// Timer timed out / count down ended
22    TimeOut,
23}
24
25macro_rules! hal {
26    ($($TIM:ident: ($tim:ident, $timXen:ident, $timXrst:ident),)+) => {
27        $(
28            impl Periodic for Timer<$TIM> {}
29
30            impl CountDown for Timer<$TIM> {
31                type Time = Hertz;
32
33                // NOTE(allow) `w.psc().bits()` is safe for TIM{6,7} but not for TIM{2,3,4} due to
34                // some SVD omission
35                #[allow(unused_unsafe)]
36                fn start<T>(&mut self, timeout: T)
37                where
38                    T: Into<Hertz>,
39                {
40                    // pause
41                    self.tim.cr1.modify(|_, w| w.cen().clear_bit());
42                    // restart counter
43                    self.tim.cnt.reset();
44
45                    self.timeout = timeout.into();
46
47                    let frequency = self.timeout.0;
48                    let ticks = self.clocks.pclk1().0 * if self.clocks.ppre1() == 1 { 1 } else { 2 }
49                        / frequency;
50
51                    let psc = u16((ticks - 1) / (1 << 16)).unwrap();
52                    self.tim.psc.write(|w| unsafe { w.psc().bits(psc) });
53
54                    let arr = u16(ticks / u32(psc + 1)).unwrap();
55                    self.tim.arr.write(|w| unsafe { w.bits(u32(arr)) });
56
57                    // start counter
58                    self.tim.cr1.modify(|_, w| w.cen().set_bit());
59                }
60
61                fn wait(&mut self) -> nb::Result<(), Void> {
62                    if self.tim.sr.read().uif().bit_is_clear() {
63                        Err(nb::Error::WouldBlock)
64                    } else {
65                        self.tim.sr.modify(|_, w| w.uif().clear_bit());
66                        Ok(())
67                    }
68                }
69            }
70
71            impl Timer<$TIM> {
72                // XXX(why not name this `new`?) bummer: constructors need to have different names
73                // even if the `$TIM` are non overlapping (compare to the `free` function below
74                // which just works)
75                /// Configures a TIM peripheral as a periodic count down timer
76                pub fn $tim<T>(tim: $TIM, timeout: T, clocks: Clocks, apb1: &mut APB1) -> Self
77                where
78                    T: Into<Hertz>,
79                {
80                    // enable and reset peripheral to a clean slate state
81                    apb1.enr().modify(|_, w| w.$timXen().set_bit());
82                    apb1.rstr().modify(|_, w| w.$timXrst().set_bit());
83                    apb1.rstr().modify(|_, w| w.$timXrst().clear_bit());
84
85                    let mut timer = Timer {
86                        clocks,
87                        tim,
88                        timeout: Hertz(0),
89                    };
90                    timer.start(timeout);
91
92                    timer
93                }
94
95                /// Starts listening for an `event`
96                pub fn listen(&mut self, event: Event) {
97                    match event {
98                        Event::TimeOut => {
99                            // Enable update event interrupt
100                            self.tim.dier.write(|w| w.uie().set_bit());
101                        }
102                    }
103                }
104
105                /// Stops listening for an `event`
106                pub fn unlisten(&mut self, event: Event) {
107                    match event {
108                        Event::TimeOut => {
109                            // Enable update event interrupt
110                            self.tim.dier.write(|w| w.uie().clear_bit());
111                        }
112                    }
113                }
114
115                /// Releases the TIM peripheral
116                pub fn free(self) -> $TIM {
117                    // pause counter
118                    self.tim.cr1.modify(|_, w| w.cen().clear_bit());
119                    self.tim
120                }
121            }
122        )+
123    }
124}
125
126hal! {
127    TIM2: (tim2, tim2en, tim2rst),
128    TIM3: (tim3, tim3en, tim3rst),
129    TIM4: (tim4, tim4en, tim4rst),
130    TIM6: (tim6, tim6en, tim6rst),
131    TIM7: (tim7, tim7en, tim7rst),
132}