@ -1,7 +1,7 @@
//! API for delays with the systick timer
//!
//! Please be aware of potential overflows.
//! For example, the maximum delay with 48MHz is around 89 seconds
//! Please be aware of potential overflows when using `delay_us` .
//! E.g. at 48MHz the maximum delay is 89 seconds.
//!
//! Consider using the timers api as a more flexible interface
//!
@ -35,27 +35,31 @@ use embedded_hal::blocking::delay::{DelayMs, DelayUs};
/// System timer (SysTick) as a delay provider
#[ derive(Clone) ]
pub struct Delay {
clocks : Clocks ,
scale : u32 ,
}
const MAX_ SYSTICK : u32 = 0x00FF_FFFF ;
const SYSTICK_RANGE : u32 = 0x0100_0000 ;
impl Delay {
/// Configures the system timer (SysTick) as a delay provider
/// As access to the count register is possible without a reference, we can
/// just drop it
pub fn new ( mut syst : SYST , clocks : Clocks ) -> Delay {
syst . set_clock_source ( SystClkSource ::Core ) ;
syst . set_reload ( MAX_ SYSTICK) ;
syst . set_reload ( SYSTICK_RANGE - 1 ) ;
syst . clear_current ( ) ;
syst . enable_counter ( ) ;
Delay { clocks }
assert! ( clocks . hclk ( ) . 0 > = 1_000_000 ) ;
let scale = clocks . hclk ( ) . 0 / 1_000_000 ;
Delay { scale }
// As access to the count register is possible without a reference to the systick, we can
// just drop it
}
}
impl DelayMs < u32 > for Delay {
// At 48 MHz, calling delay_us with ms * 1_000 directly overflows at 0x15D868 (just over the max u16 value)
// At 48 MHz (the maximum frequency), calling delay_us with ms * 1_000 directly overflows at 0x15D86 (just over the max u16 value)
// So we implement a separate, higher level, delay loop
fn delay_ms ( & mut self , mut ms : u32 ) {
const MAX_MS : u32 = 0x0000_FFFF ;
while ms ! = 0 {
@ -68,7 +72,9 @@ impl DelayMs<u32> for Delay {
impl DelayMs < u16 > for Delay {
fn delay_ms ( & mut self , ms : u16 ) {
self . delay_us ( u32 ::from ( ms ) * 1_000 ) ;
// Call delay_us directly, so we don't have to use the additional
// delay loop the u32 variant uses
self . delay_us ( u32 ( ms ) * 1_000 ) ;
}
}
@ -78,28 +84,28 @@ impl DelayMs<u8> for Delay {
}
}
// At 48MHz (the maximum frequency), this overflows at approx. 2^32 / 48 = 89 seconds
impl DelayUs < u32 > for Delay {
fn delay_us ( & mut self , us : u32 ) {
// The SysTick Reload Value register supports values between 1 and 0x00FFFFFF.
// Here less than maximum is used so we have some play if there's a long running interrupt.
const MAX_RVR : u32 = 0x007F_FFFF ;
const MAX_TICKS : u32 = 0x007F_FFFF ;
let mut total_rvr = if self . clocks . sysclk ( ) . 0 < 1_000_000 {
us / ( 1_000_000 / self . clocks . sysclk ( ) . 0 )
} else {
us * ( self . clocks . sysclk ( ) . 0 / 1_000_000 )
} ;
let mut total_ticks = us * self . scale ;
while total_rvr ! = 0 {
let current_rvr = if total_rvr < = MAX_RVR {
total_rvr
while total_ticks ! = 0 {
let current_ticks = if total_ticks < = MAX_TICKS {
total_ticks
} else {
MAX_RVR
MAX_TICKS
} ;
let start_count = SYST ::get_current ( ) ;
total_rvr - = current_rvr ;
while ( start_count . wrapping_sub ( SYST ::get_current ( ) ) % MAX_SYSTICK ) < current_rvr { }
total_ticks - = current_ticks ;
// Use the wrapping substraction and the modulo to deal with the systick wrapping around
// from 0 to 0xFFFF
while ( start_count . wrapping_sub ( SYST ::get_current ( ) ) % SYSTICK_RANGE ) < current_ticks { }
}
}
}