Skip to main content

caravel_hal/
timer0.rs

1use embedded_hal::delay::DelayNs;
2
3use caravel_pac::{CaravelInterrupt, Timer0Registers};
4
5pub struct Timer0 {
6    regs: &'static Timer0Registers,
7    /// Precomputed factor: ticks per nanosecond * 2^32 for fixed-point maths
8    ns_to_ticks_factor: u64,
9}
10
11unsafe impl Send for Timer0 {}
12
13impl Timer0 {
14    /// Constructs the Timer0 driver.
15    /// `ticks_per_s` should be the clock speed of the core, in Hertz
16    #[inline]
17    pub const fn new(ticks_per_s: u32) -> Self {
18        // Precompute fixed-point conversion factor
19        Self {
20            regs: Timer0Registers::new(),
21            ns_to_ticks_factor: ((ticks_per_s as u64) << 32) / 1_000_000_000,
22        }
23    }
24
25    /// Enable the Timer0 interrupt source
26    /// Define the ISR using the `riscv_rt::external_interrupt` attribute
27    #[cfg(feature = "interrupts")]
28    #[inline(always)]
29    pub fn enable_interrupt(&mut self) {
30        unsafe {
31            riscv::interrupt::enable_interrupt(riscv::interrupt::Interrupt::MachineExternal);
32            self.regs.ev_enable.modify(|x| x.with_zero(true));
33        }
34        CaravelInterrupt::Timer0.enable();
35    }
36
37    /// Disable the Timer0 interrupt source
38    #[cfg(feature = "interrupts")]
39    #[inline(always)]
40    pub fn disable_interrupt(&mut self) {
41        unsafe {
42            self.regs.ev_enable.modify(|x| x.with_zero(false));
43        }
44        CaravelInterrupt::Timer0.disable();
45    }
46
47    /// Set the timer to fire periodically
48    #[inline(always)]
49    pub fn set_periodic(&mut self, period_ns: u32) {
50        // Fast 32-bit fixed-point multiply: (ns * factor) >> 32
51        let ticks = ((period_ns as u64 * self.ns_to_ticks_factor) >> 32) as u32;
52
53        unsafe {
54            // Configure timer for periodic operation
55            self.regs.en.write(0);
56            self.regs.load.write(ticks);
57            self.regs.reload.write(ticks);
58            self.regs.en.write(1);
59        }
60    }
61
62    /// Disable the timer immediately
63    #[inline(always)]
64    pub fn disable(&mut self) {
65        unsafe {
66            self.regs.en.write(0);
67        }
68    }
69
70    /// Check for a pending event
71    #[inline(always)]
72    pub fn event_pending(&self) -> bool {
73        self.regs.ev_pending.read().zero()
74    }
75
76    /// Clear the pending event flag
77    #[inline(always)]
78    pub fn clear_event(&self) {
79        unsafe {
80            self.regs.ev_pending.modify(|x| x.with_zero(true));
81        }
82    }
83}
84
85impl DelayNs for Timer0 {
86    #[inline]
87    fn delay_ns(&mut self, ns: u32) {
88        // Fast 32-bit fixed-point multiply: (ns * factor) >> 32
89        let ticks = ((ns as u64 * self.ns_to_ticks_factor) >> 32) as u32;
90
91        unsafe {
92            // Configure timer for a single-shot countdown
93            self.regs.en.write(0);
94            self.regs.load.write(ticks);
95            self.regs.en.write(1);
96
97            // Loop, waiting for value to reach zero
98            self.regs.update_value.write(1);
99            while self.regs.value.read() > 0 {
100                self.regs.update_value.write(1);
101            }
102        }
103    }
104}