lpc8xx_hal/delay.rs
1//! API for delays with the systick timer
2//!
3//! Please be aware of potential overflows when using `delay_us`.
4//! E.g. at 30MHz the maximum delay is 146 seconds.
5//!
6//! # Example
7//!
8//! ``` no_run
9//! use lpc8xx_hal::{
10//! prelude::*,
11//! delay::Delay,
12//! pac::CorePeripherals,
13//! };
14//!
15//! let mut cp = CorePeripherals::take().unwrap();
16//!
17//! let mut delay = Delay::new(cp.SYST);
18//! loop {
19//! delay.delay_ms(1_000_u16);
20//! }
21//! ```
22
23use cortex_m::peripheral::syst::SystClkSource;
24
25use crate::pac::SYST;
26use embedded_hal::blocking::delay::{DelayMs, DelayUs};
27use embedded_hal_alpha::delay::blocking::DelayUs as DelayUsAlpha;
28use void::Void;
29
30const SYSTICK_RANGE: u32 = 0x0100_0000;
31const SYSTEM_CLOCK: u32 = 12_000_000;
32
33/// System timer (SysTick) as a delay provider
34///
35/// # `embedded-hal` traits
36/// - [`embedded_hal::blocking::delay::DelayUs`]
37/// - [`embedded_hal::blocking::delay::DelayMs`]
38///
39/// [`embedded_hal::blocking::delay::DelayUs`]: #impl-DelayUs%3Cu32%3E
40/// [`embedded_hal::blocking::delay::DelayMs`]: #impl-DelayMs%3Cu32%3E
41#[derive(Clone)]
42pub struct Delay {
43 scale: u32,
44}
45
46impl Delay {
47 /// Configures the system timer (SysTick) as a delay provider
48 pub fn new(mut syst: SYST) -> Self {
49 assert!(SYSTEM_CLOCK >= 1_000_000);
50 let scale = SYSTEM_CLOCK / 1_000_000;
51 syst.set_clock_source(SystClkSource::Core);
52
53 syst.set_reload(SYSTICK_RANGE - 1);
54 syst.clear_current();
55 syst.enable_counter();
56
57 Delay { scale }
58 // As access to the count register is possible without a reference to the systick, we can
59 // safely clone the enabled instance.
60 }
61}
62
63impl DelayMs<u32> for Delay {
64 /// Pauses execution for `ms` milliseconds
65 // At 30 MHz (the maximum frequency), calling delay_us with ms * 1_000 directly overflows at 0x418937 (over the max u16 value)
66 // So we implement a separate, higher level, delay loop
67 fn delay_ms(&mut self, mut ms: u32) {
68 const MAX_MS: u32 = 0x0000_FFFF;
69 while ms != 0 {
70 let current_ms = if ms <= MAX_MS { ms } else { MAX_MS };
71 DelayUs::delay_us(self, current_ms * 1_000);
72 ms -= current_ms;
73 }
74 }
75}
76
77impl DelayMs<u16> for Delay {
78 /// Pauses execution for `ms` milliseconds
79 fn delay_ms(&mut self, ms: u16) {
80 // Call delay_us directly, since we don't have to use the additional
81 // delay loop the u32 variant uses
82 DelayUs::delay_us(self, ms as u32 * 1_000);
83 }
84}
85
86impl DelayMs<u8> for Delay {
87 /// Pauses execution for `ms` milliseconds
88 fn delay_ms(&mut self, ms: u8) {
89 DelayMs::delay_ms(self, ms as u16);
90 }
91}
92
93// At 30MHz (the maximum frequency), this overflows at approx. 2^32 / 30 = 146 seconds
94impl DelayUs<u32> for Delay {
95 /// Pauses execution for `us` microseconds
96 fn delay_us(&mut self, us: u32) {
97 // The SysTick Reload Value register supports values between 1 and 0x00FFFFFF.
98 // Here half the maximum is used so we have some play if there's a long running interrupt.
99 const MAX_TICKS: u32 = 0x007F_FFFF;
100
101 let mut total_ticks = us * self.scale;
102
103 while total_ticks != 0 {
104 let current_ticks = if total_ticks <= MAX_TICKS {
105 total_ticks
106 } else {
107 MAX_TICKS
108 };
109
110 let start_count = SYST::get_current();
111 total_ticks -= current_ticks;
112
113 // Use the wrapping subtraction and the modulo to deal with the systick wrapping around
114 // from 0 to 0xFFFF
115 while (start_count.wrapping_sub(SYST::get_current())
116 % SYSTICK_RANGE)
117 < current_ticks
118 {}
119 }
120 }
121}
122
123impl DelayUsAlpha for Delay {
124 type Error = Void;
125
126 /// Pauses execution for `us` microseconds
127 fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> {
128 Ok(DelayUs::delay_us(self, us))
129 }
130}
131
132impl DelayUs<u16> for Delay {
133 /// Pauses execution for `us` microseconds
134 fn delay_us(&mut self, us: u16) {
135 DelayUs::delay_us(self, us as u32)
136 }
137}
138
139impl DelayUs<u8> for Delay {
140 /// Pauses execution for `us` microseconds
141 fn delay_us(&mut self, us: u8) {
142 DelayUs::delay_us(self, us as u32)
143 }
144}