From bc8bab84b6add8d5674af0d8e9f43b33ca1250b2 Mon Sep 17 00:00:00 2001 From: Sh3Rm4n Date: Tue, 9 Mar 2021 14:35:12 +0100 Subject: [PATCH] Increase SysTick delay limit Leverage a full 32 bit range instead of only 24 bit range. This will increase the maximum possible delay from ~2 seconds up to 9 minutes. Also cap the value, instead of panicking, if the value is to high. Fixes https://github.com/stm32-rs/stm32f3xx-hal/issues/203 --- CHANGELOG.md | 10 +++++++++- src/delay.rs | 52 ++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 735d4099c..d936668a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed -- Added support for more CAN bit rates and modes. ([#186](https://github.com/stm32-rs/stm32f3xx-hal/pull/186) +- Added support for more CAN bit rates and modes. ([#186]) + +### Fixed + +- Delay based on systick no longer panics ([#203]) for to high values + and support longer delays ([#208]) ## [v0.6.1] - 2020-12-10 @@ -266,6 +271,9 @@ let clocks = rcc - Support `stm32f303` device +[#208]: https://github.com/stm32-rs/stm32f3xx-hal/pull/208 +[#203]: https://github.com/stm32-rs/stm32f3xx-hal/issues/203 +[#186]: https://github.com/stm32-rs/stm32f3xx-hal/pull/186 [#184]: https://github.com/stm32-rs/stm32f3xx-hal/pull/184 [#172]: https://github.com/stm32-rs/stm32f3xx-hal/pull/172 [#170]: https://github.com/stm32-rs/stm32f3xx-hal/pull/170 diff --git a/src/delay.rs b/src/delay.rs index 1dab55c77..5de14c3ca 100644 --- a/src/delay.rs +++ b/src/delay.rs @@ -16,6 +16,15 @@ pub struct Delay { impl Delay { /// Configures the system timer (SysTick) as a delay provider + /// + /// # Limitations + /// + /// Depending on the core clock, this delay provider + /// can delay between 1 minute (for 72 Mhz) up to almost 9 minutes (for 8 Mhz). + /// Higher input values will be capped to these limits. + /// + /// For accuracy purposes and because this is a blocking, busy-waiting function, + /// if delays in the second to minute range are needed, use timers instead. pub fn new(mut syst: SYST, clocks: Clocks) -> Self { syst.set_clock_source(SystClkSource::Core); @@ -30,7 +39,7 @@ impl Delay { impl DelayMs for Delay { fn delay_ms(&mut self, ms: u32) { - self.delay_us(ms * 1_000); + self.delay_us(ms.saturating_mul(1_000)); } } @@ -48,17 +57,36 @@ impl DelayMs for Delay { impl DelayUs for Delay { fn delay_us(&mut self, us: u32) { - let rvr = us * (self.clocks.sysclk().0 / 1_000_000); - - crate::assert!(rvr < (1 << 24)); - - self.syst.set_reload(rvr); - self.syst.clear_current(); - self.syst.enable_counter(); - - while !self.syst.has_wrapped() {} - - self.syst.disable_counter(); + // The RVR register is 24 bits wide, as SysTick is based on a 24 bit counter + const MAX_RVR: u32 = 1 << 24; + + // Depending on hclk (core clock), this 32 bit value allows + // delays between 1 min to 9 min. + // + // (((32^2) - 1) / 72) µs ~ 59.6 seconds + // (((32^2) - 1) / 8) µs ~ 536.8 seconds + let mut total_rvr = us.saturating_mul(self.clocks.hclk().0 / 1_000_000); + + // Use the full 32 bit range to allow longer delays + // + // Like dividing total_rvr / MAX_RVR + // and delaying by MAX_RVR * (fraction). + while total_rvr != 0 { + let current_rvr = if total_rvr < MAX_RVR { + total_rvr + } else { + MAX_RVR + }; + total_rvr -= current_rvr; + + self.syst.set_reload(current_rvr); + self.syst.clear_current(); + self.syst.enable_counter(); + + while !self.syst.has_wrapped() {} + + self.syst.disable_counter(); + } } }