1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
//! Timers
use core::convert::Infallible;
use cast::{u16, u32};
use hal::timer::*;
use nb;
use void::Void;
use crate::rcc::{ClockContext, APB1, APB2};
use crate::time::Hertz;
//use rcc::clocking::LPTimerClkSource;
#[cfg(any(feature = "STM32L031x4", feature = "STM32L031x6"))]
use crate::stm32l0x1::TIM22;
use crate::stm32l0x1::{TIM2, TIM21};
/// 16-bit timer
pub struct Timer<TIM> {
/// The underlying timer peripheral
timer: TIM,
/// The timer's period
timeout: Hertz,
/// The clock frequency
clk_f: Hertz,
/// The multiplier to the clock that feeds the timer
timx_prsc: u32,
}
/// Timer events that can be subscribed to
pub enum Event {
/// The timer has expired
Timeout,
}
macro_rules! impl_timer {
($($TIMX:ident: ($timX:ident, $APB:ident, $apb:ident, $enr_bit:ident, $rstr_bit:ident),)+) => {
$(
impl Periodic for Timer<$TIMX> {}
impl Cancel for Timer<$TIMX> {
type Error = Infallible;
fn cancel(&mut self) -> Result<(), Self::Error> {
// disable the timer
self.timer.cr1.modify(|_, w| w.cen().clear_bit());
Ok(())
}
}
impl CountDown for Timer<$TIMX> {
type Time = Hertz;
fn start<T>(&mut self, timeout: T)
where
T: Into<Self::Time>
{
// disable the timer
self.timer.cr1.modify(|_, w| w.cen().clear_bit());
// reset its counter
self.timer.cnt.reset();
self.timeout = timeout.into();
// timer clock ticks per timeout cycle
let ticks = self.clk_f.0 * self.timx_prsc / self.timeout.0;
// prescale the timer clock to account for multiples of the 16-bit counter
// size
let psc = u16((ticks - 1) / (1 << 16)).unwrap();
self.timer.psc.write(|w| w.psc().bits(psc));
// now set the auto-reload value
let arr = u16(ticks / u32(psc + 1)).unwrap();
self.timer.arr.write(|w| w.bits(arr.into()));
// Trigger an update event to load the prescaler value to the clock
self.timer.egr.write(|w| w.ug().set_bit());
// The above line raises an update event which will indicate
// that the timer is already finished. Since this is not the case,
// it should be cleared
self.reset_overflow();
// start counter
self.timer.cr1.modify(|_, w| w.cen().set_bit());
}
fn wait(&mut self) -> Result<(), nb::Error<Void>> {
match self.timer.sr.read().uif().bit_is_clear() {
true => Err(nb::Error::WouldBlock),
false => {
self.reset_overflow();
Ok(())
}
}
}
}
impl Timer<$TIMX> {
/// Instantiate a new timer
pub fn $timX<T: Into<Hertz>>(timer: $TIMX, clk_ctx: &ClockContext, timeout: T, apb: &mut $APB) -> Self {
// enable and reset peripheral to a clean slate state
apb.enr().modify(|_, w| w.$enr_bit().set_bit());
apb.rstr().modify(|_, w| w.$rstr_bit().set_bit());
apb.rstr().modify(|_, w| w.$rstr_bit().clear_bit());
// timer clock is multiplied by 2 if APBx presc is != 1
let timx_prsc = if clk_ctx.hclk_fclk() == clk_ctx.$apb() { 1 } else { 2 };
Timer { timer, timeout: timeout.into(), clk_f: clk_ctx.$apb(), timx_prsc }
}
/// Starts listening for an `event`
pub fn subscribe(&mut self, event: Event) {
match event {
Event::Timeout => self.timer.dier.write(|w| w.uie().set_bit())
}
}
/// Stops listening for an `event`
pub fn unsubscribe(&mut self, event: Event) {
match event {
Event::Timeout => self.timer.dier.write(|w| w.uie().clear_bit())
}
}
#[inline(always)]
/// Resets SR's UIF register to clear status of overflow.
///
/// Unless reset is done, Interrupt handler is going to be continiously called.
pub fn reset_overflow(&mut self) {
self.timer.sr.modify(|_, w| w.uif().clear_bit());
}
/// Pauses timer and releases the TIM peripheral
pub fn free(self) -> $TIMX {
self.timer.cr1.modify(|_, w| w.cen().clear_bit());
self.timer
}
}
)+
}
}
impl_timer! {
TIM2: (tim2, APB1, apb1, tim2en, tim2rst),
TIM21: (tim21, APB2, apb2, tim21en, tim21rst),
}
#[cfg(any(feature = "STM32L031x4", feature = "STM32L031x6"))]
impl_timer! {
TIM22: (tim22, APB2, apb2, tim22en, tim22rst),
}