stm32f1_hal/timer/
syst.rs

1//! SysTick: System Timer
2
3use super::*;
4use crate::{Mcu, os::*, time::Hertz};
5use core::ops::{Deref, DerefMut};
6use cortex_m::peripheral::{SYST, syst::SystClkSource};
7use embedded_hal::delay::DelayNs;
8use fugit::{ExtU32Ceil, MicrosDurationU32, TimerDurationU32, TimerInstantU32};
9
10pub trait SysTimerInit: Sized {
11    /// Creates timer which takes [Hertz] as Duration
12    fn counter_hz(self, mcu: &Mcu) -> SysCounterHz;
13
14    /// Creates timer with custom precision (core frequency recommended is known)
15    fn counter<const FREQ: u32>(self, mcu: &Mcu) -> SysCounter<FREQ>;
16    /// Creates timer with precision of 1 μs (1 MHz sampling)
17    fn counter_us(self, mcu: &Mcu) -> SysCounterUs {
18        self.counter::<1_000_000>(mcu)
19    }
20    /// Blocking [Delay] with custom precision
21    fn delay(self, mcu: &Mcu) -> SysDelay;
22}
23
24impl SysTimerInit for SYST {
25    fn counter_hz(self, mcu: &Mcu) -> SysCounterHz {
26        SystemTimer::syst(self, mcu).counter_hz()
27    }
28    fn counter<const FREQ: u32>(self, mcu: &Mcu) -> SysCounter<FREQ> {
29        SystemTimer::syst(self, mcu).counter()
30    }
31    fn delay(self, mcu: &Mcu) -> SysDelay {
32        SystemTimer::syst_external(self, mcu).delay()
33    }
34}
35
36pub struct SystemTimer {
37    pub(super) syst: SYST,
38    pub(super) clk: Hertz,
39}
40impl SystemTimer {
41    /// Initialize SysTick timer
42    pub fn syst(mut syst: SYST, mcu: &Mcu) -> Self {
43        syst.set_clock_source(SystClkSource::Core);
44        Self {
45            syst,
46            clk: mcu.rcc.clocks.hclk(),
47        }
48    }
49
50    /// Initialize SysTick timer and set it frequency to `HCLK / 8`
51    pub fn syst_external(mut syst: SYST, mcu: &Mcu) -> Self {
52        syst.set_clock_source(SystClkSource::External);
53        Self {
54            syst,
55            clk: mcu.rcc.clocks.hclk() / 8,
56        }
57    }
58
59    pub fn release(self) -> SYST {
60        self.syst
61    }
62
63    /// Starts listening for an `event`
64    pub fn listen(&mut self, event: SysEvent) {
65        match event {
66            SysEvent::Update => self.syst.enable_interrupt(),
67        }
68    }
69
70    /// Stops listening for an `event`
71    pub fn unlisten(&mut self, event: SysEvent) {
72        match event {
73            SysEvent::Update => self.syst.disable_interrupt(),
74        }
75    }
76
77    /// Resets the counter
78    pub fn reset(&mut self) {
79        // According to the Cortex-M3 Generic User Guide, the interrupt request is only generated
80        // when the counter goes from 1 to 0, so writing zero should not trigger an interrupt
81        self.syst.clear_current();
82    }
83}
84
85// Counter --------------------------------------------------------------------
86
87impl SystemTimer {
88    /// Creates [SysCounterHz] which takes [Hertz] as Duration
89    pub fn counter_hz(self) -> SysCounterHz {
90        SysCounterHz(self)
91    }
92
93    /// Creates [SysCounter] with custom precision (core frequency recommended is known)
94    pub fn counter<const FREQ: u32>(self) -> SysCounter<FREQ> {
95        SysCounter(self)
96    }
97
98    /// Creates [SysCounter] 1 microsecond precision
99    pub fn counter_us(self) -> SysCounterUs {
100        SysCounter(self)
101    }
102}
103
104/// Hardware timers
105pub struct SysCounterHz(SystemTimer);
106
107impl Deref for SysCounterHz {
108    type Target = SystemTimer;
109    fn deref(&self) -> &Self::Target {
110        &self.0
111    }
112}
113
114impl DerefMut for SysCounterHz {
115    fn deref_mut(&mut self) -> &mut Self::Target {
116        &mut self.0
117    }
118}
119
120impl SysCounterHz {
121    pub fn start(&mut self, timeout: Hertz) -> Result<(), Error> {
122        let rvr = self.clk.raw() / timeout.raw() - 1;
123
124        if rvr >= (1 << 24) {
125            return Err(Error::WrongAutoReload);
126        }
127
128        self.syst.set_reload(rvr);
129        self.syst.clear_current();
130        self.syst.enable_counter();
131
132        Ok(())
133    }
134
135    pub fn wait(&mut self) -> nb::Result<(), Error> {
136        if self.syst.has_wrapped() {
137            Ok(())
138        } else {
139            Err(nb::Error::WouldBlock)
140        }
141    }
142
143    pub fn cancel(&mut self) -> Result<(), Error> {
144        if !self.syst.is_counter_enabled() {
145            return Err(Error::Disabled);
146        }
147
148        self.syst.disable_counter();
149        Ok(())
150    }
151}
152
153pub type SysCounterUs = SysCounter<1_000_000>;
154
155/// SysTick timer with precision of 1 μs (1 MHz sampling)
156pub struct SysCounter<const FREQ: u32>(SystemTimer);
157
158impl<const FREQ: u32> Deref for SysCounter<FREQ> {
159    type Target = SystemTimer;
160    fn deref(&self) -> &Self::Target {
161        &self.0
162    }
163}
164
165impl<const FREQ: u32> DerefMut for SysCounter<FREQ> {
166    fn deref_mut(&mut self) -> &mut Self::Target {
167        &mut self.0
168    }
169}
170
171impl<const FREQ: u32> SysCounter<FREQ> {
172    /// Starts listening for an `event`
173    pub fn listen(&mut self, event: SysEvent) {
174        match event {
175            SysEvent::Update => self.syst.enable_interrupt(),
176        }
177    }
178
179    /// Stops listening for an `event`
180    pub fn unlisten(&mut self, event: SysEvent) {
181        match event {
182            SysEvent::Update => self.syst.disable_interrupt(),
183        }
184    }
185
186    pub fn now(&self) -> TimerInstantU32<FREQ> {
187        TimerInstantU32::from_ticks(SYST::get_current() / (self.clk.raw() / FREQ))
188    }
189
190    pub fn start(&mut self, timeout: TimerDurationU32<FREQ>) -> Result<(), Error> {
191        let rvr = timeout.ticks() * (self.clk.raw() / FREQ) - 1;
192
193        if rvr >= (1 << 24) {
194            return Err(Error::WrongAutoReload);
195        }
196
197        self.syst.set_reload(rvr);
198        self.syst.clear_current();
199        self.syst.enable_counter();
200
201        Ok(())
202    }
203
204    pub fn wait(&mut self) -> nb::Result<(), Error> {
205        if self.syst.has_wrapped() {
206            Ok(())
207        } else {
208            Err(nb::Error::WouldBlock)
209        }
210    }
211
212    pub fn cancel(&mut self) -> Result<(), Error> {
213        if !self.syst.is_counter_enabled() {
214            return Err(Error::Disabled);
215        }
216
217        self.syst.disable_counter();
218        Ok(())
219    }
220}
221
222impl<const FREQ: u32> fugit_timer::Timer<FREQ> for SysCounter<FREQ> {
223    type Error = Error;
224
225    fn now(&mut self) -> TimerInstantU32<FREQ> {
226        Self::now(self)
227    }
228
229    fn start(&mut self, duration: TimerDurationU32<FREQ>) -> Result<(), Self::Error> {
230        self.start(duration)
231    }
232
233    fn wait(&mut self) -> nb::Result<(), Self::Error> {
234        self.wait()
235    }
236
237    fn cancel(&mut self) -> Result<(), Self::Error> {
238        self.cancel()
239    }
240}
241
242// Delay ----------------------------------------------------------------------
243
244/// Timer as a delay provider (SysTick by default)
245pub struct SysDelay(SystemTimer);
246
247impl Deref for SysDelay {
248    type Target = SystemTimer;
249    fn deref(&self) -> &Self::Target {
250        &self.0
251    }
252}
253
254impl DerefMut for SysDelay {
255    fn deref_mut(&mut self) -> &mut Self::Target {
256        &mut self.0
257    }
258}
259
260impl SysDelay {
261    /// Releases the timer resource
262    pub fn release(self) -> SystemTimer {
263        self.0
264    }
265}
266
267impl SystemTimer {
268    pub fn delay(self) -> SysDelay {
269        SysDelay(self)
270    }
271}
272
273impl SysDelay {
274    pub fn delay(&mut self, us: MicrosDurationU32) {
275        // The SysTick Reload Value register supports values between 1 and 0x00FFFFFF.
276        const MAX_RVR: u32 = 0x00FF_FFFF;
277
278        let mut total_rvr = us.ticks() * (self.clk.raw() / 1_000_000);
279
280        while total_rvr != 0 {
281            let current_rvr = total_rvr.min(MAX_RVR);
282
283            self.syst.set_reload(current_rvr);
284            self.syst.clear_current();
285            self.syst.enable_counter();
286
287            // Update the tracking variable while we are waiting...
288            total_rvr -= current_rvr;
289
290            while !self.syst.has_wrapped() {}
291
292            self.syst.disable_counter();
293        }
294    }
295}
296
297impl fugit_timer::Delay<1_000_000> for SysDelay {
298    type Error = core::convert::Infallible;
299
300    fn delay(&mut self, duration: MicrosDurationU32) -> Result<(), Self::Error> {
301        self.delay(duration);
302        Ok(())
303    }
304}
305
306impl DelayNs for SysDelay {
307    fn delay_ns(&mut self, ns: u32) {
308        self.delay(ns.nanos_at_least());
309    }
310
311    fn delay_ms(&mut self, ms: u32) {
312        self.delay(ms.millis_at_least());
313    }
314}
315
316// ----------------------------------------------------------------------------
317
318/// SysTick must be set to 1 kHz frequency
319pub struct SysTickTimeout {
320    timeout_us: usize,
321}
322impl SysTickTimeout {
323    pub fn new(timeout_us: usize) -> Self {
324        Self { timeout_us }
325    }
326}
327impl Timeout for SysTickTimeout {
328    fn start(&mut self) -> impl TimeoutInstance {
329        let now = SYST::get_current() as usize;
330        let reload = SYST::get_reload() as usize;
331        let round = self.timeout_us / 1000;
332        let us = self.timeout_us % 1000;
333
334        SysTickTimeoutInstance {
335            former_tick: now,
336            timeout_tick: us * reload / 1000,
337            elapsed_tick: 0,
338            round_backup: round,
339            round,
340        }
341    }
342}
343
344pub struct SysTickTimeoutInstance {
345    former_tick: usize,
346    timeout_tick: usize,
347    elapsed_tick: usize,
348    round: usize,
349    round_backup: usize,
350}
351impl SysTickTimeoutInstance {
352    fn elapsed(&mut self) -> usize {
353        let now = SYST::get_current() as usize;
354        let elapsed = if now <= self.former_tick {
355            self.former_tick - now
356        } else {
357            self.former_tick + (SYST::get_reload() as usize - now)
358        };
359        self.former_tick = now;
360        elapsed
361    }
362}
363impl TimeoutInstance for SysTickTimeoutInstance {
364    fn timeout(&mut self) -> bool {
365        self.elapsed_tick += self.elapsed();
366
367        if self.round == 0 {
368            if self.elapsed_tick >= self.timeout_tick {
369                self.elapsed_tick -= self.timeout_tick;
370                self.round = self.round_backup;
371                return true;
372            }
373        } else {
374            let reload = SYST::get_reload() as usize;
375            if self.elapsed_tick >= reload {
376                self.elapsed_tick -= reload;
377                self.round -= 1;
378            }
379        }
380        false
381    }
382
383    #[inline(always)]
384    fn restart(&mut self) {
385        self.round = self.round_backup;
386        self.elapsed_tick = 0;
387    }
388
389    #[inline(always)]
390    fn interval(&self) {}
391}