stm32g0xx_hal/timer/
stopwatch.rs

1use crate::rcc::*;
2use crate::stm32::*;
3use crate::time::{duration, Hertz, Instant, MicroSecond};
4
5pub trait StopwatchExt<TIM> {
6    fn stopwatch(self, rcc: &mut Rcc) -> Stopwatch<TIM>;
7}
8
9pub struct Stopwatch<TIM> {
10    clk: Hertz,
11    tim: TIM,
12}
13
14macro_rules! stopwatches {
15    ($($TIM:ident: $tim:ident, $depth:ident,)+) => {
16        $(
17            impl Stopwatch<$TIM> {
18                pub fn $tim(tim: $TIM, rcc: &mut Rcc) -> Self {
19                    assert!(rcc.clocks.apb_tim_clk.raw() > 1_000_000);
20                    $TIM::enable(rcc);
21                    $TIM::reset(rcc);
22
23                    tim.cr1.modify(|_, w| w.cen().set_bit());
24                    Stopwatch {
25                        tim,
26                        clk: rcc.clocks.apb_tim_clk,
27                    }
28                }
29
30                /// Overrides the counter clock input frequency
31                ///
32                /// Useful if the APB Timer Clock changes after the `Stopwatch` is created or
33                /// to deliberately speed up or slow down the `Stopwatch` from actual measured time.
34                pub fn set_clock(&mut self, clk: Hertz) {
35                    assert!(clk.raw() > 1_000_000);
36                    self.clk = clk;
37                }
38
39                /// Set the prescaler which divides the input clock frequency before the counter
40                ///
41                /// The counter frequency is equal to the input clock divided by the prescaler + 1.
42                pub fn set_prescaler(&mut self, prescaler: u16) {
43                    self.tim.psc.write(|w| unsafe { w.psc().bits(prescaler) });
44                    self.tim.egr.write(|w| w.ug().set_bit());
45                }
46
47                pub fn reset(&mut self) {
48                    self.tim.cnt.reset();
49                }
50
51                pub fn pause(&mut self) {
52                    self.tim.cr1.modify(|_, w| w.cen().clear_bit());
53                }
54
55                pub fn resume(&mut self) {
56                    self.tim.cr1.modify(|_, w| w.cen().set_bit());
57                }
58
59                pub fn release(self) -> $TIM {
60                    self.tim
61                }
62
63                pub fn now(&self) -> Instant {
64                    Instant::from_ticks(self.tim.cnt.read().bits())
65                }
66
67                pub fn elapsed(&self, ts: Instant) -> MicroSecond {
68                    let now = self.now().ticks();
69                    let cycles = (now as $depth).wrapping_sub(ts.ticks() as $depth) as u32;
70                    duration(self.clk, cycles * (1 + self.tim.psc.read().bits()))
71                }
72
73                pub fn trace<F>(&self, mut closure: F) -> MicroSecond
74                where
75                    F: FnMut(),
76                {
77                    let started = self.now().ticks();
78                    closure();
79                    let now = self.now().ticks();
80                    duration(self.clk, now.wrapping_sub(started) * (1 + self.tim.psc.read().bits()))
81                }
82            }
83
84            impl StopwatchExt<$TIM> for $TIM {
85                fn stopwatch(self, rcc: &mut Rcc) -> Stopwatch<$TIM> {
86                    Stopwatch::$tim(self, rcc)
87                }
88            }
89        )+
90    }
91}
92
93stopwatches! {
94    TIM1: tim1, u16,
95    TIM3: tim3, u16,
96    TIM14: tim14, u16,
97    TIM16: tim16, u16,
98    TIM17: tim17, u16,
99}
100
101#[cfg(feature = "stm32g0x1")]
102stopwatches! {
103    TIM2: tim2, u32,
104}
105
106#[cfg(any(feature = "stm32g070", feature = "stm32g071", feature = "stm32g081"))]
107stopwatches! {
108    TIM6: tim6, u16,
109    TIM7: tim7, u16,
110    TIM15: tim15, u16,
111}