Skip to content

Commit 43567a1

Browse files
committed
Add systick timeout implement
1 parent c957298 commit 43567a1

File tree

4 files changed

+154
-49
lines changed

4 files changed

+154
-49
lines changed

examples/f103c8/src/led_task.rs

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,19 @@
11
use crate::embedded_hal::digital::StatefulOutputPin;
2+
use crate::hal::os::TimeoutInstance;
23

3-
pub struct LedTask<P> {
4+
pub struct LedTask<P, T> {
45
led: P,
5-
freq: u32,
6-
count: u32,
6+
timeout: T,
77
}
88

9-
impl<P: StatefulOutputPin> LedTask<P> {
10-
pub fn new(led: P, freq: u32) -> Self {
11-
Self {
12-
led,
13-
freq,
14-
count: 0,
15-
}
9+
impl<P: StatefulOutputPin, T: TimeoutInstance> LedTask<P, T> {
10+
pub fn new(led: P, timeout: T) -> Self {
11+
Self { led, timeout }
1612
}
1713

1814
pub fn poll(&mut self) {
19-
self.count += 1;
20-
if self.count >= self.freq {
15+
if self.timeout.timeout() {
2116
self.led.toggle().ok();
22-
self.count = 0;
2317
}
2418
}
2519
}

examples/f103c8/src/main.rs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ use stm32f1_hal::{
1515
embedded_io,
1616
gpio::{Edge, ExtiPin, PinState},
1717
nvic_scb::PriorityGrouping,
18-
os::RetryTimes,
18+
os::{RetryTimes, Timeout},
1919
pac::{self, Interrupt},
2020
prelude::*,
2121
rcc,
22-
timer::*,
22+
timer::{syst::SysTickTimeout, *},
2323
uart::{self, UartPeriphExt},
2424
};
2525

@@ -105,10 +105,9 @@ fn main() -> ! {
105105
let mut led = gpiob
106106
.pb0
107107
.into_open_drain_output_with_state(&mut gpiob.crl, PinState::High);
108-
let mut timer = cp.SYST.counter_hz(&mcu);
109-
let freq = 100.Hz();
110-
timer.start(freq).unwrap();
111-
let mut led_task = LedTask::new(led, freq.raw());
108+
cp.SYST.counter_hz(&mcu).start(1000.Hz()).unwrap();
109+
let mut timeout = SysTickTimeout::new(1000_000);
110+
let mut led_task = LedTask::new(led, timeout.start());
112111

113112
// PWM --------------------------------------
114113

@@ -140,9 +139,7 @@ fn main() -> ! {
140139
});
141140

142141
loop {
143-
if timer.wait().is_ok() {
144-
led_task.poll();
145-
}
142+
led_task.poll();
146143
uart_task.poll();
147144
}
148145
}

src/common/os.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,12 @@ pub trait Timeout {
1919

2020
pub trait TimeoutInstance {
2121
fn timeout(&mut self) -> bool;
22+
fn restart(&mut self);
2223
fn interval(&self);
2324
}
2425

26+
// Retry ----------------------------------
27+
2528
pub struct RetryTimes {
2629
retry_times: usize,
2730
}
@@ -55,6 +58,40 @@ impl TimeoutInstance for RetryTimesInstance {
5558
}
5659
}
5760

61+
#[inline(always)]
62+
fn restart(&mut self) {
63+
self.count = 0;
64+
}
65+
66+
#[inline(always)]
67+
fn interval(&self) {}
68+
}
69+
70+
// Always ----------------------------------
71+
72+
pub struct AlwaysTimeout {}
73+
impl AlwaysTimeout {
74+
pub fn new() -> Self {
75+
Self {}
76+
}
77+
}
78+
impl Timeout for AlwaysTimeout {
79+
#[inline]
80+
fn start(&mut self) -> impl TimeoutInstance {
81+
AlwaysTimeoutInstance {}
82+
}
83+
}
84+
85+
pub struct AlwaysTimeoutInstance {}
86+
impl TimeoutInstance for AlwaysTimeoutInstance {
87+
#[inline(always)]
88+
fn timeout(&mut self) -> bool {
89+
true
90+
}
91+
92+
#[inline(always)]
93+
fn restart(&mut self) {}
94+
5895
#[inline(always)]
5996
fn interval(&self) {}
6097
}

src/timer/syst.rs

Lines changed: 104 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,38 @@
11
//! SysTick: System Timer
22
33
use super::*;
4-
use crate::{Mcu, time::Hertz};
4+
use crate::{Mcu, os::*, time::Hertz};
55
use core::ops::{Deref, DerefMut};
66
use cortex_m::peripheral::{SYST, syst::SystClkSource};
77
use embedded_hal::delay::DelayNs;
88
use fugit::{ExtU32Ceil, MicrosDurationU32, TimerDurationU32, TimerInstantU32};
99

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+
1036
pub struct SystemTimer {
1137
pub(super) syst: SYST,
1238
pub(super) clk: Hertz,
@@ -56,32 +82,6 @@ impl SystemTimer {
5682
}
5783
}
5884

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-
8585
// Counter --------------------------------------------------------------------
8686

8787
impl SystemTimer {
@@ -312,3 +312,80 @@ impl DelayNs for SysDelay {
312312
self.delay(ms.millis_at_least());
313313
}
314314
}
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

Comments
 (0)