use embedded_hal::delay::DelayNs;
use caravel_pac::{CaravelInterrupt, Timer0Registers};
pub struct Timer0 {
regs: &'static Timer0Registers,
ns_to_ticks_factor: u64,
}
unsafe impl Send for Timer0 {}
impl Timer0 {
#[inline]
pub const fn new(ticks_per_s: u32) -> Self {
Self {
regs: Timer0Registers::new(),
ns_to_ticks_factor: ((ticks_per_s as u64) << 32) / 1_000_000_000,
}
}
#[cfg(feature = "interrupts")]
#[inline(always)]
pub fn enable_interrupt(&mut self) {
unsafe {
riscv::interrupt::enable_interrupt(riscv::interrupt::Interrupt::MachineExternal);
self.regs.ev_enable.modify(|x| x.with_zero(true));
}
CaravelInterrupt::Timer0.enable();
}
#[cfg(feature = "interrupts")]
#[inline(always)]
pub fn disable_interrupt(&mut self) {
unsafe {
self.regs.ev_enable.modify(|x| x.with_zero(false));
}
CaravelInterrupt::Timer0.disable();
}
#[inline(always)]
pub fn set_periodic(&mut self, period_ns: u32) {
let ticks = ((period_ns as u64 * self.ns_to_ticks_factor) >> 32) as u32;
unsafe {
self.regs.en.write(0);
self.regs.load.write(ticks);
self.regs.reload.write(ticks);
self.regs.en.write(1);
}
}
#[inline(always)]
pub fn disable(&mut self) {
unsafe {
self.regs.en.write(0);
}
}
#[inline(always)]
pub fn event_pending(&self) -> bool {
self.regs.ev_pending.read().zero()
}
#[inline(always)]
pub fn clear_event(&self) {
unsafe {
self.regs.ev_pending.modify(|x| x.with_zero(true));
}
}
}
impl DelayNs for Timer0 {
#[inline]
fn delay_ns(&mut self, ns: u32) {
let ticks = ((ns as u64 * self.ns_to_ticks_factor) >> 32) as u32;
unsafe {
self.regs.en.write(0);
self.regs.load.write(ticks);
self.regs.en.write(1);
self.regs.update_value.write(1);
while self.regs.value.read() > 0 {
self.regs.update_value.write(1);
}
}
}
}