Skip to content

Commit 7f7a7d6

Browse files
authored
Merge pull request #5 from david-sawatzke/timers
Add timer implementation
2 parents 2814d5b + 200543b commit 7f7a7d6

File tree

6 files changed

+298
-3
lines changed

6 files changed

+298
-3
lines changed

.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@ matrix:
1515
fast_finish: true
1616
script:
1717
- rustup target add thumbv6m-none-eabi
18-
- cargo build --features=$MCU
18+
- cargo build --features=$MCU --examples --release

Cargo.toml

+16
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,22 @@ debug = true
6262
lto = true
6363
opt-level = "s"
6464

65+
[[example]]
66+
name = "i2c_hal_ssd1306alphabeter"
67+
required-features = ["stm32f042"]
68+
69+
[[example]]
70+
name = "i2c_hal_ina260serial"
71+
required-features = ["stm32f042"]
72+
6573
[[example]]
6674
name = "led_hal_button_irq"
75+
required-features = ["stm32f042", "rt"]
76+
77+
[[example]]
78+
name = "i2c_hal_ina260reader"
79+
required-features = ["stm32f042"]
80+
81+
[[example]]
82+
name = "spi_hal_apa102c"
6783
required-features = ["stm32f042"]

examples/blinky_timer.rs

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#![no_main]
2+
#![no_std]
3+
4+
use panic_halt;
5+
6+
use stm32f0xx_hal as hal;
7+
8+
use crate::hal::prelude::*;
9+
use crate::hal::stm32;
10+
use crate::hal::time::*;
11+
use crate::hal::timers::*;
12+
13+
use cortex_m_rt::entry;
14+
use nb::block;
15+
16+
#[entry]
17+
fn main() -> ! {
18+
if let Some(p) = stm32::Peripherals::take() {
19+
let gpioa = p.GPIOA.split();
20+
/* (Re-)configure PA1 as output */
21+
let mut led = gpioa.pa1.into_push_pull_output();
22+
23+
/* Constrain clocking registers */
24+
let rcc = p.RCC.constrain();
25+
26+
/* Configure clock to 8 MHz (i.e. the default) and freeze it */
27+
let clocks = rcc.cfgr.sysclk(8.mhz()).freeze();
28+
29+
let mut timer = Timer::tim1(p.TIM1, Hertz(1), clocks);
30+
31+
loop {
32+
led.toggle();
33+
block!(timer.wait()).ok();
34+
}
35+
}
36+
37+
loop {
38+
continue;
39+
}
40+
}

memory.x

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
MEMORY
22
{
33
/* NOTE K = KiBi = 1024 bytes */
4-
FLASH : ORIGIN = 0x08000000, LENGTH = 32K
5-
RAM : ORIGIN = 0x20000000, LENGTH = 6K
4+
FLASH : ORIGIN = 0x08000000, LENGTH = 16K
5+
RAM : ORIGIN = 0x20000000, LENGTH = 4K
66
}
77

88
/* This is where the call stack will be allocated. */

src/lib.rs

+1
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

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

0 commit comments

Comments
 (0)