Skip to content

Commit 8326eac

Browse files
committed
systick: System time counter based on Timer(systick)
1 parent 3660505 commit 8326eac

File tree

2 files changed

+116
-0
lines changed

2 files changed

+116
-0
lines changed

src/lib.rs

Lines changed: 2 additions & 0 deletions
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

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
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 as_nanos(&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 as_micros(&self) -> u64 {
66+
self.as_nanos() / 1_000_000
67+
}
68+
/// return time in ms
69+
pub fn as_millis(&self) -> u64 {
70+
self.as_nanos() / 1_000_000
71+
}
72+
/// return time in seconds, as f64
73+
pub fn as_secs_f64(&self) -> f64 {
74+
self.as_nanos() as f64 / 1_000_000_000f64
75+
}
76+
/// return time in seconds, as f32
77+
pub fn as_secs_f32(&self) -> f32 {
78+
self.as_nanos() as f32 / 1_000_000_000f32
79+
}
80+
81+
/// delay n ns
82+
/// note: this function depends on the systick interrupt,
83+
/// so do not use it from other interrupts (with higher priority).
84+
fn delay_ns_(&self, ns: u64) {
85+
let timeout = self.as_nanos() + ns;
86+
while timeout >= self.as_nanos() {}
87+
}
88+
}
89+
// Implement DelayUs/DelayMs for various integer types
90+
macro_rules! impl_DelayIntT {
91+
(for $($t:ty),+) => {$(
92+
impl DelayMs<$t> for SysTime {
93+
fn delay_ms(&mut self, ms: $t) {
94+
self.delay_ns_(ms as u64 * 1_000_000);
95+
}
96+
}
97+
impl DelayUs<$t> for SysTime {
98+
fn delay_us(&mut self, us: $t) {
99+
self.delay_ns_(us as u64 * 1_000);
100+
}
101+
}
102+
)*}
103+
}
104+
impl_DelayIntT!(for usize,u64,u32,u16,u8,i64,i32,i16,i8);
105+
106+
// there can only be one!
107+
#[exception]
108+
fn SysTick() {
109+
free(|_| unsafe {
110+
if let Some(systime) = &mut SYSTIME {
111+
systime.systick += 1;
112+
}
113+
});
114+
}

0 commit comments

Comments
 (0)