1 | //! A delay driver based on SysTick. |
2 | |
3 | use crate::peripheral::{syst::SystClkSource, SYST}; |
4 | use embedded_hal::blocking::delay::{DelayMs, DelayUs}; |
5 | |
6 | /// System timer (SysTick) as a delay provider. |
7 | pub struct Delay { |
8 | syst: SYST, |
9 | frequency: u32, |
10 | } |
11 | |
12 | impl Delay { |
13 | /// Configures the system timer (SysTick) as a delay provider. |
14 | /// |
15 | /// `ahb_frequency` is a frequency of the AHB bus in Hz. |
16 | #[inline ] |
17 | pub fn new(syst: SYST, ahb_frequency: u32) -> Self { |
18 | Self::with_source(syst, ahb_frequency, SystClkSource::Core) |
19 | } |
20 | |
21 | /// Configures the system timer (SysTick) as a delay provider |
22 | /// with a clock source. |
23 | /// |
24 | /// `frequency` is the frequency of your `clock_source` in Hz. |
25 | #[inline ] |
26 | pub fn with_source(mut syst: SYST, frequency: u32, clock_source: SystClkSource) -> Self { |
27 | syst.set_clock_source(clock_source); |
28 | |
29 | Delay { syst, frequency } |
30 | } |
31 | |
32 | /// Releases the system timer (SysTick) resource. |
33 | #[inline ] |
34 | pub fn free(self) -> SYST { |
35 | self.syst |
36 | } |
37 | |
38 | /// Delay using the Cortex-M systick for a certain duration, in µs. |
39 | #[allow (clippy::missing_inline_in_public_items)] |
40 | pub fn delay_us(&mut self, us: u32) { |
41 | let ticks = (u64::from(us)) * (u64::from(self.frequency)) / 1_000_000; |
42 | |
43 | let full_cycles = ticks >> 24; |
44 | if full_cycles > 0 { |
45 | self.syst.set_reload(0xffffff); |
46 | self.syst.clear_current(); |
47 | self.syst.enable_counter(); |
48 | |
49 | for _ in 0..full_cycles { |
50 | while !self.syst.has_wrapped() {} |
51 | } |
52 | } |
53 | |
54 | let ticks = (ticks & 0xffffff) as u32; |
55 | if ticks > 1 { |
56 | self.syst.set_reload(ticks - 1); |
57 | self.syst.clear_current(); |
58 | self.syst.enable_counter(); |
59 | |
60 | while !self.syst.has_wrapped() {} |
61 | } |
62 | |
63 | self.syst.disable_counter(); |
64 | } |
65 | |
66 | /// Delay using the Cortex-M systick for a certain duration, in ms. |
67 | #[inline ] |
68 | pub fn delay_ms(&mut self, mut ms: u32) { |
69 | // 4294967 is the highest u32 value which you can multiply by 1000 without overflow |
70 | while ms > 4294967 { |
71 | self.delay_us(4294967000u32); |
72 | ms -= 4294967; |
73 | } |
74 | self.delay_us(ms * 1_000); |
75 | } |
76 | } |
77 | |
78 | impl DelayMs<u32> for Delay { |
79 | #[inline ] |
80 | fn delay_ms(&mut self, ms: u32) { |
81 | Delay::delay_ms(self, ms); |
82 | } |
83 | } |
84 | |
85 | // This is a workaround to allow `delay_ms(42)` construction without specifying a type. |
86 | impl DelayMs<i32> for Delay { |
87 | #[inline (always)] |
88 | fn delay_ms(&mut self, ms: i32) { |
89 | assert!(ms >= 0); |
90 | Delay::delay_ms(self, ms as u32); |
91 | } |
92 | } |
93 | |
94 | impl DelayMs<u16> for Delay { |
95 | #[inline (always)] |
96 | fn delay_ms(&mut self, ms: u16) { |
97 | Delay::delay_ms(self, ms:u32::from(ms)); |
98 | } |
99 | } |
100 | |
101 | impl DelayMs<u8> for Delay { |
102 | #[inline (always)] |
103 | fn delay_ms(&mut self, ms: u8) { |
104 | Delay::delay_ms(self, ms:u32::from(ms)); |
105 | } |
106 | } |
107 | |
108 | impl DelayUs<u32> for Delay { |
109 | #[inline ] |
110 | fn delay_us(&mut self, us: u32) { |
111 | Delay::delay_us(self, us); |
112 | } |
113 | } |
114 | |
115 | // This is a workaround to allow `delay_us(42)` construction without specifying a type. |
116 | impl DelayUs<i32> for Delay { |
117 | #[inline (always)] |
118 | fn delay_us(&mut self, us: i32) { |
119 | assert!(us >= 0); |
120 | Delay::delay_us(self, us as u32); |
121 | } |
122 | } |
123 | |
124 | impl DelayUs<u16> for Delay { |
125 | #[inline (always)] |
126 | fn delay_us(&mut self, us: u16) { |
127 | Delay::delay_us(self, us:u32::from(us)) |
128 | } |
129 | } |
130 | |
131 | impl DelayUs<u8> for Delay { |
132 | #[inline (always)] |
133 | fn delay_us(&mut self, us: u8) { |
134 | Delay::delay_us(self, us:u32::from(us)) |
135 | } |
136 | } |
137 | |