stm32f7x7_hal/
timer.rs

1//! Timers
2
3use cast::{u16, u32};
4use cortex_m::peripheral::syst::SystClkSource;
5use cortex_m::peripheral::SYST;
6use embedded_hal::timer::{CountDown, Periodic};
7use nb;
8use void::Void;
9
10use crate::stm32::RCC;
11
12use crate::stm32::{
13    TIM1, TIM10, TIM11, TIM12, TIM13, TIM14, TIM2, TIM3, TIM4, TIM5, TIM6, TIM7, TIM8, TIM9,
14};
15
16use crate::rcc::Clocks;
17use crate::time::Hertz;
18
19/// Hardware timers
20pub struct Timer<TIM> {
21    clocks: Clocks,
22    tim: TIM,
23}
24
25/// Interrupt events
26pub enum Event {
27    /// Timer timed out / count down ended
28    TimeOut,
29}
30
31impl Timer<SYST> {
32    /// Configures the SYST clock as a periodic count down timer
33    pub fn syst<T>(mut syst: SYST, timeout: T, clocks: Clocks) -> Self
34    where
35        T: Into<Hertz>,
36    {
37        syst.set_clock_source(SystClkSource::Core);
38        let mut timer = Timer { tim: syst, clocks };
39        timer.start(timeout);
40        timer
41    }
42
43    /// Starts listening for an `event`
44    pub fn listen(&mut self, event: Event) {
45        match event {
46            Event::TimeOut => self.tim.enable_interrupt(),
47        }
48    }
49
50    /// Stops listening for an `event`
51    pub fn unlisten(&mut self, event: Event) {
52        match event {
53            Event::TimeOut => self.tim.disable_interrupt(),
54        }
55    }
56}
57
58impl CountDown for Timer<SYST> {
59    type Time = Hertz;
60
61    fn start<T>(&mut self, timeout: T)
62    where
63        T: Into<Hertz>,
64    {
65        let rvr = self.clocks.sysclk().0 / timeout.into().0 - 1;
66
67        assert!(rvr < (1 << 24));
68
69        self.tim.set_reload(rvr);
70        self.tim.clear_current();
71        self.tim.enable_counter();
72    }
73
74    fn wait(&mut self) -> nb::Result<(), Void> {
75        if self.tim.has_wrapped() {
76            Ok(())
77        } else {
78            Err(nb::Error::WouldBlock)
79        }
80    }
81}
82
83impl Periodic for Timer<SYST> {}
84
85macro_rules! hal {
86    ($($TIM:ident: ($tim:ident, $timXen:ident, $timXrst:ident, $apbenr:ident, $apbrstr:ident, $pclk:ident, $ppre:ident),)+) => {
87        $(
88            impl Timer<$TIM> {
89                /// Configures a TIM peripheral as a periodic count down timer
90                pub fn $tim<T>(tim: $TIM, timeout: T, clocks: Clocks) -> Self
91                where
92                    T: Into<Hertz>,
93                {
94                    // enable and reset peripheral to a clean slate state
95                    let rcc = unsafe { &(*RCC::ptr()) };
96                    rcc.$apbenr.modify(|_, w| w.$timXen().set_bit());
97                    rcc.$apbrstr.modify(|_, w| w.$timXrst().set_bit());
98                    rcc.$apbrstr.modify(|_, w| w.$timXrst().clear_bit());
99
100                    let mut timer = Timer {
101                        clocks,
102                        tim,
103                    };
104                    timer.start(timeout);
105
106                    timer
107                }
108
109                /// Starts listening for an `event`
110                pub fn listen(&mut self, event: Event) {
111                    match event {
112                        Event::TimeOut => {
113                            // Enable update event interrupt
114                            self.tim.dier.write(|w| w.uie().set_bit());
115                        }
116                    }
117                }
118
119                /// Stops listening for an `event`
120                pub fn unlisten(&mut self, event: Event) {
121                    match event {
122                        Event::TimeOut => {
123                            // Enable update event interrupt
124                            self.tim.dier.write(|w| w.uie().clear_bit());
125                        }
126                    }
127                }
128
129                /// Releases the TIM peripheral
130                pub fn release(self) -> $TIM {
131                    // pause counter
132                    self.tim.cr1.modify(|_, w| w.cen().clear_bit());
133                    self.tim
134                }
135            }
136
137            impl CountDown for Timer<$TIM> {
138                type Time = Hertz;
139
140                fn start<T>(&mut self, timeout: T)
141                where
142                    T: Into<Hertz>,
143                {
144                    // pause
145                    self.tim.cr1.modify(|_, w| w.cen().clear_bit());
146                    // reset counter
147                    self.tim.cnt.reset();
148
149                    let frequency = timeout.into().0;
150                    let pclk_mul = if self.clocks.$ppre() == 1 { 1 } else { 2 };
151                    let ticks = self.clocks.$pclk().0 * pclk_mul / frequency;
152
153                    let psc = u16((ticks - 1) / (1 << 16)).unwrap();
154                    self.tim.psc.write(|w| unsafe { w.psc().bits(psc) });
155
156                    let arr = u16(ticks / u32(psc + 1)).unwrap();
157                    self.tim.arr.write(|w| unsafe { w.bits(u32(arr)) });
158
159                    // start counter
160                    self.tim.cr1.modify(|_, w| w.cen().set_bit());
161                }
162
163                fn wait(&mut self) -> nb::Result<(), Void> {
164                    if self.tim.sr.read().uif().bit_is_clear() {
165                        Err(nb::Error::WouldBlock)
166                    } else {
167                        self.tim.sr.modify(|_, w| w.uif().clear_bit());
168                        Ok(())
169                    }
170                }
171            }
172
173            impl Periodic for Timer<$TIM> {}
174        )+
175    }
176}
177
178hal! {
179    TIM1: (tim1, tim1en, tim1rst, apb2enr, apb2rstr, pclk2, ppre2),
180    TIM5: (tim5, tim5en, tim5rst, apb1enr, apb1rstr, pclk1, ppre1),
181    TIM9: (tim9, tim9en, tim9rst, apb2enr, apb2rstr, pclk1, ppre1),
182    TIM11: (tim11, tim11en, tim11rst, apb2enr, apb2rstr, pclk2, ppre2),
183    TIM2: (tim2, tim2en, tim2rst, apb1enr, apb1rstr, pclk1, ppre1),
184    TIM3: (tim3, tim3en, tim3rst, apb1enr, apb1rstr, pclk1, ppre1),
185    TIM4: (tim4, tim4en, tim4rst, apb1enr, apb1rstr, pclk1, ppre1),
186    TIM10: (tim10, tim10en, tim10rst, apb2enr, apb2rstr, pclk2, ppre2),
187    TIM6: (tim6, tim6en, tim6rst, apb1enr, apb1rstr, pclk1, ppre1),
188    TIM7: (tim7, tim7en, tim7rst, apb1enr, apb1rstr, pclk1, ppre1),
189    TIM8: (tim8, tim8en, tim8rst, apb2enr, apb2rstr, pclk2, ppre2),
190    TIM12: (tim12, tim12en, tim12rst, apb1enr, apb1rstr, pclk1, ppre1),
191    TIM13: (tim13, tim13en, tim13rst, apb1enr, apb1rstr, pclk1, ppre1),
192    TIM14: (tim14, tim14en, tim14rst, apb1enr, apb1rstr, pclk1, ppre1),
193}