| 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 | |