Skip to content

Commit 34ce33c

Browse files
Add timer implementation
1 parent 2814d5b commit 34ce33c

File tree

2 files changed

+207
-0
lines changed

2 files changed

+207
-0
lines changed

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ pub mod rcc;
1717
pub mod serial;
1818
pub mod spi;
1919
pub mod time;
20+
pub mod timers;

src/timers.rs

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
#[cfg(feature = "stm32f030")]
2+
use crate::stm32::{RCC, TIM1, TIM14, TIM15, TIM16, TIM17, TIM3, TIM6, TIM7};
3+
#[cfg(feature = "stm32f042")]
4+
use crate::stm32::{RCC, TIM1, TIM14, TIM16, TIM17, TIM2, TIM3};
5+
use cortex_m::peripheral::syst::SystClkSource;
6+
use cortex_m::peripheral::SYST;
7+
8+
use crate::rcc::Clocks;
9+
use cast::{u16, u32};
10+
use embedded_hal::timer::{CountDown, Periodic};
11+
use nb;
12+
use void::Void;
13+
14+
use crate::time::Hertz;
15+
16+
/// Hardware timers
17+
pub struct Timer<TIM> {
18+
clocks: Clocks,
19+
tim: TIM,
20+
}
21+
22+
/// Interrupt events
23+
pub enum Event {
24+
/// Timer timed out / count down ended
25+
TimeOut,
26+
}
27+
28+
impl Timer<SYST> {
29+
/// Configures the SYST clock as a periodic count down timer
30+
pub fn syst<T>(mut syst: SYST, timeout: T, clocks: Clocks) -> Self
31+
where
32+
T: Into<Hertz>,
33+
{
34+
syst.set_clock_source(SystClkSource::Core);
35+
let mut timer = Timer { tim: syst, clocks };
36+
timer.start(timeout);
37+
timer
38+
}
39+
40+
/// Starts listening for an `event`
41+
pub fn listen(&mut self, event: Event) {
42+
match event {
43+
Event::TimeOut => self.tim.enable_interrupt(),
44+
}
45+
}
46+
47+
/// Stops listening for an `event`
48+
pub fn unlisten(&mut self, event: Event) {
49+
match event {
50+
Event::TimeOut => self.tim.disable_interrupt(),
51+
}
52+
}
53+
}
54+
55+
impl CountDown for Timer<SYST> {
56+
type Time = Hertz;
57+
58+
fn start<T>(&mut self, timeout: T)
59+
where
60+
T: Into<Hertz>,
61+
{
62+
let rvr = self.clocks.sysclk().0 / timeout.into().0 - 1;
63+
64+
assert!(rvr < (1 << 24));
65+
66+
self.tim.set_reload(rvr);
67+
self.tim.clear_current();
68+
self.tim.enable_counter();
69+
}
70+
71+
fn wait(&mut self) -> nb::Result<(), Void> {
72+
if self.tim.has_wrapped() {
73+
Ok(())
74+
} else {
75+
Err(nb::Error::WouldBlock)
76+
}
77+
}
78+
}
79+
80+
impl Periodic for Timer<SYST> {}
81+
82+
macro_rules! timers {
83+
($($TIM:ident: ($tim:ident, $timXen:ident, $timXrst:ident, $apbenr:ident, $apbrstr:ident),)+) => {
84+
$(
85+
impl Timer<$TIM> {
86+
// XXX(why not name this `new`?) bummer: constructors need to have different names
87+
// even if the `$TIM` are non overlapping (compare to the `free` function below
88+
// which just works)
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+
// NOTE(unsafe) This executes only during initialisation
95+
let rcc = unsafe { &(*RCC::ptr()) };
96+
97+
// enable and reset peripheral to a clean slate state
98+
rcc.$apbenr.modify(|_, w| w.$timXen().set_bit());
99+
rcc.$apbrstr.modify(|_, w| w.$timXrst().set_bit());
100+
rcc.$apbrstr.modify(|_, w| w.$timXrst().clear_bit());
101+
102+
let mut timer = Timer {
103+
clocks,
104+
tim,
105+
};
106+
timer.start(timeout);
107+
108+
timer
109+
}
110+
111+
/// Starts listening for an `event`
112+
pub fn listen(&mut self, event: Event) {
113+
match event {
114+
Event::TimeOut => {
115+
// Enable update event interrupt
116+
self.tim.dier.write(|w| w.uie().set_bit());
117+
}
118+
}
119+
}
120+
121+
/// Stops listening for an `event`
122+
pub fn unlisten(&mut self, event: Event) {
123+
match event {
124+
Event::TimeOut => {
125+
// Enable update event interrupt
126+
self.tim.dier.write(|w| w.uie().clear_bit());
127+
}
128+
}
129+
}
130+
131+
/// Releases the TIM peripheral
132+
pub fn release(self) -> $TIM {
133+
use crate::stm32::RCC;
134+
let rcc = unsafe { &(*RCC::ptr()) };
135+
// Pause counter
136+
self.tim.cr1.modify(|_, w| w.cen().clear_bit());
137+
// Disable timer
138+
rcc.$apbenr.modify(|_, w| w.$timXen().clear_bit());
139+
self.tim
140+
}
141+
}
142+
143+
impl CountDown for Timer<$TIM> {
144+
type Time = Hertz;
145+
146+
fn start<T>(&mut self, timeout: T)
147+
where
148+
T: Into<Hertz>,
149+
{
150+
// pause
151+
self.tim.cr1.modify(|_, w| w.cen().clear_bit());
152+
// restart counter
153+
self.tim.cnt.reset();
154+
155+
let frequency = timeout.into().0;
156+
let ticks = self.clocks.pclk().0 / frequency;
157+
158+
let psc = u16((ticks - 1) / (1 << 16)).unwrap();
159+
self.tim.psc.write(|w| unsafe { w.psc().bits(psc) });
160+
161+
let arr = u16(ticks / u32(psc + 1)).unwrap();
162+
self.tim.arr.write(|w| unsafe { w.bits(u32(arr)) });
163+
164+
// start counter
165+
self.tim.cr1.modify(|_, w| w.cen().set_bit());
166+
}
167+
168+
fn wait(&mut self) -> nb::Result<(), Void> {
169+
if self.tim.sr.read().uif().bit_is_clear() {
170+
Err(nb::Error::WouldBlock)
171+
} else {
172+
self.tim.sr.modify(|_, w| w.uif().clear_bit());
173+
Ok(())
174+
}
175+
}
176+
}
177+
178+
impl Periodic for Timer<$TIM> {}
179+
)+
180+
}
181+
}
182+
183+
#[cfg(any(feature = "stm32f030", feature = "stm32f042",))]
184+
timers! {
185+
TIM1: (tim1, tim1en, tim1rst, apb2enr, apb2rstr),
186+
TIM3: (tim3, tim3en, tim3rst, apb1enr, apb1rstr),
187+
TIM14: (tim14, tim14en, tim14rst, apb1enr, apb1rstr),
188+
TIM16: (tim16, tim16en, tim16rst, apb2enr, apb2rstr),
189+
TIM17: (tim17, tim17en, tim17rst, apb2enr, apb2rstr),
190+
}
191+
192+
#[cfg(any(feature = "stm32f030x8", feature = "stm32f030xc"))]
193+
timers! {
194+
TIM6: (tim6, tim6en, tim6rst, apb1enr, apb1rstr),
195+
TIM15: (tim15, tim15en, tim15rst, apb2enr, apb2rstr),
196+
}
197+
198+
#[cfg(feature = "stm32f030xc")]
199+
timers! {
200+
TIM7: (tim7, tim7en, tim7rst, apb1enr, apb1rstr),
201+
}
202+
203+
#[cfg(feature = "stm32f042")]
204+
timers! {
205+
TIM2: (tim2, tim2en, tim2rst, apb1enr, apb1rstr),
206+
}

0 commit comments

Comments
 (0)