|
1 | 1 | //! SysTick: System Timer |
2 | 2 |
|
3 | 3 | use super::*; |
4 | | -use crate::{Mcu, time::Hertz}; |
| 4 | +use crate::{Mcu, os::*, time::Hertz}; |
5 | 5 | use core::ops::{Deref, DerefMut}; |
6 | 6 | use cortex_m::peripheral::{SYST, syst::SystClkSource}; |
7 | 7 | use embedded_hal::delay::DelayNs; |
8 | 8 | use fugit::{ExtU32Ceil, MicrosDurationU32, TimerDurationU32, TimerInstantU32}; |
9 | 9 |
|
| 10 | +pub 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 | + |
| 24 | +impl 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 | + |
10 | 36 | pub struct SystemTimer { |
11 | 37 | pub(super) syst: SYST, |
12 | 38 | pub(super) clk: Hertz, |
@@ -56,32 +82,6 @@ impl SystemTimer { |
56 | 82 | } |
57 | 83 | } |
58 | 84 |
|
59 | | -pub trait SysTimerInit: Sized { |
60 | | - /// Creates timer which takes [Hertz] as Duration |
61 | | - fn counter_hz(self, mcu: &Mcu) -> SysCounterHz; |
62 | | - |
63 | | - /// Creates timer with custom precision (core frequency recommended is known) |
64 | | - fn counter<const FREQ: u32>(self, mcu: &Mcu) -> SysCounter<FREQ>; |
65 | | - /// Creates timer with precision of 1 μs (1 MHz sampling) |
66 | | - fn counter_us(self, mcu: &Mcu) -> SysCounterUs { |
67 | | - self.counter::<1_000_000>(mcu) |
68 | | - } |
69 | | - /// Blocking [Delay] with custom precision |
70 | | - fn delay(self, mcu: &Mcu) -> SysDelay; |
71 | | -} |
72 | | - |
73 | | -impl SysTimerInit for SYST { |
74 | | - fn counter_hz(self, mcu: &Mcu) -> SysCounterHz { |
75 | | - SystemTimer::syst(self, mcu).counter_hz() |
76 | | - } |
77 | | - fn counter<const FREQ: u32>(self, mcu: &Mcu) -> SysCounter<FREQ> { |
78 | | - SystemTimer::syst(self, mcu).counter() |
79 | | - } |
80 | | - fn delay(self, mcu: &Mcu) -> SysDelay { |
81 | | - SystemTimer::syst_external(self, mcu).delay() |
82 | | - } |
83 | | -} |
84 | | - |
85 | 85 | // Counter -------------------------------------------------------------------- |
86 | 86 |
|
87 | 87 | impl SystemTimer { |
@@ -312,3 +312,80 @@ impl DelayNs for SysDelay { |
312 | 312 | self.delay(ms.millis_at_least()); |
313 | 313 | } |
314 | 314 | } |
| 315 | + |
| 316 | +// ---------------------------------------------------------------------------- |
| 317 | + |
| 318 | +/// SysTick must be set to 1 kHz frequency |
| 319 | +pub struct SysTickTimeout { |
| 320 | + timeout_us: usize, |
| 321 | +} |
| 322 | +impl SysTickTimeout { |
| 323 | + pub fn new(timeout_us: usize) -> Self { |
| 324 | + Self { timeout_us } |
| 325 | + } |
| 326 | +} |
| 327 | +impl 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 | + |
| 344 | +pub struct SysTickTimeoutInstance { |
| 345 | + former_tick: usize, |
| 346 | + timeout_tick: usize, |
| 347 | + elapsed_tick: usize, |
| 348 | + round: usize, |
| 349 | + round_backup: usize, |
| 350 | +} |
| 351 | +impl 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 | +} |
| 363 | +impl 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 | +} |
0 commit comments