|
1 |
| -//! Delays |
2 |
| -
|
3 |
| -use cast::u32; |
| 1 | +//! API for delays with the systick timer |
| 2 | +//! |
| 3 | +//! Please be aware of potential overflows. |
| 4 | +//! For example, the maximum delay with 48MHz is around 89 seconds |
| 5 | +//! |
| 6 | +//! Consider using the timers api as a more flexible interface |
| 7 | +//! |
| 8 | +//! # Example |
| 9 | +//! |
| 10 | +//! ``` no_run |
| 11 | +//! use stm32f0xx_hal as hal; |
| 12 | +//! |
| 13 | +//! use crate::hal::stm32; |
| 14 | +//! use crate::hal::prelude::*; |
| 15 | +//! use crate::hal::delay::Delay; |
| 16 | +//! use cortex_m::peripheral::Peripherals; |
| 17 | +//! |
| 18 | +//! let mut p = stm32::Peripherals::take().unwrap(); |
| 19 | +//! let mut cp = cortex_m::Peripherals::take().unwrap(); |
| 20 | +//! |
| 21 | +//! let clocks = p.RCC.constrain().cfgr.freeze(); |
| 22 | +//! let mut delay = Delay::new(cp.SYST, clocks); |
| 23 | +//! loop { |
| 24 | +//! delay.delay_ms(1_000_u16); |
| 25 | +//! } |
| 26 | +//! ``` |
| 27 | +
|
| 28 | +use cast::{u16, u32}; |
4 | 29 | use cortex_m::peripheral::syst::SystClkSource;
|
5 | 30 | use cortex_m::peripheral::SYST;
|
6 | 31 |
|
@@ -28,36 +53,58 @@ impl Delay {
|
28 | 53 | }
|
29 | 54 |
|
30 | 55 | impl DelayMs<u32> for Delay {
|
31 |
| - fn delay_ms(&mut self, ms: u32) { |
32 |
| - self.delay_us(ms * 1_000); |
| 56 | + // At 48 MHz, calling delay_us with ms * 1_000 directly overflows at 0x15D868 (just over the max u16 value) |
| 57 | + fn delay_ms(&mut self, mut ms: u32) { |
| 58 | + const MAX_MS: u32 = 0x0000_FFFF; |
| 59 | + while ms != 0 { |
| 60 | + let current_ms = if ms <= MAX_MS { ms } else { MAX_MS }; |
| 61 | + self.delay_us(current_ms * 1_000); |
| 62 | + ms -= current_ms; |
| 63 | + } |
33 | 64 | }
|
34 | 65 | }
|
35 | 66 |
|
36 | 67 | impl DelayMs<u16> for Delay {
|
37 | 68 | fn delay_ms(&mut self, ms: u16) {
|
38 |
| - self.delay_ms(u32(ms)); |
| 69 | + self.delay_us(ms as u32 * 1_000); |
39 | 70 | }
|
40 | 71 | }
|
41 | 72 |
|
42 | 73 | impl DelayMs<u8> for Delay {
|
43 | 74 | fn delay_ms(&mut self, ms: u8) {
|
44 |
| - self.delay_ms(u32(ms)); |
| 75 | + self.delay_ms(u16(ms)); |
45 | 76 | }
|
46 | 77 | }
|
47 | 78 |
|
48 | 79 | impl DelayUs<u32> for Delay {
|
49 | 80 | fn delay_us(&mut self, us: u32) {
|
50 |
| - let rvr = us * (self.clocks.sysclk().0 / 1_000_000); |
| 81 | + // The SysTick Reload Value register supports values between 1 and 0x00FFFFFF. |
| 82 | + const MAX_RVR: u32 = 0x00FF_FFFF; |
| 83 | + |
| 84 | + let mut total_rvr = if self.clocks.sysclk().0 < 1_000_000 { |
| 85 | + us / (1_000_00 / self.clocks.sysclk().0) |
| 86 | + } else { |
| 87 | + us * (self.clocks.sysclk().0 / 1_000_000) |
| 88 | + }; |
| 89 | + |
| 90 | + while total_rvr != 0 { |
| 91 | + let current_rvr = if total_rvr <= MAX_RVR { |
| 92 | + total_rvr |
| 93 | + } else { |
| 94 | + MAX_RVR |
| 95 | + }; |
51 | 96 |
|
52 |
| - assert!(rvr < (1 << 24)); |
| 97 | + self.syst.set_reload(current_rvr); |
| 98 | + self.syst.clear_current(); |
| 99 | + self.syst.enable_counter(); |
53 | 100 |
|
54 |
| - self.syst.set_reload(rvr); |
55 |
| - self.syst.clear_current(); |
56 |
| - self.syst.enable_counter(); |
| 101 | + // Update the tracking variable while we are waiting... |
| 102 | + total_rvr -= current_rvr; |
57 | 103 |
|
58 |
| - while !self.syst.has_wrapped() {} |
| 104 | + while !self.syst.has_wrapped() {} |
59 | 105 |
|
60 |
| - self.syst.disable_counter(); |
| 106 | + self.syst.disable_counter(); |
| 107 | + } |
61 | 108 | }
|
62 | 109 | }
|
63 | 110 |
|
|
0 commit comments