11//! API for delays with the systick timer
22//!
3- //! Please be aware of potential overflows.
4- //! For example, the maximum delay with 48MHz is around 89 seconds
3+ //! Please be aware of potential overflows when using `delay_us` .
4+ //! E.g. at 48MHz the maximum delay is 89 seconds.
55//!
66//! Consider using the timers api as a more flexible interface
77//!
@@ -35,27 +35,31 @@ use embedded_hal::blocking::delay::{DelayMs, DelayUs};
3535/// System timer (SysTick) as a delay provider
3636#[ derive( Clone ) ]
3737pub struct Delay {
38- clocks : Clocks ,
38+ scale : u32 ,
3939}
4040
41- const MAX_SYSTICK : u32 = 0x00FF_FFFF ;
41+ const SYSTICK_RANGE : u32 = 0x0100_0000 ;
4242
4343impl Delay {
4444 /// Configures the system timer (SysTick) as a delay provider
45- /// As access to the count register is possible without a reference, we can
46- /// just drop it
4745 pub fn new ( mut syst : SYST , clocks : Clocks ) -> Delay {
4846 syst. set_clock_source ( SystClkSource :: Core ) ;
4947
50- syst. set_reload ( MAX_SYSTICK ) ;
48+ syst. set_reload ( SYSTICK_RANGE - 1 ) ;
5149 syst. clear_current ( ) ;
5250 syst. enable_counter ( ) ;
53- Delay { clocks }
51+ assert ! ( clocks. hclk( ) . 0 >= 1_000_000 ) ;
52+ let scale = clocks. hclk ( ) . 0 / 1_000_000 ;
53+
54+ Delay { scale }
55+ // As access to the count register is possible without a reference to the systick, we can
56+ // just drop it
5457 }
5558}
5659
5760impl DelayMs < u32 > for Delay {
58- // At 48 MHz, calling delay_us with ms * 1_000 directly overflows at 0x15D868 (just over the max u16 value)
61+ // At 48 MHz (the maximum frequency), calling delay_us with ms * 1_000 directly overflows at 0x15D86 (just over the max u16 value)
62+ // So we implement a separate, higher level, delay loop
5963 fn delay_ms ( & mut self , mut ms : u32 ) {
6064 const MAX_MS : u32 = 0x0000_FFFF ;
6165 while ms != 0 {
@@ -68,7 +72,9 @@ impl DelayMs<u32> for Delay {
6872
6973impl DelayMs < u16 > for Delay {
7074 fn delay_ms ( & mut self , ms : u16 ) {
71- self . delay_us ( u32:: from ( ms) * 1_000 ) ;
75+ // Call delay_us directly, so we don't have to use the additional
76+ // delay loop the u32 variant uses
77+ self . delay_us ( u32 ( ms) * 1_000 ) ;
7278 }
7379}
7480
@@ -78,28 +84,28 @@ impl DelayMs<u8> for Delay {
7884 }
7985}
8086
87+ // At 48MHz (the maximum frequency), this overflows at approx. 2^32 / 48 = 89 seconds
8188impl DelayUs < u32 > for Delay {
8289 fn delay_us ( & mut self , us : u32 ) {
8390 // The SysTick Reload Value register supports values between 1 and 0x00FFFFFF.
8491 // Here less than maximum is used so we have some play if there's a long running interrupt.
85- const MAX_RVR : u32 = 0x007F_FFFF ;
92+ const MAX_TICKS : u32 = 0x007F_FFFF ;
8693
87- let mut total_rvr = if self . clocks . sysclk ( ) . 0 < 1_000_000 {
88- us / ( 1_000_000 / self . clocks . sysclk ( ) . 0 )
89- } else {
90- us * ( self . clocks . sysclk ( ) . 0 / 1_000_000 )
91- } ;
94+ let mut total_ticks = us * self . scale ;
9295
93- while total_rvr != 0 {
94- let current_rvr = if total_rvr <= MAX_RVR {
95- total_rvr
96+ while total_ticks != 0 {
97+ let current_ticks = if total_ticks <= MAX_TICKS {
98+ total_ticks
9699 } else {
97- MAX_RVR
100+ MAX_TICKS
98101 } ;
99102
100103 let start_count = SYST :: get_current ( ) ;
101- total_rvr -= current_rvr;
102- while ( start_count. wrapping_sub ( SYST :: get_current ( ) ) % MAX_SYSTICK ) < current_rvr { }
104+ total_ticks -= current_ticks;
105+
106+ // Use the wrapping substraction and the modulo to deal with the systick wrapping around
107+ // from 0 to 0xFFFF
108+ while ( start_count. wrapping_sub ( SYST :: get_current ( ) ) % SYSTICK_RANGE ) < current_ticks { }
103109 }
104110 }
105111}
0 commit comments