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#[no_mangle]
52#[deprecated(since = "0.7.3", note = "Please use `sys_tick_handler!()` instead")]
53unsafe extern "C" fn sys_tick_inc() {
54 Tick::on_sys_tick_interrupt();
55}
56
57#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Default)]
61pub struct Tick(TickType);
62
63impl Tick {
64 pub fn now() -> Self {
71 #[cfg(feature = "tick-size-64bit")]
73 loop {
74 let t0 = SYS_TICK_1.load(Ordering::SeqCst);
75 let t = SYS_TICK_0.load(Ordering::SeqCst);
76 let t1 = SYS_TICK_1.load(Ordering::SeqCst);
77 if t0 == t1 {
78 break Tick(((t0 as u64) << 32) | (t as u64));
79 }
80 }
81 #[cfg(not(feature = "tick-size-64bit"))]
83 Tick(SYS_TICK_0.load(Ordering::Relaxed))
84 }
85
86 pub fn elapsed(self) -> TickType {
94 if let Some(tick) = Self::now().0.checked_sub(self.0) {
95 tick
96 } else {
97 TickType::MAX
98 }
99 }
100
101 #[inline]
109 pub const fn with_value(value: TickType) -> Self {
110 Tick(value)
111 }
112
113 #[inline]
118 pub fn tick() -> TickType {
119 Self::now().0
120 }
121
122 pub fn elapsed_time(self) -> Duration<TickType, 1, TICK_FREQ_HZ> {
127 let tick = if let Some(res) = Self::now().0.checked_sub(self.0) {
128 res
129 } else {
130 TickType::MAX
131 };
132
133 Duration::<TickType, 1, TICK_FREQ_HZ>::from_ticks(tick)
134 }
135
136 pub fn every(&mut self, duration: TickType) -> bool {
144 let timeout = if let Some(elapsed) = Self::now().0.checked_sub(self.0) {
145 if elapsed >= duration {
146 true
147 } else {
148 false
149 }
150 } else {
151 true
152 };
153
154 if timeout {
155 self.0 = Self::now().0;
156 }
157 return timeout;
158 }
159
160 pub fn reset(&mut self) {
162 self.0 = Self::now().0;
163 }
164}
165
166impl core::ops::Add for Tick {
167 type Output = Self;
168
169 fn add(self, rhs: Self) -> Self::Output {
170 Tick(self.0 + rhs.0)
171 }
172}
173
174impl core::ops::Sub for Tick {
175 type Output = Self;
176
177 fn sub(self, rhs: Self) -> Self::Output {
178 Tick(self.0 - rhs.0)
179 }
180}
181
182#[derive(Debug, Clone, Copy)]
193pub struct Delay;
194
195impl Delay {
196 pub const fn new() -> Self {
203 Delay
204 }
205}
206
207impl DelayNs for Delay {
209 #[inline]
217 fn delay_ns(&mut self, ns: u32) {
218 ll_invoke_inner!(INVOKE_ID_DELAY_NANO, ns);
219 }
220
221 #[cfg(feature = "tick-based-msdelay")]
229 #[inline]
230 fn delay_ms(&mut self, ms: u32) {
231 let ms_tick = TimerDurationU32::<TICK_FREQ_HZ>::millis(ms).ticks();
232 let start = Tick::now();
233 loop {
234 unsafe {
235 core::arch::asm!("wfi");
236 }
237 if (start.elapsed() as u32) >= ms_tick {
238 break;
239 }
240 }
241 }
242}
243
244#[cfg(feature = "embassy")]
245mod tick_time_driver {
246 use core::cell::{Cell, RefCell};
247 use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
248 use embassy_sync::blocking_mutex::Mutex;
249 use embassy_time_driver::Driver;
250 use embassy_time_queue_utils::Queue;
251
252 struct AlarmState {
253 timestamp: Cell<super::TickType>,
254 }
255 unsafe impl Send for AlarmState {}
256
257 struct TimerDriver {
258 alarms: Mutex<CriticalSectionRawMutex, AlarmState>,
259 queue: Mutex<CriticalSectionRawMutex, RefCell<Queue>>,
260 }
261
262 embassy_time_driver::time_driver_impl!(static DRIVER: TimerDriver = TimerDriver{
263 alarms: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState {
264 timestamp: Cell::new(0),
265 }),
266 queue: Mutex::new(RefCell::new(Queue::new()))
267 });
268
269 #[inline(always)]
270 pub fn check_alarm(curr_tick: super::TickType) {
271 DRIVER.check_alarm(curr_tick);
272 }
273
274 impl TimerDriver {
275 fn check_alarm(&self, curr_tick: super::TickType) {
280 critical_section::with(|cs| {
281 let alarm = &self.alarms.borrow(cs);
282 let mut timestamp = alarm.timestamp.get();
283 while timestamp <= curr_tick {
284 let mut queue = self.queue.borrow(cs).borrow_mut();
285 timestamp = queue.next_expiration(curr_tick as u64) as super::TickType; alarm.timestamp.set(timestamp); }
288 });
289 }
290 }
291
292 impl Driver for TimerDriver {
293 fn now(&self) -> u64 {
294 super::Tick::now().0 as u64
295 }
296
297 fn schedule_wake(&self, at: u64, waker: &core::task::Waker) {
298 critical_section::with(|cs| {
299 let mut queue = self.queue.borrow(cs).borrow_mut();
300
301 if queue.schedule_wake(at, waker) {
302 let alarm = &self.alarms.borrow(cs);
303 let now = self.now();
304 loop {
305 let timestamp = queue.next_expiration(now) as super::TickType; alarm.timestamp.set(timestamp); if timestamp > now as super::TickType {
308 break;
309 }
310 }
311 }
312 })
313 }
314 }
315}