Skip to content

Commit ba3acf1

Browse files
bors[bot]dbrgnburrbull
authored
Merge #335
335: Timer delay r=therealprof a=burrbull Slightly improved and rebased #309 Co-authored-by: Danilo Bargen <mail@dbrgn.ch> Co-authored-by: Andrey Zgarbul <zgarbul.andrey@gmail.com>
2 parents 5791476 + f48a760 commit ba3acf1

File tree

8 files changed

+248
-25
lines changed

8 files changed

+248
-25
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
2525
- Added support for I2S communication using SPI peripherals, and two examples [#265]
2626
- Added support for some LCD controllers using the Flexible Static Memory
2727
Controller / Flexible Memory Controller [#297]
28+
- Added `DelayMs` / `DelayUs` impls for TIM2/TIM5 [#309]
2829
- Added an example for using the new FSMC interface with the provided
2930
`display-interface` driver and the `st7789` driver on a F413Discovery board [#302]
3031
- Derive `Eq`, `PartialEq`, `Copy` and `Clone` for error types
@@ -34,6 +35,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
3435
[#265]: https://github.com/stm32-rs/stm32f4xx-hal/pull/265
3536
[#297]: https://github.com/stm32-rs/stm32f4xx-hal/pull/297
3637
[#302]: https://github.com/stm32-rs/stm32f4xx-hal/pull/302
38+
[#309]: https://github.com/stm32-rs/stm32f4xx-hal/pull/309
3739
[#313]: https://github.com/stm32-rs/stm32f4xx-hal/pull/313
3840
[#318]: https://github.com/stm32-rs/stm32f4xx-hal/pull/318
3941

Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,11 @@ name = "sd"
336336
required-features = ["rt", "stm32f405", "sdio-host"]
337337

338338
[[example]]
339-
name = "delay-blinky"
339+
name = "delay-syst-blinky"
340+
required-features = ["rt", "stm32f411"]
341+
342+
[[example]]
343+
name = "delay-timer-blinky"
340344
required-features = ["rt", "stm32f411"]
341345

342346
[[example]]

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ use the bsp as BSP for your project.
5555

5656
Otherwise, create a new Rust project as you usually do with `cargo init`. The
5757
"hello world" of embedded development is usually to blink a LED. The code to do
58-
so is available in [examples/delay-blinky.rs](examples/delay-blinky.rs).
58+
so is available in [examples/delay-syst-blinky.rs](examples/delay-syst-blinky.rs).
5959
Copy that file to the `main.rs` of your project.
6060

6161
You also need to add some dependencies to your `Cargo.toml`:

examples/delay-blinky.rs renamed to examples/delay-syst-blinky.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//! Demonstrate the use of a blocking `Delay` using the SYST (sysclock) timer.
2+
13
#![deny(unsafe_code)]
24
#![no_main]
35
#![no_std]

examples/delay-timer-blinky.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//! Demonstrate the use of a blocking `Delay` using TIM5 general-purpose timer.
2+
3+
#![deny(unsafe_code)]
4+
#![no_main]
5+
#![no_std]
6+
7+
// Halt on panic
8+
use panic_halt as _; // panic handler
9+
10+
use cortex_m;
11+
use cortex_m_rt::entry;
12+
use stm32f4xx_hal as hal;
13+
14+
use crate::hal::{prelude::*, stm32};
15+
16+
#[entry]
17+
fn main() -> ! {
18+
if let (Some(dp), Some(_cp)) = (
19+
stm32::Peripherals::take(),
20+
cortex_m::peripheral::Peripherals::take(),
21+
) {
22+
// Set up the LED. On the Mini-F4 it's connected to pin PC13.
23+
let gpioc = dp.GPIOC.split();
24+
let mut led = gpioc.pc13.into_push_pull_output();
25+
26+
// Set up the system clock. We want to run at 48MHz for this one.
27+
let rcc = dp.RCC.constrain();
28+
let clocks = rcc.cfgr.sysclk(48.mhz()).freeze();
29+
30+
// Create a delay abstraction based on general-pupose 32-bit timer TIM5
31+
let mut delay = hal::delay::Delay::tim5(dp.TIM5, clocks);
32+
33+
loop {
34+
// On for 1s, off for 1s.
35+
led.set_high();
36+
delay.delay_ms(1_000_u32);
37+
led.set_low();
38+
delay.delay_us(1_000_000_u32);
39+
}
40+
}
41+
42+
loop {}
43+
}

src/delay/mod.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//! Delays
2+
3+
mod syst;
4+
5+
use cortex_m::peripheral::SYST;
6+
7+
use crate::rcc::Clocks;
8+
9+
/// Timer as a delay provider (SysTick by default)
10+
pub struct Delay<T = SYST> {
11+
tim: T,
12+
clocks: Clocks,
13+
}
14+
15+
mod timer;

src/delay.rs renamed to src/delay/syst.rs

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//! Delays
1+
//! System timer (SysTick) as a delay provider.
22
33
use cast::u32;
44
use cortex_m::peripheral::syst::SystClkSource;
@@ -7,18 +7,13 @@ use cortex_m::peripheral::SYST;
77
use crate::rcc::Clocks;
88
use embedded_hal::blocking::delay::{DelayMs, DelayUs};
99

10-
/// System timer (SysTick) as a delay provider
11-
pub struct Delay {
12-
clocks: Clocks,
13-
syst: SYST,
14-
}
10+
use super::Delay;
1511

16-
impl Delay {
12+
impl Delay<SYST> {
1713
/// Configures the system timer (SysTick) as a delay provider
18-
pub fn new(mut syst: SYST, clocks: Clocks) -> Self {
19-
syst.set_clock_source(SystClkSource::External);
20-
21-
Delay { clocks, syst }
14+
pub fn new(mut tim: SYST, clocks: Clocks) -> Self {
15+
tim.set_clock_source(SystClkSource::External);
16+
Self { tim, clocks }
2217
}
2318

2419
#[deprecated(since = "0.10.0", note = "Please use release instead")]
@@ -28,29 +23,29 @@ impl Delay {
2823

2924
/// Releases the system timer (SysTick) resource
3025
pub fn release(self) -> SYST {
31-
self.syst
26+
self.tim
3227
}
3328
}
3429

35-
impl DelayMs<u32> for Delay {
30+
impl DelayMs<u32> for Delay<SYST> {
3631
fn delay_ms(&mut self, ms: u32) {
3732
self.delay_us(ms * 1_000);
3833
}
3934
}
4035

41-
impl DelayMs<u16> for Delay {
36+
impl DelayMs<u16> for Delay<SYST> {
4237
fn delay_ms(&mut self, ms: u16) {
4338
self.delay_ms(u32(ms));
4439
}
4540
}
4641

47-
impl DelayMs<u8> for Delay {
42+
impl DelayMs<u8> for Delay<SYST> {
4843
fn delay_ms(&mut self, ms: u8) {
4944
self.delay_ms(u32(ms));
5045
}
5146
}
5247

53-
impl DelayUs<u32> for Delay {
48+
impl DelayUs<u32> for Delay<SYST> {
5449
fn delay_us(&mut self, us: u32) {
5550
// The SysTick Reload Value register supports values between 1 and 0x00FFFFFF.
5651
const MAX_RVR: u32 = 0x00FF_FFFF;
@@ -64,27 +59,27 @@ impl DelayUs<u32> for Delay {
6459
MAX_RVR
6560
};
6661

67-
self.syst.set_reload(current_rvr);
68-
self.syst.clear_current();
69-
self.syst.enable_counter();
62+
self.tim.set_reload(current_rvr);
63+
self.tim.clear_current();
64+
self.tim.enable_counter();
7065

7166
// Update the tracking variable while we are waiting...
7267
total_rvr -= current_rvr;
7368

74-
while !self.syst.has_wrapped() {}
69+
while !self.tim.has_wrapped() {}
7570

76-
self.syst.disable_counter();
71+
self.tim.disable_counter();
7772
}
7873
}
7974
}
8075

81-
impl DelayUs<u16> for Delay {
76+
impl DelayUs<u16> for Delay<SYST> {
8277
fn delay_us(&mut self, us: u16) {
8378
self.delay_us(u32(us))
8479
}
8580
}
8681

87-
impl DelayUs<u8> for Delay {
82+
impl DelayUs<u8> for Delay<SYST> {
8883
fn delay_us(&mut self, us: u8) {
8984
self.delay_us(u32(us))
9085
}

src/delay/timer.rs

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
//! Delay implementation based on general-purpose 32 bit timers.
2+
//!
3+
//! TIM2 and TIM5 are a general purpose 32-bit auto-reload up/downcounter with
4+
//! a 16-bit prescaler.
5+
6+
use core::cmp::max;
7+
8+
use cast::{u16, u32};
9+
use embedded_hal::blocking::delay::{DelayMs, DelayUs};
10+
11+
use crate::{
12+
pac::{self, RCC},
13+
rcc::{Clocks, Enable, Reset},
14+
};
15+
16+
use super::Delay;
17+
18+
macro_rules! hal {
19+
($($TIM:ty: ($tim:ident, $waitfn:ident),)+) => {
20+
$(
21+
fn $waitfn(tim: &mut $TIM, prescaler: u16, auto_reload_register: u32) {
22+
// Write Prescaler (PSC)
23+
tim.psc.write(|w| w.psc().bits(prescaler));
24+
25+
// Write Auto-Reload Register (ARR)
26+
// Note: Make it impossible to set the ARR value to 0, since this
27+
// would cause an infinite loop.
28+
tim.arr.write(|w| unsafe { w.bits(max(1, auto_reload_register)) });
29+
30+
// Trigger update event (UEV) in the event generation register (EGR)
31+
// in order to immediately apply the config
32+
tim.cr1.modify(|_, w| w.urs().set_bit());
33+
tim.egr.write(|w| w.ug().set_bit());
34+
tim.cr1.modify(|_, w| w.urs().clear_bit());
35+
36+
// Configure the counter in one-pulse mode (counter stops counting at
37+
// the next updateevent, clearing the CEN bit) and enable the counter.
38+
tim.cr1.write(|w| w.opm().set_bit().cen().set_bit());
39+
40+
// Wait for CEN bit to clear
41+
while tim.cr1.read().cen().is_enabled() { /* wait */ }
42+
}
43+
44+
impl Delay<$TIM> {
45+
/// Configures the timer as a delay provider
46+
pub fn $tim(tim: $TIM, clocks: Clocks) -> Self {
47+
unsafe {
48+
//NOTE(unsafe) this reference will only be used for atomic writes with no side effects
49+
let rcc = &(*RCC::ptr());
50+
51+
<$TIM>::enable(rcc);
52+
<$TIM>::reset(rcc);
53+
}
54+
55+
// Enable one-pulse mode (counter stops counting at the next update
56+
// event, clearing the CEN bit)
57+
tim.cr1.modify(|_, w| w.opm().enabled());
58+
59+
Self { tim, clocks }
60+
}
61+
62+
/// Releases the timer resource
63+
pub fn free(self) -> $TIM {
64+
self.tim
65+
}
66+
}
67+
68+
impl DelayUs<u32> for Delay<$TIM> {
69+
/// Sleep for up to 2^32-1 microseconds (~71 minutes).
70+
fn delay_us(&mut self, us: u32) {
71+
// Set up prescaler so that a tick takes exactly 1 µs.
72+
//
73+
// For example, if the clock is set to 48 MHz, with a prescaler of 48
74+
// we'll get ticks that are 1 µs long. This means that we can write the
75+
// delay value directly to the auto-reload register (ARR).
76+
let psc = u16(self.clocks.pclk1().0 / 1_000_000)
77+
.expect("Prescaler does not fit in u16");
78+
let arr = us;
79+
$waitfn(&mut self.tim, psc, arr);
80+
}
81+
}
82+
83+
impl DelayUs<u16> for Delay<$TIM> {
84+
/// Sleep for up to 2^16-1 microseconds (~65 milliseconds).
85+
fn delay_us(&mut self, us: u16) {
86+
// See DelayUs<u32> for explanations.
87+
let psc = u16(self.clocks.pclk1().0 / 1_000_000)
88+
.expect("Prescaler does not fit in u16");
89+
let arr = u32(us);
90+
$waitfn(&mut self.tim, psc, arr);
91+
}
92+
}
93+
94+
impl DelayMs<u32> for Delay<$TIM> {
95+
/// Sleep for up to (2^32)/2-1 milliseconds (~24 days).
96+
/// If the `ms` value is larger than 2147483647, the code will panic.
97+
fn delay_ms(&mut self, ms: u32) {
98+
// See next section for explanation why the usable range is reduced.
99+
assert!(ms <= 2_147_483_647); // (2^32)/2-1
100+
101+
// Set up prescaler so that a tick takes exactly 0.5 ms.
102+
//
103+
// For example, if the clock is set to 48 MHz, with a prescaler of 24'000
104+
// we'll get ticks that are 0.5 ms long. This means that we can write the
105+
// delay value multipled by two to the auto-reload register (ARR).
106+
//
107+
// Note that we cannot simply use a prescaler value where the tick corresponds
108+
// to 1 ms, because then a clock of 100 MHz would correspond to a prescaler
109+
// value of 100'000, which doesn't fit in the 16-bit PSC register.
110+
//
111+
// Unfortunately this means that only one half of the full 32-bit range
112+
// can be used, but 24 days should be plenty of usable delay time.
113+
let psc = u16(self.clocks.pclk1().0 / 1000 / 2)
114+
.expect("Prescaler does not fit in u16");
115+
116+
// Since PSC = 0.5 ms, double the value for the ARR
117+
let arr = ms << 1;
118+
119+
$waitfn(&mut self.tim, psc, arr);
120+
}
121+
}
122+
123+
impl DelayMs<u16> for Delay<$TIM> {
124+
/// Sleep for up to (2^16)-1 milliseconds (~65 seconds).
125+
fn delay_ms(&mut self, ms: u16) {
126+
// See DelayMs<u32> for explanations. Since the value range is only 16 bit,
127+
// we don't need an assert here.
128+
let psc = u16(self.clocks.pclk1().0 / 1000 / 2)
129+
.expect("Prescaler does not fit in u16");
130+
let arr = u32(ms) << 1;
131+
$waitfn(&mut self.tim, psc, arr);
132+
}
133+
}
134+
)+
135+
}
136+
}
137+
138+
hal! {
139+
pac::TIM5: (tim5, wait_tim5),
140+
}
141+
142+
#[cfg(any(
143+
feature = "stm32f401",
144+
feature = "stm32f405",
145+
feature = "stm32f407",
146+
feature = "stm32f411",
147+
feature = "stm32f412",
148+
feature = "stm32f413",
149+
feature = "stm32f415",
150+
feature = "stm32f417",
151+
feature = "stm32f423",
152+
feature = "stm32f427",
153+
feature = "stm32f429",
154+
feature = "stm32f437",
155+
feature = "stm32f439",
156+
feature = "stm32f446",
157+
feature = "stm32f469",
158+
feature = "stm32f479"
159+
))]
160+
hal! {
161+
pac::TIM2: (tim2, wait_tim2),
162+
}

0 commit comments

Comments
 (0)