stm32f1_hal/timer/
syst.rs

1//! SysTick: System Timer
2
3use super::*;
4use crate::{
5    Mcu,
6    fugit::{HertzU32, KilohertzU32, TimerDurationU32, TimerInstantU32},
7    prelude::*,
8    rcc,
9};
10use core::{
11    ops::{Deref, DerefMut},
12    sync::atomic::{AtomicU8, Ordering},
13};
14use cortex_m::peripheral::{SYST, syst::SystClkSource};
15
16pub trait SysTimerInit: Sized {
17    /// Creates timer which takes [HertzU32] as Duration
18    fn counter_hz(self, mcu: &Mcu) -> SysCounterHz;
19    /// Creates timer with custom precision (core frequency recommended is known)
20    fn counter<const FREQ: u32>(self, mcu: &Mcu) -> SysCounter<FREQ>;
21    /// Creates timer with precision of 1 μs (1 MHz sampling)
22    fn counter_us(self, mcu: &Mcu) -> SysCounterUs {
23        self.counter::<1_000_000>(mcu)
24    }
25    /// Only initialize `SysTickInstant`.
26    /// It's useful when the sys tick has been enabled by other program.
27    fn init_sys_tick_instant(self);
28}
29
30impl SysTimerInit for SYST {
31    fn counter_hz(self, mcu: &Mcu) -> SysCounterHz {
32        SystemTimer::syst(self, mcu).counter_hz()
33    }
34    fn counter<const FREQ: u32>(self, mcu: &Mcu) -> SysCounter<FREQ> {
35        SystemTimer::syst(self, mcu).counter()
36    }
37    fn init_sys_tick_instant(mut self) {
38        let factor = match self.get_clock_source() {
39            SystClkSource::Core => 0,
40            SystClkSource::External => 3, // frequency >> 3
41        };
42        FACTOR.store(factor, Ordering::Relaxed);
43    }
44}
45
46pub struct SystemTimer {
47    pub(super) syst: SYST,
48    pub(super) clk: HertzU32,
49}
50impl SystemTimer {
51    /// Initialize SysTick timer
52    pub fn syst(mut syst: SYST, mcu: &Mcu) -> Self {
53        syst.set_clock_source(SystClkSource::Core);
54        let clk = mcu.rcc.clocks().hclk();
55        FACTOR.store(0, Ordering::Relaxed);
56        Self { syst, clk }
57    }
58
59    /// Initialize SysTick timer and set it frequency to `HCLK / 8`
60    pub fn syst_external(mut syst: SYST, mcu: &Mcu) -> Self {
61        syst.set_clock_source(SystClkSource::External);
62        let clk = mcu.rcc.clocks().hclk() / 8;
63        FACTOR.store(3, Ordering::Relaxed); // frequency >> 3
64        Self { syst, clk }
65    }
66
67    pub fn release(self) -> SYST {
68        self.syst
69    }
70
71    /// Starts listening for an `event`
72    pub fn listen(&mut self, event: SysEvent) {
73        match event {
74            SysEvent::Update => self.syst.enable_interrupt(),
75        }
76    }
77
78    /// Stops listening for an `event`
79    pub fn unlisten(&mut self, event: SysEvent) {
80        match event {
81            SysEvent::Update => self.syst.disable_interrupt(),
82        }
83    }
84
85    /// Resets the counter
86    pub fn reset(&mut self) {
87        // According to the Cortex-M3 Generic User Guide, the interrupt request is only generated
88        // when the counter goes from 1 to 0, so writing zero should not trigger an interrupt
89        self.syst.clear_current();
90    }
91}
92
93// Counter --------------------------------------------------------------------
94
95impl SystemTimer {
96    /// Creates [SysCounterHz] which takes [HertzU32] as Duration
97    pub fn counter_hz(self) -> SysCounterHz {
98        SysCounterHz(self)
99    }
100
101    /// Creates [SysCounter] with custom precision (core frequency recommended is known)
102    pub fn counter<const FREQ: u32>(self) -> SysCounter<FREQ> {
103        SysCounter(self)
104    }
105
106    /// Creates [SysCounter] 1 microsecond precision
107    pub fn counter_us(self) -> SysCounterUs {
108        SysCounter(self)
109    }
110}
111
112/// Hardware timers
113pub struct SysCounterHz(SystemTimer);
114
115impl Deref for SysCounterHz {
116    type Target = SystemTimer;
117    fn deref(&self) -> &Self::Target {
118        &self.0
119    }
120}
121
122impl DerefMut for SysCounterHz {
123    fn deref_mut(&mut self) -> &mut Self::Target {
124        &mut self.0
125    }
126}
127
128impl SysCounterHz {
129    pub fn start(&mut self, timeout: HertzU32) -> Result<(), Error> {
130        let rvr = self.clk.raw() / timeout.raw() - 1;
131
132        if rvr >= (1 << 24) {
133            return Err(Error::WrongAutoReload);
134        }
135
136        self.syst.set_reload(rvr);
137        self.syst.clear_current();
138        self.syst.enable_counter();
139
140        Ok(())
141    }
142
143    pub fn wait(&mut self) -> nb::Result<(), Error> {
144        if self.syst.has_wrapped() {
145            Ok(())
146        } else {
147            Err(nb::Error::WouldBlock)
148        }
149    }
150
151    pub fn cancel(&mut self) -> Result<(), Error> {
152        if !self.syst.is_counter_enabled() {
153            return Err(Error::Disabled);
154        }
155
156        self.syst.disable_counter();
157        Ok(())
158    }
159}
160
161pub type SysCounterUs = SysCounter<1_000_000>;
162
163/// SysTick timer with precision of 1 μs (1 MHz sampling)
164pub struct SysCounter<const FREQ: u32>(SystemTimer);
165
166impl<const FREQ: u32> Deref for SysCounter<FREQ> {
167    type Target = SystemTimer;
168    fn deref(&self) -> &Self::Target {
169        &self.0
170    }
171}
172
173impl<const FREQ: u32> DerefMut for SysCounter<FREQ> {
174    fn deref_mut(&mut self) -> &mut Self::Target {
175        &mut self.0
176    }
177}
178
179impl<const FREQ: u32> SysCounter<FREQ> {
180    /// Starts listening for an `event`
181    pub fn listen(&mut self, event: SysEvent) {
182        match event {
183            SysEvent::Update => self.syst.enable_interrupt(),
184        }
185    }
186
187    /// Stops listening for an `event`
188    pub fn unlisten(&mut self, event: SysEvent) {
189        match event {
190            SysEvent::Update => self.syst.disable_interrupt(),
191        }
192    }
193
194    pub fn now(&self) -> TimerInstantU32<FREQ> {
195        TimerInstantU32::from_ticks(SYST::get_current() / (self.clk.raw() / FREQ))
196    }
197
198    pub fn start(&mut self, timeout: TimerDurationU32<FREQ>) -> Result<(), Error> {
199        let rvr = timeout.ticks() * (self.clk.raw() / FREQ) - 1;
200
201        if rvr >= (1 << 24) {
202            return Err(Error::WrongAutoReload);
203        }
204
205        self.syst.set_reload(rvr);
206        self.syst.clear_current();
207        self.syst.enable_counter();
208
209        Ok(())
210    }
211
212    pub fn wait(&mut self) -> nb::Result<(), Error> {
213        if self.syst.has_wrapped() {
214            Ok(())
215        } else {
216            Err(nb::Error::WouldBlock)
217        }
218    }
219
220    pub fn cancel(&mut self) -> Result<(), Error> {
221        if !self.syst.is_counter_enabled() {
222            return Err(Error::Disabled);
223        }
224
225        self.syst.disable_counter();
226        Ok(())
227    }
228}
229
230// ----------------------------------------------------------------------------
231
232/// A `TickInstant` implementation
233#[derive(Copy, Clone)]
234pub struct SysTickInstant {
235    tick: u32,
236}
237
238static FACTOR: AtomicU8 = AtomicU8::new(0);
239
240impl TickInstant for SysTickInstant {
241    fn frequency() -> KilohertzU32 {
242        // `frequency` or `frequency >> 3`
243        KilohertzU32::from_raw(rcc::get_clocks().hclk().to_kHz() >> FACTOR.load(Ordering::Relaxed))
244    }
245
246    #[inline(always)]
247    fn now() -> Self {
248        Self {
249            tick: SYST::get_current(),
250        }
251    }
252
253    #[inline(always)]
254    fn tick_since(self, earlier: Self) -> u32 {
255        if self.tick <= earlier.tick {
256            earlier.tick - self.tick
257        } else {
258            earlier.tick + (SYST::get_reload() - self.tick + 1)
259        }
260    }
261}