1use cast::{u16, u32};
3use cortex_m::peripheral::syst::SystClkSource;
4use cortex_m::peripheral::SYST;
5use hal::timer::{CountDown, Periodic};
6use nb;
7use void::Void;
8
9use crate::rcc::{Clocks, Rcc};
10use crate::stm32::{TIM2, TIM3, TIM4, TIM5, TIM6, TIM7, TIM9};
11use crate::time::Hertz;
12
13pub trait TimerExt<TIM> {
14 fn timer<T>(self, timeout: T, rcc: &mut Rcc) -> Timer<TIM>
15 where
16 T: Into<Hertz>;
17}
18
19pub struct Timer<TIM> {
21 clocks: Clocks,
22 tim: TIM,
23}
24
25impl Timer<SYST> {
26 pub fn syst<T>(mut syst: SYST, timeout: T, rcc: &mut Rcc) -> Self
28 where
29 T: Into<Hertz>,
30 {
31 syst.set_clock_source(SystClkSource::Core);
32 let mut timer = Timer {
33 tim: syst,
34 clocks: rcc.clocks,
35 };
36 timer.start(timeout);
37 timer
38 }
39
40 pub fn listen(&mut self) {
42 self.tim.enable_interrupt()
43 }
44
45 pub fn unlisten(&mut self) {
47 self.tim.disable_interrupt()
48 }
49}
50
51impl CountDown for Timer<SYST> {
52 type Time = Hertz;
53
54 fn start<T>(&mut self, timeout: T)
55 where
56 T: Into<Hertz>,
57 {
58 let rvr = self.clocks.sys_clk().0 / timeout.into().0 - 1;
59 assert!(rvr < (1 << 24));
60
61 self.tim.set_reload(rvr);
62 self.tim.clear_current();
63 self.tim.enable_counter();
64 }
65
66 fn wait(&mut self) -> nb::Result<(), Void> {
67 if self.tim.has_wrapped() {
68 Ok(())
69 } else {
70 Err(nb::Error::WouldBlock)
71 }
72 }
73}
74
75impl TimerExt<SYST> for SYST {
76 fn timer<T>(self, timeout: T, rcc: &mut Rcc) -> Timer<SYST>
77 where
78 T: Into<Hertz>,
79 {
80 Timer::syst(self, timeout, rcc)
81 }
82}
83
84impl Periodic for Timer<SYST> {}
85
86macro_rules! timers {
87 ($($TIM:ident: ($tim:ident, $timXen:ident, $timXrst:ident, $apbenr:ident, $apbrstr:ident, $timclk:ident),)+) => {
88 $(
89 impl TimerExt<$TIM> for $TIM {
90 fn timer<T>(self, timeout: T, rcc: &mut Rcc) -> Timer<$TIM>
91 where
92 T: Into<Hertz>,
93 {
94 Timer::$tim(self, timeout, rcc)
95 }
96 }
97
98 impl Timer<$TIM> {
99 pub fn $tim<T>(tim: $TIM, timeout: T, rcc: &mut Rcc) -> Self
101 where
102 T: Into<Hertz>,
103 {
104 rcc.rb.$apbenr.modify(|_, w| w.$timXen().set_bit());
105 rcc.rb.$apbrstr.modify(|_, w| w.$timXrst().set_bit());
106 rcc.rb.$apbrstr.modify(|_, w| w.$timXrst().clear_bit());
107
108 let mut timer = Timer {
109 tim,
110 clocks: rcc.clocks,
111 };
112 timer.start(timeout);
113 timer
114 }
115
116 pub fn listen(&mut self) {
118 self.tim.dier.write(|w| w.uie().set_bit());
119 }
120
121 pub fn unlisten(&mut self) {
123 self.tim.dier.write(|w| w.uie().clear_bit());
124 }
125
126 pub fn clear_irq(&mut self) {
128 self.tim.sr.write(|w| w.uif().clear_bit());
129 }
130
131 pub fn release(self) -> $TIM {
133 self.tim.cr1.modify(|_, w| w.cen().clear_bit());
134 self.tim
135 }
136 }
137
138 impl CountDown for Timer<$TIM> {
139 type Time = Hertz;
140
141 fn start<T>(&mut self, timeout: T)
142 where
143 T: Into<Hertz>,
144 {
145 self.tim.cr1.modify(|_, w| w.cen().clear_bit());
147 self.tim.cnt.reset();
149
150 let freq = timeout.into().0;
151 let ticks = self.clocks.$timclk().0 / freq;
152 let psc = u16((ticks - 1) / (1 << 16)).unwrap();
153
154 self.tim.psc.write(|w| unsafe { w.psc().bits(psc) });
155 self.tim.arr.write(|w| unsafe { w.bits(ticks / u32(psc + 1)) });
156
157 self.tim.cr1.modify(|_, w| w.urs().set_bit());
158 self.tim.cr1.modify(|_, w| w.cen().set_bit());
159 }
160
161 fn wait(&mut self) -> nb::Result<(), Void> {
162 if self.tim.sr.read().uif().bit_is_clear() {
163 Err(nb::Error::WouldBlock)
164 } else {
165 self.tim.sr.modify(|_, w| w.uif().clear_bit());
166 Ok(())
167 }
168 }
169 }
170
171 impl Periodic for Timer<$TIM> {}
172 )+
173 }
174}
175
176timers! {
177 TIM2: (tim2, tim2en, tim2rst, apb1enr, apb1rstr, apb1_tim_clk),
178 TIM3: (tim3, tim3en, tim3rst, apb1enr, apb1rstr, apb1_tim_clk),
179 TIM4: (tim4, tim4en, tim4rst, apb1enr, apb1rstr, apb1_tim_clk),
180 TIM5: (tim5, tim5en, tim5rst, apb1enr, apb1rstr, apb1_tim_clk),
181 TIM6: (tim6, tim6en, tim6rst, apb1enr, apb1rstr, apb1_tim_clk),
182 TIM7: (tim7, tim7en, tim7rst, apb1enr, apb1rstr, apb1_tim_clk),
183 TIM9: (tim9, tim9en, tim9rst, apb2enr, apb2rstr, apb2_tim_clk),
184}