vorago_shared_hal/
embassy.rs

1use core::cell::{Cell, RefCell};
2
3use crate::{
4    enable_nvic_interrupt,
5    timer::{
6        TimId, TimInstance, assert_tim_reset_for_cycles, enable_tim_clk,
7        regs::{EnableControl, MmioTimer},
8    },
9};
10use critical_section::{CriticalSection, Mutex};
11use embassy_time_driver::TICK_HZ;
12use embassy_time_driver::{Driver, time_driver_impl};
13use embassy_time_queue_utils::Queue;
14use once_cell::sync::OnceCell;
15use portable_atomic::{AtomicU32, Ordering};
16
17#[cfg(feature = "vor1x")]
18use crate::time::Hertz;
19#[cfg(feature = "vor1x")]
20use crate::{PeripheralSelect, enable_peripheral_clock};
21
22time_driver_impl!(
23    static TIME_DRIVER: TimerDriver = TimerDriver {
24        periods: AtomicU32::new(0),
25        alarms: Mutex::new(AlarmState::new()),
26        queue: Mutex::new(RefCell::new(Queue::new())),
27});
28
29/// Expose the time driver so the user can specify the IRQ handlers themselves.
30pub fn time_driver() -> &'static TimerDriver {
31    &TIME_DRIVER
32}
33
34struct AlarmState {
35    timestamp: Cell<u64>,
36}
37
38impl AlarmState {
39    const fn new() -> Self {
40        Self {
41            timestamp: Cell::new(u64::MAX),
42        }
43    }
44}
45
46unsafe impl Send for AlarmState {}
47
48static SCALE: OnceCell<u64> = OnceCell::new();
49static TIMEKEEPER_TIM: OnceCell<TimId> = OnceCell::new();
50static ALARM_TIM: OnceCell<TimId> = OnceCell::new();
51
52pub struct TimerDriver {
53    periods: AtomicU32,
54    /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled.
55    alarms: Mutex<AlarmState>,
56    queue: Mutex<RefCell<Queue>>,
57}
58
59impl TimerDriver {
60    #[cfg(feature = "vor1x")]
61    #[doc(hidden)]
62    pub fn __init<TimekeeperTim: TimInstance, AlarmTim: TimInstance>(
63        &self,
64        sysclk: Hertz,
65        _timekeeper_tim: TimekeeperTim,
66        _alarm_tim: AlarmTim,
67        timekeeper_irq: va108xx::Interrupt,
68        alarm_irq: va108xx::Interrupt,
69    ) {
70        if ALARM_TIM.get().is_some() || TIMEKEEPER_TIM.get().is_some() {
71            return;
72        }
73        ALARM_TIM.set(AlarmTim::ID).ok();
74        TIMEKEEPER_TIM.set(TimekeeperTim::ID).ok();
75        enable_peripheral_clock(PeripheralSelect::Irqsel);
76        enable_tim_clk(TimekeeperTim::ID);
77        assert_tim_reset_for_cycles(TimekeeperTim::ID, 2);
78
79        let mut timekeeper_reg_block = unsafe { TimekeeperTim::ID.steal_regs() };
80        let mut alarm_tim_reg_block = unsafe { AlarmTim::ID.steal_regs() };
81        // Initiate scale value here. This is required to convert timer ticks back to a timestamp.
82        SCALE.set((sysclk.raw() / TICK_HZ as u32) as u64).unwrap();
83        timekeeper_reg_block.write_reset_value(u32::MAX);
84        // Decrementing counter.
85        timekeeper_reg_block.write_count_value(u32::MAX);
86        let irqsel = unsafe { va108xx::Irqsel::steal() };
87        // Switch on. Timekeeping should always be done.
88        irqsel
89            .tim(TimekeeperTim::ID.value() as usize)
90            .write(|w| unsafe { w.bits(timekeeper_irq as u32) });
91        unsafe {
92            enable_nvic_interrupt(timekeeper_irq);
93        }
94        timekeeper_reg_block.modify_control(|mut value| {
95            value.set_irq_enable(true);
96            value
97        });
98        timekeeper_reg_block.write_enable_control(EnableControl::new_enable());
99
100        enable_tim_clk(AlarmTim::ID);
101        assert_tim_reset_for_cycles(AlarmTim::ID, 2);
102
103        // Explicitely disable alarm timer until needed.
104        alarm_tim_reg_block.modify_control(|mut value| {
105            value.set_irq_enable(false);
106            value.set_enable(false);
107            value
108        });
109        // Enable general interrupts. The IRQ enable of the peripheral remains cleared.
110        unsafe {
111            enable_nvic_interrupt(alarm_irq);
112        }
113        irqsel
114            .tim(AlarmTim::ID.value() as usize)
115            .write(|w| unsafe { w.bits(alarm_irq as u32) });
116    }
117
118    #[cfg(feature = "vor4x")]
119    #[doc(hidden)]
120    pub fn __init<TimekeeperTim: TimInstance, AlarmTim: TimInstance>(
121        &self,
122        _timekeeper_tim: TimekeeperTim,
123        _alarm_tim: AlarmTim,
124        clocks: &crate::clock::Clocks,
125    ) {
126        if ALARM_TIM.get().is_some() || TIMEKEEPER_TIM.get().is_some() {
127            return;
128        }
129        ALARM_TIM.set(AlarmTim::ID).ok();
130        TIMEKEEPER_TIM.set(TimekeeperTim::ID).ok();
131        let mut timekeeper_regs = unsafe { TimekeeperTim::ID.steal_regs() };
132        let mut alarm_regs = unsafe { AlarmTim::ID.steal_regs() };
133
134        enable_tim_clk(TimekeeperTim::ID);
135        assert_tim_reset_for_cycles(TimekeeperTim::ID, 2);
136
137        // Initiate scale value here. This is required to convert timer ticks back to a timestamp.
138
139        SCALE
140            .set((TimekeeperTim::clock(clocks).raw() / TICK_HZ as u32) as u64)
141            .unwrap();
142        timekeeper_regs.write_reset_value(u32::MAX);
143        // Decrementing counter.
144        timekeeper_regs.write_count_value(u32::MAX);
145        // Switch on. Timekeeping should always be done.
146        unsafe {
147            enable_nvic_interrupt(TimekeeperTim::IRQ);
148        }
149        timekeeper_regs.modify_control(|mut value| {
150            value.set_irq_enable(true);
151            value
152        });
153        timekeeper_regs.write_enable_control(EnableControl::new_enable());
154
155        enable_tim_clk(AlarmTim::ID);
156        assert_tim_reset_for_cycles(AlarmTim::ID, 2);
157        // Explicitely disable alarm timer until needed.
158        alarm_regs.modify_control(|mut value| {
159            value.set_irq_enable(false);
160            value.set_enable(false);
161            value
162        });
163        // Enable general interrupts. The IRQ enable of the peripheral remains cleared.
164        unsafe {
165            enable_nvic_interrupt(AlarmTim::IRQ);
166        }
167    }
168
169    fn timekeeper_tim() -> MmioTimer<'static> {
170        TIMEKEEPER_TIM
171            .get()
172            .map(|tim| unsafe { tim.steal_regs() })
173            .unwrap()
174    }
175    fn alarm_tim() -> MmioTimer<'static> {
176        ALARM_TIM
177            .get()
178            .map(|tim| unsafe { tim.steal_regs() })
179            .unwrap()
180    }
181
182    /// Should be called inside the IRQ of the timekeeper timer.
183    ///
184    /// # Safety
185    ///
186    /// This function has to be called once by the TIM IRQ used for the timekeeping.
187    pub unsafe fn on_interrupt_timekeeping(&self) {
188        self.next_period();
189    }
190
191    /// Should be called inside the IRQ of the alarm timer.
192    ///
193    /// # Safety
194    ///
195    ///This function has to be called once by the TIM IRQ used for the timekeeping.
196    pub unsafe fn on_interrupt_alarm(&self) {
197        critical_section::with(|cs| {
198            if self.alarms.borrow(cs).timestamp.get() <= self.now() {
199                self.trigger_alarm(cs)
200            }
201        })
202    }
203
204    fn next_period(&self) {
205        let period = self.periods.fetch_add(1, Ordering::AcqRel) + 1;
206        let t = (period as u64) << 32;
207        critical_section::with(|cs| {
208            let alarm = &self.alarms.borrow(cs);
209            let at = alarm.timestamp.get();
210            if at < t {
211                self.trigger_alarm(cs);
212            } else {
213                let mut alarm_tim = Self::alarm_tim();
214
215                let remaining_ticks = (at - t).checked_mul(*SCALE.get().unwrap());
216                if remaining_ticks.is_some_and(|v| v <= u32::MAX as u64) {
217                    alarm_tim.write_enable_control(EnableControl::new_disable());
218                    alarm_tim.write_count_value(remaining_ticks.unwrap() as u32);
219                    alarm_tim.modify_control(|mut value| {
220                        value.set_irq_enable(true);
221                        value
222                    });
223                    alarm_tim.write_enable_control(EnableControl::new_enable());
224                }
225            }
226        })
227    }
228
229    fn trigger_alarm(&self, cs: CriticalSection) {
230        Self::alarm_tim().modify_control(|mut value| {
231            value.set_irq_enable(false);
232            value.set_enable(false);
233            value
234        });
235
236        let alarm = &self.alarms.borrow(cs);
237        // Setting the maximum value disables the alarm.
238        alarm.timestamp.set(u64::MAX);
239
240        // Call after clearing alarm, so the callback can set another alarm.
241        let mut next = self
242            .queue
243            .borrow(cs)
244            .borrow_mut()
245            .next_expiration(self.now());
246        while !self.set_alarm(cs, next) {
247            next = self
248                .queue
249                .borrow(cs)
250                .borrow_mut()
251                .next_expiration(self.now());
252        }
253    }
254
255    fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool {
256        if SCALE.get().is_none() {
257            return false;
258        }
259        let mut alarm_tim = Self::alarm_tim();
260        alarm_tim.modify_control(|mut value| {
261            value.set_irq_enable(false);
262            value.set_enable(false);
263            value
264        });
265
266        let alarm = self.alarms.borrow(cs);
267        alarm.timestamp.set(timestamp);
268
269        let t = self.now();
270        if timestamp <= t {
271            alarm.timestamp.set(u64::MAX);
272            return false;
273        }
274
275        // If it hasn't triggered yet, setup the relevant reset value, regardless of whether
276        // the interrupts are enabled or not. When they are enabled at a later point, the
277        // right value is already set.
278
279        // If the timestamp is in the next few ticks, add a bit of buffer to be sure the alarm
280        // is not missed.
281        //
282        // This means that an alarm can be delayed for up to 2 ticks (from t+1 to t+3), but this is allowed
283        // by the Alarm trait contract. What's not allowed is triggering alarms *before* their scheduled time,
284        // and we don't do that here.
285        let safe_timestamp = timestamp.max(t + 3);
286        let timer_ticks = (safe_timestamp - t).checked_mul(*SCALE.get().unwrap());
287        alarm_tim.write_reset_value(u32::MAX);
288        if timer_ticks.is_some_and(|v| v <= u32::MAX as u64) {
289            alarm_tim.write_count_value(timer_ticks.unwrap() as u32);
290            alarm_tim.modify_control(|mut value| {
291                value.set_irq_enable(true);
292                value.set_enable(true);
293                value
294            });
295        }
296        // If it's too far in the future, don't enable timer yet.
297        // It will be enabled later by `next_period`.
298
299        true
300    }
301}
302
303impl Driver for TimerDriver {
304    fn now(&self) -> u64 {
305        if SCALE.get().is_none() {
306            return 0;
307        }
308        let mut period1: u32;
309        let mut period2: u32;
310        let mut counter_val: u32;
311
312        loop {
313            // Acquire ensures that we get the latest value of `periods` and
314            // no instructions can be reordered before the load.
315            period1 = self.periods.load(Ordering::Acquire);
316
317            counter_val = u32::MAX - Self::timekeeper_tim().read_count_value();
318
319            // Double read to protect against race conditions when the counter is overflowing.
320            period2 = self.periods.load(Ordering::Relaxed);
321            if period1 == period2 {
322                let now = (((period1 as u64) << 32) | counter_val as u64) / *SCALE.get().unwrap();
323                return now;
324            }
325        }
326    }
327
328    fn schedule_wake(&self, at: u64, waker: &core::task::Waker) {
329        critical_section::with(|cs| {
330            let mut queue = self.queue.borrow(cs).borrow_mut();
331
332            if queue.schedule_wake(at, waker) {
333                let mut next = queue.next_expiration(self.now());
334                while !self.set_alarm(cs, next) {
335                    next = queue.next_expiration(self.now());
336                }
337            }
338        })
339    }
340}