Skip to main content

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