init new shared periph crate
This commit is contained in:
@ -20,7 +20,7 @@ embassy-time-queue-utils = "0.1"
|
||||
|
||||
once_cell = { version = "1", default-features = false, features = ["critical-section"] }
|
||||
|
||||
va108xx-hal = { version = ">=0.10, <=0.11" }
|
||||
va108xx-hal = { version = ">=0.10, <=0.11", path = "../va108xx-hal" }
|
||||
|
||||
[target.'cfg(all(target_arch = "arm", target_os = "none"))'.dependencies]
|
||||
portable-atomic = { version = "1", features = ["unsafe-assume-single-core"] }
|
||||
|
@ -45,7 +45,11 @@ use va108xx_hal::{
|
||||
clock::enable_peripheral_clock,
|
||||
enable_nvic_interrupt, pac,
|
||||
prelude::*,
|
||||
timer::{enable_tim_clk, get_tim_raw, TimRegInterface, ValidTim},
|
||||
timer::{
|
||||
enable_tim_clk,
|
||||
regs::{EnableControl, MmioTimer},
|
||||
TimId, TimMarker,
|
||||
},
|
||||
PeripheralSelect,
|
||||
};
|
||||
|
||||
@ -109,48 +113,25 @@ pub fn time_driver() -> &'static TimerDriver {
|
||||
/// This should be used if the interrupt handler is provided by the library, which is the
|
||||
/// default case.
|
||||
#[cfg(feature = "irqs-in-lib")]
|
||||
pub fn init<TimekeeperTim: TimRegInterface + ValidTim, AlarmTim: TimRegInterface + ValidTim>(
|
||||
syscfg: &mut pac::Sysconfig,
|
||||
irqsel: &pac::Irqsel,
|
||||
sysclk: impl Into<Hertz>,
|
||||
pub fn init<TimekeeperTim: TimMarker, AlarmTim: TimMarker>(
|
||||
sysclk: Hertz,
|
||||
timekeeper_tim: TimekeeperTim,
|
||||
alarm_tim: AlarmTim,
|
||||
) {
|
||||
TIME_DRIVER.init(
|
||||
syscfg,
|
||||
irqsel,
|
||||
sysclk,
|
||||
timekeeper_tim,
|
||||
alarm_tim,
|
||||
TIMEKEEPER_IRQ,
|
||||
ALARM_IRQ,
|
||||
)
|
||||
TIME_DRIVER.init(sysclk, timekeeper_tim, alarm_tim, TIMEKEEPER_IRQ, ALARM_IRQ)
|
||||
}
|
||||
|
||||
/// Initialization method for embassy when using custom IRQ handlers.
|
||||
///
|
||||
/// Requires an explicit [pac::Interrupt] argument for the timekeeper and alarm IRQs.
|
||||
pub fn init_with_custom_irqs<
|
||||
TimekeeperTim: TimRegInterface + ValidTim,
|
||||
AlarmTim: TimRegInterface + ValidTim,
|
||||
>(
|
||||
syscfg: &mut pac::Sysconfig,
|
||||
irqsel: &pac::Irqsel,
|
||||
sysclk: impl Into<Hertz>,
|
||||
pub fn init_with_custom_irqs<TimekeeperTim: TimMarker, AlarmTim: TimMarker>(
|
||||
sysclk: Hertz,
|
||||
timekeeper_tim: TimekeeperTim,
|
||||
alarm_tim: AlarmTim,
|
||||
timekeeper_irq: pac::Interrupt,
|
||||
alarm_irq: pac::Interrupt,
|
||||
) {
|
||||
TIME_DRIVER.init(
|
||||
syscfg,
|
||||
irqsel,
|
||||
sysclk,
|
||||
timekeeper_tim,
|
||||
alarm_tim,
|
||||
timekeeper_irq,
|
||||
alarm_irq,
|
||||
)
|
||||
TIME_DRIVER.init(sysclk, timekeeper_tim, alarm_tim, timekeeper_irq, alarm_irq)
|
||||
}
|
||||
|
||||
struct AlarmState {
|
||||
@ -168,8 +149,8 @@ impl AlarmState {
|
||||
unsafe impl Send for AlarmState {}
|
||||
|
||||
static SCALE: OnceCell<u64> = OnceCell::new();
|
||||
static TIMEKEEPER_TIM: OnceCell<u8> = OnceCell::new();
|
||||
static ALARM_TIM: OnceCell<u8> = OnceCell::new();
|
||||
static TIMEKEEPER_TIM: OnceCell<TimId> = OnceCell::new();
|
||||
static ALARM_TIM: OnceCell<TimId> = OnceCell::new();
|
||||
|
||||
pub struct TimerDriver {
|
||||
periods: AtomicU32,
|
||||
@ -180,62 +161,56 @@ pub struct TimerDriver {
|
||||
|
||||
impl TimerDriver {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn init<TimekeeperTim: TimRegInterface + ValidTim, AlarmTim: TimRegInterface + ValidTim>(
|
||||
fn init<TimekeeperTim: TimMarker, AlarmTim: TimMarker>(
|
||||
&self,
|
||||
syscfg: &mut pac::Sysconfig,
|
||||
irqsel: &pac::Irqsel,
|
||||
sysclk: impl Into<Hertz>,
|
||||
timekeeper_tim: TimekeeperTim,
|
||||
alarm_tim: AlarmTim,
|
||||
sysclk: Hertz,
|
||||
_timekeeper_tim: TimekeeperTim,
|
||||
_alarm_tim: AlarmTim,
|
||||
timekeeper_irq: pac::Interrupt,
|
||||
alarm_irq: pac::Interrupt,
|
||||
) {
|
||||
if ALARM_TIM.get().is_some() || TIMEKEEPER_TIM.get().is_some() {
|
||||
return;
|
||||
}
|
||||
ALARM_TIM.set(AlarmTim::TIM_ID).ok();
|
||||
TIMEKEEPER_TIM.set(TimekeeperTim::TIM_ID).ok();
|
||||
enable_peripheral_clock(syscfg, PeripheralSelect::Irqsel);
|
||||
enable_tim_clk(syscfg, timekeeper_tim.tim_id());
|
||||
let timekeeper_reg_block = timekeeper_tim.reg_block();
|
||||
let alarm_tim_reg_block = alarm_tim.reg_block();
|
||||
let sysclk = sysclk.into();
|
||||
ALARM_TIM.set(AlarmTim::ID).ok();
|
||||
TIMEKEEPER_TIM.set(TimekeeperTim::ID).ok();
|
||||
enable_peripheral_clock(PeripheralSelect::Irqsel);
|
||||
enable_tim_clk(TimekeeperTim::ID);
|
||||
let mut timekeeper_reg_block = unsafe { TimekeeperTim::ID.steal_regs() };
|
||||
let mut alarm_tim_reg_block = unsafe { AlarmTim::ID.steal_regs() };
|
||||
// Initiate scale value here. This is required to convert timer ticks back to a timestamp.
|
||||
SCALE.set((sysclk.raw() / TICK_HZ as u32) as u64).unwrap();
|
||||
timekeeper_reg_block
|
||||
.rst_value()
|
||||
.write(|w| unsafe { w.bits(u32::MAX) });
|
||||
timekeeper_reg_block.write_reset_value(u32::MAX);
|
||||
// Decrementing counter.
|
||||
timekeeper_reg_block
|
||||
.cnt_value()
|
||||
.write(|w| unsafe { w.bits(u32::MAX) });
|
||||
timekeeper_reg_block.write_count_value(u32::MAX);
|
||||
let irqsel = unsafe { va108xx_hal::pac::Irqsel::steal() };
|
||||
// Switch on. Timekeeping should always be done.
|
||||
irqsel
|
||||
.tim0(timekeeper_tim.tim_id() as usize)
|
||||
.tim0(TimekeeperTim::ID.value() as usize)
|
||||
.write(|w| unsafe { w.bits(timekeeper_irq as u32) });
|
||||
unsafe {
|
||||
enable_nvic_interrupt(timekeeper_irq);
|
||||
}
|
||||
timekeeper_reg_block
|
||||
.ctrl()
|
||||
.modify(|_, w| w.irq_enb().set_bit());
|
||||
timekeeper_reg_block
|
||||
.enable()
|
||||
.write(|w| unsafe { w.bits(1) });
|
||||
timekeeper_reg_block.modify_control(|mut value| {
|
||||
value.set_irq_enable(true);
|
||||
value
|
||||
});
|
||||
timekeeper_reg_block.write_enable_control(EnableControl::new_enable());
|
||||
|
||||
enable_tim_clk(syscfg, alarm_tim.tim_id());
|
||||
enable_tim_clk(AlarmTim::ID);
|
||||
|
||||
// Explicitely disable alarm timer until needed.
|
||||
alarm_tim_reg_block.ctrl().modify(|_, w| {
|
||||
w.irq_enb().clear_bit();
|
||||
w.enable().clear_bit()
|
||||
alarm_tim_reg_block.modify_control(|mut value| {
|
||||
value.set_irq_enable(false);
|
||||
value.set_enable(false);
|
||||
value
|
||||
});
|
||||
// Enable general interrupts. The IRQ enable of the peripheral remains cleared.
|
||||
unsafe {
|
||||
enable_nvic_interrupt(alarm_irq);
|
||||
}
|
||||
irqsel
|
||||
.tim0(alarm_tim.tim_id() as usize)
|
||||
.tim0(AlarmTim::ID.value() as usize)
|
||||
.write(|w| unsafe { w.bits(alarm_irq as u32) });
|
||||
}
|
||||
|
||||
@ -261,16 +236,16 @@ impl TimerDriver {
|
||||
})
|
||||
}
|
||||
|
||||
fn timekeeper_tim() -> &'static pac::tim0::RegisterBlock {
|
||||
fn timekeeper_tim() -> MmioTimer<'static> {
|
||||
TIMEKEEPER_TIM
|
||||
.get()
|
||||
.map(|idx| unsafe { get_tim_raw(*idx as usize) })
|
||||
.map(|id| unsafe { id.steal_regs() })
|
||||
.unwrap()
|
||||
}
|
||||
fn alarm_tim() -> &'static pac::tim0::RegisterBlock {
|
||||
fn alarm_tim() -> MmioTimer<'static> {
|
||||
ALARM_TIM
|
||||
.get()
|
||||
.map(|idx| unsafe { get_tim_raw(*idx as usize) })
|
||||
.map(|id| unsafe { id.steal_regs() })
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
@ -283,25 +258,27 @@ impl TimerDriver {
|
||||
if at < t {
|
||||
self.trigger_alarm(cs);
|
||||
} else {
|
||||
let alarm_tim = Self::alarm_tim();
|
||||
let mut alarm_tim = Self::alarm_tim();
|
||||
|
||||
let remaining_ticks = (at - t).checked_mul(*SCALE.get().unwrap());
|
||||
if remaining_ticks.is_some_and(|v| v <= u32::MAX as u64) {
|
||||
alarm_tim.enable().write(|w| unsafe { w.bits(0) });
|
||||
alarm_tim
|
||||
.cnt_value()
|
||||
.write(|w| unsafe { w.bits(remaining_ticks.unwrap() as u32) });
|
||||
alarm_tim.ctrl().modify(|_, w| w.irq_enb().set_bit());
|
||||
alarm_tim.enable().write(|w| unsafe { w.bits(1) });
|
||||
alarm_tim.write_enable_control(EnableControl::new_disable());
|
||||
alarm_tim.write_count_value(remaining_ticks.unwrap() as u32);
|
||||
alarm_tim.modify_control(|mut value| {
|
||||
value.set_irq_enable(true);
|
||||
value
|
||||
});
|
||||
alarm_tim.write_enable_control(EnableControl::new_enable());
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn trigger_alarm(&self, cs: CriticalSection) {
|
||||
Self::alarm_tim().ctrl().modify(|_, w| {
|
||||
w.irq_enb().clear_bit();
|
||||
w.enable().clear_bit()
|
||||
Self::alarm_tim().modify_control(|mut value| {
|
||||
value.set_irq_enable(false);
|
||||
value.set_enable(false);
|
||||
value
|
||||
});
|
||||
|
||||
let alarm = &self.alarms.borrow(cs);
|
||||
@ -327,10 +304,11 @@ impl TimerDriver {
|
||||
if SCALE.get().is_none() {
|
||||
return false;
|
||||
}
|
||||
let alarm_tim = Self::alarm_tim();
|
||||
alarm_tim.ctrl().modify(|_, w| {
|
||||
w.irq_enb().clear_bit();
|
||||
w.enable().clear_bit()
|
||||
let mut alarm_tim = Self::alarm_tim();
|
||||
alarm_tim.modify_control(|mut value| {
|
||||
value.set_irq_enable(false);
|
||||
value.set_enable(false);
|
||||
value
|
||||
});
|
||||
|
||||
let alarm = self.alarms.borrow(cs);
|
||||
@ -354,13 +332,14 @@ impl TimerDriver {
|
||||
// and we don't do that here.
|
||||
let safe_timestamp = timestamp.max(t + 3);
|
||||
let timer_ticks = (safe_timestamp - t).checked_mul(*SCALE.get().unwrap());
|
||||
alarm_tim.rst_value().write(|w| unsafe { w.bits(u32::MAX) });
|
||||
alarm_tim.write_reset_value(u32::MAX);
|
||||
if timer_ticks.is_some_and(|v| v <= u32::MAX as u64) {
|
||||
alarm_tim
|
||||
.cnt_value()
|
||||
.write(|w| unsafe { w.bits(timer_ticks.unwrap() as u32) });
|
||||
alarm_tim.ctrl().modify(|_, w| w.irq_enb().set_bit());
|
||||
alarm_tim.enable().write(|w| unsafe { w.bits(1) });
|
||||
alarm_tim.write_count_value(timer_ticks.unwrap() as u32);
|
||||
alarm_tim.modify_control(|mut value| {
|
||||
value.set_irq_enable(true);
|
||||
value.set_enable(true);
|
||||
value
|
||||
});
|
||||
}
|
||||
// If it's too far in the future, don't enable timer yet.
|
||||
// It will be enabled later by `next_period`.
|
||||
@ -383,7 +362,7 @@ impl Driver for TimerDriver {
|
||||
// no instructions can be reordered before the load.
|
||||
period1 = self.periods.load(Ordering::Acquire);
|
||||
|
||||
counter_val = u32::MAX - Self::timekeeper_tim().cnt_value().read().bits();
|
||||
counter_val = u32::MAX - Self::timekeeper_tim().read_count_value();
|
||||
|
||||
// Double read to protect against race conditions when the counter is overflowing.
|
||||
period2 = self.periods.load(Ordering::Relaxed);
|
||||
|
Reference in New Issue
Block a user