1
1
//! API for delays with the systick timer
2
2
//!
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.
5
5
//!
6
6
//! Consider using the timers api as a more flexible interface
7
7
//!
@@ -35,27 +35,31 @@ use embedded_hal::blocking::delay::{DelayMs, DelayUs};
35
35
/// System timer (SysTick) as a delay provider
36
36
#[ derive( Clone ) ]
37
37
pub struct Delay {
38
- clocks : Clocks ,
38
+ scale : u32 ,
39
39
}
40
40
41
- const MAX_SYSTICK : u32 = 0x00FF_FFFF ;
41
+ const SYSTICK_RANGE : u32 = 0x0100_0000 ;
42
42
43
43
impl Delay {
44
44
/// 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
47
45
pub fn new ( mut syst : SYST , clocks : Clocks ) -> Delay {
48
46
syst. set_clock_source ( SystClkSource :: Core ) ;
49
47
50
- syst. set_reload ( MAX_SYSTICK ) ;
48
+ syst. set_reload ( SYSTICK_RANGE - 1 ) ;
51
49
syst. clear_current ( ) ;
52
50
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
54
57
}
55
58
}
56
59
57
60
impl 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
59
63
fn delay_ms ( & mut self , mut ms : u32 ) {
60
64
const MAX_MS : u32 = 0x0000_FFFF ;
61
65
while ms != 0 {
@@ -68,7 +72,9 @@ impl DelayMs<u32> for Delay {
68
72
69
73
impl DelayMs < u16 > for Delay {
70
74
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 ) ;
72
78
}
73
79
}
74
80
@@ -78,28 +84,28 @@ impl DelayMs<u8> for Delay {
78
84
}
79
85
}
80
86
87
+ // At 48MHz (the maximum frequency), this overflows at approx. 2^32 / 48 = 89 seconds
81
88
impl DelayUs < u32 > for Delay {
82
89
fn delay_us ( & mut self , us : u32 ) {
83
90
// The SysTick Reload Value register supports values between 1 and 0x00FFFFFF.
84
91
// 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 ;
86
93
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 ;
92
95
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
96
99
} else {
97
- MAX_RVR
100
+ MAX_TICKS
98
101
} ;
99
102
100
103
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 { }
103
109
}
104
110
}
105
111
}
0 commit comments