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#[inline]
53#[deprecated(since = "0.7.3", note = "Please use `sys_tick_handler!()` instead")]
54unsafe extern "C" fn sys_tick_inc() {
55 Tick::on_sys_tick_interrupt();
56}
57
58#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Default)]
62pub struct Tick(TickType);
63
64impl Tick {
65 pub fn now() -> Self {
72 #[cfg(feature = "tick-size-64bit")]
74 loop {
75 let t0 = SYS_TICK_1.load(Ordering::SeqCst);
76 let t = SYS_TICK_0.load(Ordering::SeqCst);
77 let t1 = SYS_TICK_1.load(Ordering::SeqCst);
78 if t0 == t1 {
79 break Tick(((t0 as u64) << 32) | (t as u64));
80 }
81 }
82 #[cfg(not(feature = "tick-size-64bit"))]
84 Tick(SYS_TICK_0.load(Ordering::Relaxed))
85 }
86
87 pub fn elapsed(self) -> TickType {
95 if let Some(tick) = Self::now().0.checked_sub(self.0) {
96 tick
97 } else {
98 TickType::MAX
99 }
100 }
101
102 #[inline]
110 pub const fn with_value(value: TickType) -> Self {
111 Tick(value)
112 }
113
114 #[inline]
119 pub fn tick() -> TickType {
120 Self::now().0
121 }
122
123 pub fn elapsed_time(self) -> Duration<TickType, 1, TICK_FREQ_HZ> {
128 let tick = if let Some(res) = Self::now().0.checked_sub(self.0) {
129 res
130 } else {
131 TickType::MAX
132 };
133
134 Duration::<TickType, 1, TICK_FREQ_HZ>::from_ticks(tick)
135 }
136}
137
138impl core::ops::Add for Tick {
139 type Output = Self;
140
141 fn add(self, rhs: Self) -> Self::Output {
142 Tick(self.0 + rhs.0)
143 }
144}
145
146impl core::ops::Sub for Tick {
147 type Output = Self;
148
149 fn sub(self, rhs: Self) -> Self::Output {
150 Tick(self.0 - rhs.0)
151 }
152}
153
154#[derive(Debug, Clone, Copy)]
165pub struct Delay;
166
167impl Delay {
168 pub const fn new() -> Self {
175 Delay
176 }
177}
178
179impl DelayNs for Delay {
181 #[inline]
189 fn delay_ns(&mut self, ns: u32) {
190 ll_invoke_inner!(INVOKE_ID_DELAY_NANO, ns);
191 }
192
193 #[cfg(feature = "tick-based-msdelay")]
201 #[inline]
202 fn delay_ms(&mut self, ms: u32) {
203 let ms_tick = TimerDurationU32::<TICK_FREQ_HZ>::millis(ms).ticks();
204 let start = Tick::now();
205 loop {
206 unsafe {
207 core::arch::asm!("wfi");
208 }
209 if (start.elapsed() as u32) >= ms_tick {
210 break;
211 }
212 }
213 }
214}
215
216#[cfg(feature = "embassy")]
217mod tick_time_driver {
218 use core::cell::{Cell, RefCell};
219 use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
220 use embassy_sync::blocking_mutex::Mutex;
221 use embassy_time_driver::Driver;
222 use embassy_time_queue_utils::Queue;
223
224 struct AlarmState {
225 timestamp: Cell<super::TickType>,
226 }
227 unsafe impl Send for AlarmState {}
228
229 struct TimerDriver {
230 alarms: Mutex<CriticalSectionRawMutex, AlarmState>,
231 queue: Mutex<CriticalSectionRawMutex, RefCell<Queue>>,
232 }
233
234 embassy_time_driver::time_driver_impl!(static DRIVER: TimerDriver = TimerDriver{
235 alarms: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState {
236 timestamp: Cell::new(0),
237 }),
238 queue: Mutex::new(RefCell::new(Queue::new()))
239 });
240
241 #[inline(always)]
242 pub fn check_alarm(curr_tick: super::TickType) {
243 DRIVER.check_alarm(curr_tick);
244 }
245
246 impl TimerDriver {
247 fn check_alarm(&self, curr_tick: super::TickType) {
252 critical_section::with(|cs| {
253 let alarm = &self.alarms.borrow(cs);
254 let mut timestamp = alarm.timestamp.get();
255 while timestamp <= curr_tick {
256 let mut queue = self.queue.borrow(cs).borrow_mut();
257 timestamp = queue.next_expiration(curr_tick as u64) as super::TickType; alarm.timestamp.set(timestamp); }
260 });
261 }
262 }
263
264 impl Driver for TimerDriver {
265 fn now(&self) -> u64 {
266 super::Tick::now().0 as u64
267 }
268
269 fn schedule_wake(&self, at: u64, waker: &core::task::Waker) {
270 critical_section::with(|cs| {
271 let mut queue = self.queue.borrow(cs).borrow_mut();
272
273 if queue.schedule_wake(at, waker) {
274 let alarm = &self.alarms.borrow(cs);
275 let now = self.now();
276 loop {
277 let timestamp = queue.next_expiration(now) as super::TickType; alarm.timestamp.set(timestamp); if timestamp > now as super::TickType {
280 break;
281 }
282 }
283 }
284 })
285 }
286 }
287}