Skip to content

Commit 4e2bed9

Browse files
authored
delay: Add delay module (#23)
This implements the embedded-hal 1.0 `DelayNs` trait. The cortex-m crate has essentially the same logic, but the published version is based on embedded-hal 0.2. This can be removed (repurposed for use with timers?) when a new version of the cortex-m crate is published. The blinky example has been updated to use the delay module.
1 parent f3b4914 commit 4e2bed9

File tree

4 files changed

+137
-9
lines changed

4 files changed

+137
-9
lines changed

examples/blinky.rs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,34 +4,38 @@
44
mod utilities;
55

66
use cortex_m_rt::entry;
7-
use stm32h5xx_hal::{pac, prelude::*};
7+
use embedded_hal::delay::DelayNs;
8+
use fugit::SecsDurationU32;
9+
use stm32h5xx_hal::{delay::Delay, pac, prelude::*, rcc::ResetEnable};
810

911
#[entry]
1012
fn main() -> ! {
1113
utilities::logger::init();
1214

15+
let cp = cortex_m::Peripherals::take().unwrap();
1316
let dp = pac::Peripherals::take().unwrap();
1417

1518
let pwr = dp.PWR.constrain();
1619
let pwrcfg = pwr.vos0().freeze();
1720

1821
// Constrain and Freeze clock
1922
let rcc = dp.RCC.constrain();
20-
let _ccdr = rcc.sys_ck(250.MHz()).freeze(pwrcfg, &dp.SBS);
23+
let ccdr = rcc.sys_ck(250.MHz()).freeze(pwrcfg, &dp.SBS);
24+
25+
ccdr.peripheral.GPIOA.enable();
2126

2227
dp.GPIOA.moder().write(|w| w.mode5().output()); // output
2328
dp.GPIOA.pupdr().write(|w| w.pupd5().pull_up()); // pull-up
2429

25-
// dp.GPIOA.odr.write(|w| w.od5().set_bit());
30+
let mut delay = Delay::new(cp.SYST, &ccdr.clocks);
31+
let duration = SecsDurationU32::secs(1).to_millis();
2632

2733
loop {
2834
dp.GPIOA.odr().write(|w| w.od5().low());
29-
for _ in 0..10_000 {
30-
cortex_m::asm::nop();
31-
}
35+
delay.delay_ms(duration);
36+
log::info!("Off");
3237
dp.GPIOA.odr().write(|w| w.od5().high());
33-
for _ in 0..10_000 {
34-
cortex_m::asm::nop();
35-
}
38+
delay.delay_ms(duration);
39+
log::info!("On");
3640
}
3741
}

src/delay.rs

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
//! Delay providers
2+
//!
3+
//! # Examples
4+
//!
5+
//! ## Delay
6+
//!
7+
//! ```no_run
8+
//! let mut delay = Delay::new(core.SYST, device.clocks);
9+
//!
10+
//! delay.delay_ms(500);
11+
//!
12+
//! // Release SYST from the delay
13+
//! let syst = delay.free();
14+
//! ```
15+
//!
16+
//! # Examples
17+
//!
18+
//! - [Blinky](https://github.com/stm32-rs/stm32h7xx-hal/blob/master/examples/blinky.rs)
19+
20+
use cortex_m::peripheral::syst::SystClkSource;
21+
use cortex_m::peripheral::SYST;
22+
use embedded_hal::delay::DelayNs;
23+
use fugit::SecsDurationU64;
24+
25+
use crate::rcc::CoreClocks;
26+
27+
const SYSTICK_HCLK_DIV: u32 = 8;
28+
29+
pub trait DelayExt {
30+
fn delay(self, clocks: &CoreClocks) -> Delay;
31+
}
32+
33+
impl DelayExt for SYST {
34+
fn delay(self, clocks: &CoreClocks) -> Delay {
35+
Delay::new(self, clocks)
36+
}
37+
}
38+
39+
/// System timer (SysTick) as a delay provider
40+
pub struct Delay {
41+
hclk_hz: u32,
42+
syst: SYST,
43+
}
44+
45+
fn calc_ticks(ns: u32, hclk: u32) -> u32 {
46+
// Default is for SYSTICK to be fed by HCLK/8
47+
let ticks: u64 = (SecsDurationU64::secs(1) * SYSTICK_HCLK_DIV).to_nanos();
48+
((ns as u64 * hclk as u64) / ticks) as u32
49+
}
50+
51+
impl Delay {
52+
/// Configures the system timer (SysTick) as a delay provider
53+
pub fn new(mut syst: SYST, clocks: &CoreClocks) -> Self {
54+
syst.set_clock_source(SystClkSource::External);
55+
56+
Delay {
57+
hclk_hz: clocks.hclk().raw(),
58+
syst,
59+
}
60+
}
61+
62+
/// Releases the system timer (SysTick) resource
63+
pub fn free(self) -> SYST {
64+
self.syst
65+
}
66+
}
67+
68+
impl DelayNs for Delay {
69+
fn delay_ns(&mut self, ns: u32) {
70+
// The SysTick Reload Value register supports values between 1 and 0x00FFFFFF.
71+
const MAX_RVR: u32 = 0x00FF_FFFF;
72+
73+
let mut total_ticks = calc_ticks(ns, self.hclk_hz);
74+
75+
while total_ticks != 0 {
76+
let current_ticks = if total_ticks <= MAX_RVR {
77+
// To count N ticks, set RVR to N-1
78+
// (see ARM Cortex M33 Devices Generic User Guide section 4.3.2.1)
79+
core::cmp::max(total_ticks - 1, 1)
80+
} else {
81+
MAX_RVR
82+
};
83+
84+
self.syst.set_reload(current_ticks);
85+
self.syst.clear_current();
86+
self.syst.enable_counter();
87+
88+
// For an RVR value of N, the SYSTICK counts N+1 ticks
89+
// (see ARM Cortex M33 Devices Generic User Guide section 4.3.2.1)
90+
total_ticks = total_ticks.saturating_sub(current_ticks + 1);
91+
92+
while !self.syst.has_wrapped() {}
93+
94+
self.syst.disable_counter();
95+
}
96+
}
97+
}
98+
99+
#[cfg(test)]
100+
mod tests {
101+
use super::calc_ticks;
102+
#[test]
103+
fn test_calc_rvr() {
104+
let rvr = calc_ticks(1_000, 8_000_000);
105+
assert_eq!(rvr, 1);
106+
107+
let rvr = calc_ticks(1_000_000, 8_000_000);
108+
assert_eq!(rvr, 1000);
109+
110+
let rvr = calc_ticks(1_000_000, 10_000_000);
111+
assert_eq!(rvr, 1250);
112+
113+
let rvr = calc_ticks(1_000_000_000, 250_000_000);
114+
assert_eq!(rvr, 31_250_000);
115+
116+
let rvr = calc_ticks(32, 250_000_000);
117+
assert_eq!(rvr, 1);
118+
}
119+
}

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ pub mod gpio;
5555
#[cfg(feature = "device-selected")]
5656
pub mod icache;
5757

58+
#[cfg(feature = "device-selected")]
59+
pub mod delay;
60+
5861
#[cfg(feature = "device-selected")]
5962
mod sealed {
6063
pub trait Sealed {}

src/prelude.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
//! Prelude
22
3+
pub use crate::delay::DelayExt as _stm32h5xx_hal_delay_DelayExt;
34
pub use crate::gpio::GpioExt as _stm32h5xx_hal_gpio_GpioExt;
45
pub use crate::icache::ICacheExt as _stm32h5xx_hal_delay_ICacheExt;
56
pub use crate::pwr::PwrExt as _stm32h5xx_hal_pwr_PwrExt;
67
pub use crate::rcc::RccExt as _stm32h5xx_hal_rcc_RccExt;
78

9+
pub use crate::time::U32Ext as _;
810
pub use fugit::{ExtU32 as _, RateExtU32 as _};

0 commit comments

Comments
 (0)