Skip to content

Commit 0d3352e

Browse files
committed
systick: System time counter based on Timer(systick)
1 parent 36ad03a commit 0d3352e

File tree

2 files changed

+112
-0
lines changed

2 files changed

+112
-0
lines changed

src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,8 @@ pub mod signature;
176176
#[cfg(feature = "device-selected")]
177177
pub mod spi;
178178
#[cfg(feature = "device-selected")]
179+
pub mod systick;
180+
#[cfg(feature = "device-selected")]
179181
pub mod time;
180182
#[cfg(feature = "device-selected")]
181183
pub mod timer;

src/systick.rs

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
//! SYSTEMTIME based on systick
2+
3+
use cortex_m::interrupt::free;
4+
use cortex_m::peripheral::SYST;
5+
use cortex_m_rt::exception;
6+
7+
use crate::rcc::Clocks;
8+
use crate::time::Hertz;
9+
use crate::timer::{Event, Timer};
10+
11+
use embedded_hal::blocking::delay::{DelayMs, DelayUs};
12+
13+
pub trait SysTickTime {
14+
fn to_systemtime<T>(self, timeout: T, clocks: Clocks) -> SysTime
15+
where
16+
T: Into<Hertz>;
17+
}
18+
impl SysTickTime for SYST {
19+
fn to_systemtime<T>(self, timeout_hz: T, clocks: Clocks) -> SysTime
20+
where
21+
T: Into<Hertz>,
22+
{
23+
let timeout_hz = timeout_hz.into();
24+
25+
let mut systime = SysTickTimeStatic {
26+
countdown: Timer::syst(self, timeout_hz, clocks),
27+
systick: 0,
28+
tick_to_ns: 1_000_000_000 / timeout_hz.0,
29+
};
30+
31+
systime.countdown.listen(Event::TimeOut);
32+
33+
free(|_| unsafe {
34+
SYSTIME = Some(systime);
35+
});
36+
37+
SysTime {}
38+
}
39+
}
40+
41+
struct SysTickTimeStatic {
42+
countdown: Timer<SYST>,
43+
systick: u64,
44+
tick_to_ns: u32,
45+
}
46+
47+
// there can only be one!
48+
static mut SYSTIME: Option<SysTickTimeStatic> = None;
49+
50+
pub struct SysTime {}
51+
impl SysTime {
52+
/// return time in ns
53+
pub fn ns(&self) -> u64 {
54+
let mut tick_to_ns = 0u32;
55+
free(|_| unsafe {
56+
if let Some(systime) = &SYSTIME {
57+
tick_to_ns = systime.tick_to_ns;
58+
(&systime.systick as *const u64).read_volatile()
59+
} else {
60+
0
61+
}
62+
}) * tick_to_ns as u64
63+
}
64+
/// return time in us
65+
pub fn us(&self) -> u64 {
66+
self.ns() / 1_000_000
67+
}
68+
/// return time in ms
69+
pub fn ms(&self) -> u64 {
70+
self.ns() / 1_000_000
71+
}
72+
/// return time in seconds, as double
73+
pub fn s(&self) -> f64 {
74+
self.ns() as f64 / 1_000_000_000f64
75+
}
76+
77+
/// delay n ns
78+
/// note: this function depends on the systick interrupt,
79+
/// so do not use it from other interrupts (with higher priority).
80+
fn delay_ns_(&self, ns: u64) {
81+
let timeout = self.ns() + ns;
82+
while timeout >= self.ns() {}
83+
}
84+
}
85+
// Implement DelayUs/DelayMs for various integer types
86+
macro_rules! impl_DelayIntT {
87+
(for $($t:ty),+) => {$(
88+
impl DelayMs<$t> for SysTime {
89+
fn delay_ms(&mut self, ms: $t) {
90+
self.delay_ns_(ms as u64 * 1_000_000);
91+
}
92+
}
93+
impl DelayUs<$t> for SysTime {
94+
fn delay_us(&mut self, us: $t) {
95+
self.delay_ns_(us as u64 * 1_000);
96+
}
97+
}
98+
)*}
99+
}
100+
impl_DelayIntT!(for usize,u64,u32,u16,u8,i64,i32,i16,i8);
101+
102+
// there can only be one!
103+
#[exception]
104+
fn SysTick() {
105+
free(|_| unsafe {
106+
if let Some(systime) = &mut SYSTIME {
107+
systime.systick += 1;
108+
}
109+
});
110+
}

0 commit comments

Comments
 (0)