embedded_c_sdk_bind_hal/
tick.rs1use crate::ll_api::ll_cmd::*;
2use embedded_hal::delay::DelayNs;
3use fugit::{Duration, TimerDurationU32};
4use portable_atomic::{AtomicU32, Ordering};
5
6pub const TICK_FREQ_HZ: u32 = crate::tick_freq_hz::TICK_FREQ_HZ;
7
8#[cfg(not(feature = "tick-size-64bit"))]
9pub type TickType = u32;
10#[cfg(feature = "tick-size-64bit")]
11pub type TickType = u64;
12
13static SYS_TICK_0: AtomicU32 = AtomicU32::new(0);
14#[cfg(feature = "tick-size-64bit")]
15static SYS_TICK_1: AtomicU32 = AtomicU32::new(0);
16
17pub trait HalTickHandler {
18 unsafe fn on_sys_tick_interrupt();
19}
20
21impl HalTickHandler for Tick {
22 #[inline]
26 unsafe fn on_sys_tick_interrupt() {
27 #[cfg(any(feature = "tick-size-64bit", feature = "embassy"))]
29 let sys_tick = SYS_TICK_0.fetch_add(1, Ordering::Relaxed);
30
31 #[cfg(not(any(feature = "tick-size-64bit", feature = "embassy")))]
33 SYS_TICK_0.add(1, Ordering::Relaxed);
34
35 #[cfg(feature = "tick-size-64bit")]
37 let sys_tick = if sys_tick == u32::MAX {
38 let tick_1 = SYS_TICK_1.fetch_add(1, Ordering::Release);
39 ((tick_1 as u64) << 32) | (sys_tick as u64)
40 } else {
41 let tick_1 = SYS_TICK_1.load(Ordering::Relaxed);
42 ((tick_1 as u64) << 32) | (sys_tick as u64)
43 };
44
45 #[cfg(feature = "embassy")]
47 tick_time_driver::check_alarm(sys_tick);
48 }
49}
50
51#[unsafe(no_mangle)]
55unsafe extern "C" fn sys_tick_inc() {
56 unsafe { Tick::on_sys_tick_interrupt() };
57}
58
59#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Default)]
63pub struct Tick(TickType);
64
65impl Tick {
66 pub fn now() -> Self {
73 #[cfg(feature = "tick-size-64bit")]
75 loop {
76 let t0 = SYS_TICK_1.load(Ordering::SeqCst);
77 let t = SYS_TICK_0.load(Ordering::SeqCst);
78 let t1 = SYS_TICK_1.load(Ordering::SeqCst);
79 if t0 == t1 {
80 break Tick(((t0 as u64) << 32) | (t as u64));
81 }
82 }
83 #[cfg(not(feature = "tick-size-64bit"))]
85 Tick(SYS_TICK_0.load(Ordering::Relaxed))
86 }
87
88 pub fn elapsed(self) -> TickType {
96 if let Some(tick) = Self::now().0.checked_sub(self.0) {
97 tick
98 } else {
99 TickType::MAX
100 }
101 }
102
103 #[inline]
111 pub const fn with_value(value: TickType) -> Self {
112 Tick(value)
113 }
114
115 #[inline]
120 pub fn tick() -> TickType {
121 Self::now().0
122 }
123
124 pub fn elapsed_time(self) -> Duration<TickType, 1, TICK_FREQ_HZ> {
129 let tick = if let Some(res) = Self::now().0.checked_sub(self.0) {
130 res
131 } else {
132 TickType::MAX
133 };
134
135 Duration::<TickType, 1, TICK_FREQ_HZ>::from_ticks(tick)
136 }
137
138 pub fn every(&mut self, duration: TickType) -> bool {
146 let timeout = if let Some(elapsed) = Self::now().0.checked_sub(self.0) {
147 if elapsed >= duration { true } else { false }
148 } else {
149 true
150 };
151
152 if timeout {
153 self.0 = Self::now().0;
154 }
155 return timeout;
156 }
157
158 pub fn reset(&mut self) {
160 self.0 = Self::now().0;
161 }
162}
163
164impl core::ops::Add for Tick {
165 type Output = Self;
166
167 fn add(self, rhs: Self) -> Self::Output {
168 Tick(self.0 + rhs.0)
169 }
170}
171
172impl core::ops::Sub for Tick {
173 type Output = Self;
174
175 fn sub(self, rhs: Self) -> Self::Output {
176 Tick(self.0 - rhs.0)
177 }
178}
179
180#[derive(Debug, Clone, Copy)]
191pub struct Delay;
192
193impl Delay {
194 pub const fn new() -> Self {
201 Delay
202 }
203}
204
205impl DelayNs for Delay {
207 #[inline]
215 fn delay_ns(&mut self, ns: u32) {
216 ll_invoke_inner!(INVOKE_ID_DELAY_NANO, ns);
217 }
218
219 #[cfg(feature = "tick-based-msdelay")]
227 #[inline]
228 fn delay_ms(&mut self, ms: u32) {
229 let ms_tick = TimerDurationU32::<TICK_FREQ_HZ>::millis(ms).ticks();
230 let start = Tick::now();
231 loop {
232 unsafe {
233 core::arch::asm!("wfi");
234 }
235 if (start.elapsed() as u32) >= ms_tick {
236 break;
237 }
238 }
239 }
240}
241
242#[cfg(feature = "embassy")]
243mod tick_time_driver {
244 use core::cell::{Cell, RefCell};
245 use embassy_sync::blocking_mutex::Mutex;
246 use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
247 use embassy_time_driver::Driver;
248 use embassy_time_queue_utils::Queue;
249
250 struct AlarmState {
251 timestamp: Cell<super::TickType>,
252 }
253 unsafe impl Send for AlarmState {}
254
255 struct TimerDriver {
256 alarms: Mutex<CriticalSectionRawMutex, AlarmState>,
257 queue: Mutex<CriticalSectionRawMutex, RefCell<Queue>>,
258 }
259
260 embassy_time_driver::time_driver_impl!(static DRIVER: TimerDriver = TimerDriver{
261 alarms: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState {
262 timestamp: Cell::new(0),
263 }),
264 queue: Mutex::new(RefCell::new(Queue::new()))
265 });
266
267 #[inline(always)]
268 pub fn check_alarm(curr_tick: super::TickType) {
269 DRIVER.check_alarm(curr_tick);
270 }
271
272 impl TimerDriver {
273 fn check_alarm(&self, curr_tick: super::TickType) {
278 critical_section::with(|cs| {
279 let alarm = &self.alarms.borrow(cs);
280 let mut timestamp = alarm.timestamp.get();
281 while timestamp <= curr_tick {
282 let mut queue = self.queue.borrow(cs).borrow_mut();
283 timestamp = queue.next_expiration(curr_tick as u64) as super::TickType; alarm.timestamp.set(timestamp); }
286 });
287 }
288 }
289
290 impl Driver for TimerDriver {
291 fn now(&self) -> u64 {
292 super::Tick::now().0 as u64
293 }
294
295 fn schedule_wake(&self, at: u64, waker: &core::task::Waker) {
296 critical_section::with(|cs| {
297 let mut queue = self.queue.borrow(cs).borrow_mut();
298
299 if queue.schedule_wake(at, waker) {
300 let alarm = &self.alarms.borrow(cs);
301 let now = self.now();
302 loop {
303 let timestamp = queue.next_expiration(now) as super::TickType; alarm.timestamp.set(timestamp); if timestamp > now as super::TickType {
306 break;
307 }
308 }
309 }
310 })
311 }
312 }
313}