stm32f0xx_hal/
timers.rs

1//! API for the integrated timers
2//!
3//! This only implements basic functions, a lot of things are missing
4//!
5//! # Example
6//! Blink the led with 1Hz
7//! ``` no_run
8//! use stm32f0xx_hal as hal;
9//!
10//! use crate::hal::pac;
11//! use crate::hal::prelude::*;
12//! use crate::hal::time::*;
13//! use crate::hal::timers::*;
14//! use nb::block;
15//!
16//! cortex_m::interrupt::free(|cs| {
17//!     let mut p = pac::Peripherals::take().unwrap();
18//!     let mut rcc = p.RCC.configure().freeze(&mut p.FLASH);
19//!
20//!     let gpioa = p.GPIOA.split(&mut rcc);
21//!
22//!     let mut led = gpioa.pa1.into_push_pull_pull_output(cs);
23//!
24//!     let mut timer = Timer::tim1(p.TIM1, Hertz(1), &mut rcc);
25//!     loop {
26//!         led.toggle();
27//!         block!(timer.wait()).ok();
28//!     }
29//! });
30//! ```
31use cortex_m::peripheral::syst::SystClkSource;
32use cortex_m::peripheral::SYST;
33
34use crate::rcc::{Clocks, Rcc};
35
36use crate::time::Hertz;
37use embedded_hal::timer::{CountDown, Periodic};
38use void::Void;
39
40/// Hardware timers
41pub struct Timer<TIM> {
42    clocks: Clocks,
43    tim: TIM,
44}
45
46/// Interrupt events
47pub enum Event {
48    /// Timer timed out / count down ended
49    TimeOut,
50}
51
52impl Timer<SYST> {
53    /// Configures the SYST clock as a periodic count down timer
54    pub fn syst<T>(mut syst: SYST, timeout: T, rcc: &Rcc) -> Self
55    where
56        T: Into<Hertz>,
57    {
58        syst.set_clock_source(SystClkSource::Core);
59        let mut timer = Timer {
60            tim: syst,
61            clocks: rcc.clocks,
62        };
63        timer.start(timeout);
64        timer
65    }
66
67    /// Starts listening for an `event`
68    pub fn listen(&mut self, event: &Event) {
69        match event {
70            Event::TimeOut => self.tim.enable_interrupt(),
71        }
72    }
73
74    /// Stops listening for an `event`
75    pub fn unlisten(&mut self, event: &Event) {
76        match event {
77            Event::TimeOut => self.tim.disable_interrupt(),
78        }
79    }
80}
81
82/// Use the systick as a timer
83///
84/// Be aware that intervals less than 4 Hertz may not function properly
85impl CountDown for Timer<SYST> {
86    type Time = Hertz;
87
88    /// Start the timer with a `timeout`
89    fn start<T>(&mut self, timeout: T)
90    where
91        T: Into<Hertz>,
92    {
93        let rvr = self.clocks.sysclk().0 / timeout.into().0 - 1;
94
95        assert!(rvr < (1 << 24));
96
97        self.tim.set_reload(rvr);
98        self.tim.clear_current();
99        self.tim.enable_counter();
100    }
101
102    /// Return `Ok` if the timer has wrapped
103    /// Automatically clears the flag and restarts the time
104    fn wait(&mut self) -> nb::Result<(), Void> {
105        if self.tim.has_wrapped() {
106            Ok(())
107        } else {
108            Err(nb::Error::WouldBlock)
109        }
110    }
111}
112
113impl Periodic for Timer<SYST> {}
114
115macro_rules! timers {
116    ($($TIM:ident: ($tim:ident, $timXen:ident, $timXrst:ident, $apbenr:ident, $apbrstr:ident),)+) => {
117        $(
118            use crate::pac::$TIM;
119            impl Timer<$TIM> {
120                // XXX(why not name this `new`?) bummer: constructors need to have different names
121                // even if the `$TIM` are non overlapping (compare to the `free` function below
122                // which just works)
123                /// Configures a TIM peripheral as a periodic count down timer
124                pub fn $tim<T>(tim: $TIM, timeout: T, rcc: &mut Rcc) -> Self
125                where
126                    T: Into<Hertz>,
127                {
128                    // enable and reset peripheral to a clean slate state
129                    rcc.regs.$apbenr.modify(|_, w| w.$timXen().set_bit());
130                    rcc.regs.$apbrstr.modify(|_, w| w.$timXrst().set_bit());
131                    rcc.regs.$apbrstr.modify(|_, w| w.$timXrst().clear_bit());
132
133                    let mut timer = Timer {
134                        clocks: rcc.clocks,
135                        tim,
136                    };
137                    timer.start(timeout);
138
139                    timer
140                }
141
142                /// Starts listening for an `event`
143                pub fn listen(&mut self, event: Event) {
144                    match event {
145                        Event::TimeOut => {
146                            // Enable update event interrupt
147                            self.tim.dier.write(|w| w.uie().set_bit());
148                        }
149                    }
150                }
151
152                /// Stops listening for an `event`
153                pub fn unlisten(&mut self, event: Event) {
154                    match event {
155                        Event::TimeOut => {
156                            // Enable update event interrupt
157                            self.tim.dier.write(|w| w.uie().clear_bit());
158                        }
159                    }
160                }
161
162                /// Releases the TIM peripheral
163                pub fn release(self) -> $TIM {
164                    let rcc = unsafe { &(*crate::pac::RCC::ptr()) };
165                    // Pause counter
166                    self.tim.cr1.modify(|_, w| w.cen().clear_bit());
167                    // Disable timer
168                    rcc.$apbenr.modify(|_, w| w.$timXen().clear_bit());
169                    self.tim
170                }
171            }
172
173            impl CountDown for Timer<$TIM> {
174                type Time = Hertz;
175
176                /// Start the timer with a `timeout`
177                fn start<T>(&mut self, timeout: T)
178                where
179                    T: Into<Hertz>,
180                {
181                    // pause
182                    self.tim.cr1.modify(|_, w| w.cen().clear_bit());
183                    // restart counter
184                    self.tim.cnt.reset();
185
186                    let frequency = timeout.into().0;
187                    // If pclk is prescaled from hclk, the frequency fed into the timers is doubled
188                    let tclk = if self.clocks.hclk().0 == self.clocks.pclk().0 {
189                        self.clocks.pclk().0
190                    } else {
191                        self.clocks.pclk().0 * 2
192                    };
193                    let ticks = tclk / frequency;
194
195                    let psc = cast::u16((ticks - 1) / (1 << 16)).unwrap();
196                    self.tim.psc.write(|w| w.psc().bits(psc));
197
198                    let arr = cast::u16(ticks / cast::u32(psc + 1)).unwrap();
199                    self.tim.arr.write(|w| unsafe { w.bits(cast::u32(arr)) });
200
201                    // start counter
202                    self.tim.cr1.modify(|_, w| w.cen().set_bit());
203                }
204
205                /// Return `Ok` if the timer has wrapped
206                /// Automatically clears the flag and restarts the time
207                fn wait(&mut self) -> nb::Result<(), Void> {
208                    if self.tim.sr.read().uif().bit_is_clear() {
209                        Err(nb::Error::WouldBlock)
210                    } else {
211                        self.tim.sr.modify(|_, w| w.uif().clear_bit());
212                        Ok(())
213                    }
214                }
215            }
216
217            impl Periodic for Timer<$TIM> {}
218        )+
219    }
220}
221
222timers! {
223    TIM1: (tim1, tim1en, tim1rst, apb2enr, apb2rstr),
224    TIM3: (tim3, tim3en, tim3rst, apb1enr, apb1rstr),
225    TIM14: (tim14, tim14en, tim14rst, apb1enr, apb1rstr),
226    TIM16: (tim16, tim16en, tim16rst, apb2enr, apb2rstr),
227    TIM17: (tim17, tim17en, tim17rst, apb2enr, apb2rstr),
228}
229
230#[cfg(any(
231    feature = "stm32f031",
232    feature = "stm32f038",
233    feature = "stm32f042",
234    feature = "stm32f048",
235    feature = "stm32f051",
236    feature = "stm32f058",
237    feature = "stm32f071",
238    feature = "stm32f072",
239    feature = "stm32f078",
240    feature = "stm32f091",
241    feature = "stm32f098",
242))]
243timers! {
244    TIM2: (tim2, tim2en, tim2rst, apb1enr, apb1rstr),
245}
246
247#[cfg(any(
248    feature = "stm32f030x8",
249    feature = "stm32f030xc",
250    feature = "stm32f051",
251    feature = "stm32f058",
252    feature = "stm32f070xb",
253    feature = "stm32f071",
254    feature = "stm32f072",
255    feature = "stm32f078",
256    feature = "stm32f091",
257    feature = "stm32f098",
258))]
259timers! {
260    TIM6: (tim6, tim6en, tim6rst, apb1enr, apb1rstr),
261    TIM15: (tim15, tim15en, tim15rst, apb2enr, apb2rstr),
262}
263
264#[cfg(any(
265    feature = "stm32f030xc",
266    feature = "stm32f070xb",
267    feature = "stm32f071",
268    feature = "stm32f072",
269    feature = "stm32f078",
270    feature = "stm32f091",
271    feature = "stm32f098",
272))]
273timers! {
274    TIM7: (tim7, tim7en, tim7rst, apb1enr, apb1rstr),
275}
276
277use crate::gpio::{AF0, AF1, AF2, AF4, AF5};
278
279use crate::gpio::{gpioa::*, gpiob::*, Alternate};
280
281// Output channels marker traits
282pub trait PinC1<TIM> {}
283pub trait PinC2<TIM> {}
284pub trait PinC3<TIM> {}
285pub trait PinC4<TIM> {}
286
287macro_rules! channel_impl {
288    ( $( $TIM:ident, $PINC:ident, $PINX:ident, $MODE:ident<$AF:ident>; )+ ) => {
289        $(
290            impl $PINC<$TIM> for $PINX<$MODE<$AF>> {}
291        )+
292    };
293}
294
295channel_impl!(
296    TIM1, PinC1, PA8, Alternate<AF2>;
297    TIM1, PinC2, PA9, Alternate<AF2>;
298    TIM1, PinC3, PA10, Alternate<AF2>;
299    TIM1, PinC4, PA11, Alternate<AF2>;
300
301    TIM3, PinC1, PA6, Alternate<AF1>;
302    TIM3, PinC2, PA7, Alternate<AF1>;
303
304    TIM3, PinC1, PB4, Alternate<AF1>;
305    TIM3, PinC2, PB5, Alternate<AF1>;
306    TIM3, PinC3, PB0, Alternate<AF1>;
307    TIM3, PinC4, PB1, Alternate<AF1>;
308
309
310    TIM14, PinC1, PA4, Alternate<AF4>;
311    TIM14, PinC1, PA7, Alternate<AF4>;
312    TIM14, PinC1, PB1, Alternate<AF0>;
313
314    TIM16, PinC1, PA6, Alternate<AF5>;
315    TIM16, PinC1, PB8, Alternate<AF2>;
316
317    TIM17, PinC1, PA7, Alternate<AF5>;
318    TIM17, PinC1, PB9, Alternate<AF2>;
319);
320
321#[cfg(any(
322    feature = "stm32f030x8",
323    feature = "stm32f030xc",
324    feature = "stm32f051",
325    feature = "stm32f058",
326    feature = "stm32f070xb",
327    feature = "stm32f071",
328    feature = "stm32f072",
329    feature = "stm32f078",
330    feature = "stm32f091",
331    feature = "stm32f098",
332))]
333channel_impl!(
334    TIM15, PinC1, PA2, Alternate<AF0>;
335    TIM15, PinC2, PA3, Alternate<AF0>;
336
337    TIM15, PinC1, PB14, Alternate<AF1>;
338    TIM15, PinC2, PB15, Alternate<AF1>;
339);
340
341#[cfg(any(
342    feature = "stm32f030",
343    feature = "stm32f051",
344    feature = "stm32f058",
345    feature = "stm32f070",
346    feature = "stm32f071",
347    feature = "stm32f072",
348    feature = "stm32f078",
349    feature = "stm32f091",
350    feature = "stm32f098"
351))]
352use crate::gpio::gpioc::*;
353
354#[cfg(any(
355    feature = "stm32f030",
356    feature = "stm32f051",
357    feature = "stm32f058",
358    feature = "stm32f070",
359    feature = "stm32f071",
360    feature = "stm32f072",
361    feature = "stm32f078",
362    feature = "stm32f091",
363    feature = "stm32f098"
364))]
365channel_impl!(
366    TIM3, PinC1, PC6, Alternate<AF0>;
367    TIM3, PinC2, PC7, Alternate<AF0>;
368    TIM3, PinC3, PC8, Alternate<AF0>;
369    TIM3, PinC4, PC9, Alternate<AF0>;
370);
371
372#[cfg(any(
373    feature = "stm32f071",
374    feature = "stm32f072",
375    feature = "stm32f078",
376    feature = "stm32f091",
377    feature = "stm32f098"
378))]
379use crate::gpio::gpioe::*;
380
381#[cfg(any(
382    feature = "stm32f071",
383    feature = "stm32f072",
384    feature = "stm32f078",
385    feature = "stm32f091",
386    feature = "stm32f098"
387))]
388channel_impl!(
389    TIM1, PinC1, PE9, Alternate<AF0>;
390    TIM1, PinC2, PE11, Alternate<AF0>;
391    TIM1, PinC3, PE13, Alternate<AF0>;
392    TIM1, PinC4, PE14, Alternate<AF0>;
393
394    TIM3, PinC1, PE3, Alternate<AF0>;
395    TIM3, PinC2, PE4, Alternate<AF0>;
396    TIM3, PinC3, PE5, Alternate<AF0>;
397    TIM3, PinC4, PE6, Alternate<AF0>;
398
399    TIM16, PinC1, PE0, Alternate<AF0>;
400
401    TIM17, PinC1, PE1, Alternate<AF0>;
402);
403
404#[cfg(any(
405    feature = "stm32f071",
406    feature = "stm32f072",
407    feature = "stm32f078",
408    feature = "stm32f091",
409    feature = "stm32f098",
410))]
411use crate::gpio::gpiof::*;
412
413#[cfg(any(
414    feature = "stm32f071",
415    feature = "stm32f072",
416    feature = "stm32f078",
417    feature = "stm32f091",
418    feature = "stm32f098",
419))]
420channel_impl!(
421    TIM15, PinC1, PF9, Alternate<AF0>;
422    TIM15, PinC2, PF10, Alternate<AF0>;
423);