Vorago Repo Unification
shared-hal-ci / Check build (push) Has been cancelled
shared-hal-ci / Check formatting (push) Has been cancelled
shared-hal-ci / Check Documentation Build (push) Has been cancelled
shared-hal-ci / Clippy (push) Has been cancelled
va108xx-ci / Check build (push) Has been cancelled
va108xx-ci / Run Tests (push) Has been cancelled
va108xx-ci / Check formatting (push) Has been cancelled
va108xx-ci / Check Documentation Build (push) Has been cancelled
va108xx-ci / Clippy (push) Has been cancelled
va416xx-ci / Check build (push) Has been cancelled
va416xx-ci / Run Tests (push) Has been cancelled
va416xx-ci / Check formatting (push) Has been cancelled
va416xx-ci / Check Documentation Build (push) Has been cancelled
va416xx-ci / Clippy (push) Has been cancelled
shared-hal-ci / Check build (push) Has been cancelled
shared-hal-ci / Check formatting (push) Has been cancelled
shared-hal-ci / Check Documentation Build (push) Has been cancelled
shared-hal-ci / Clippy (push) Has been cancelled
va108xx-ci / Check build (push) Has been cancelled
va108xx-ci / Run Tests (push) Has been cancelled
va108xx-ci / Check formatting (push) Has been cancelled
va108xx-ci / Check Documentation Build (push) Has been cancelled
va108xx-ci / Clippy (push) Has been cancelled
va416xx-ci / Check build (push) Has been cancelled
va416xx-ci / Run Tests (push) Has been cancelled
va416xx-ci / Check formatting (push) Has been cancelled
va416xx-ci / Check Documentation Build (push) Has been cancelled
va416xx-ci / Clippy (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,504 @@
|
||||
pub mod regs;
|
||||
|
||||
use core::convert::Infallible;
|
||||
|
||||
#[cfg(feature = "vor1x")]
|
||||
pub use crate::InterruptConfig;
|
||||
#[cfg(feature = "vor1x")]
|
||||
use crate::sysconfig::enable_peripheral_clock;
|
||||
pub use regs::{CascadeSource, InvalidTimerIndex, TimId};
|
||||
|
||||
use crate::{enable_nvic_interrupt, sealed::Sealed, time::Hertz};
|
||||
use crate::{gpio::DynPinId, ioconfig::regs::FunctionSelect, pins::AnyPin};
|
||||
use fugit::RateExtU32;
|
||||
|
||||
#[cfg(feature = "vor1x")]
|
||||
use crate::PeripheralSelect;
|
||||
|
||||
#[cfg(feature = "vor1x")]
|
||||
use va108xx as pac;
|
||||
#[cfg(feature = "vor4x")]
|
||||
use va416xx as pac;
|
||||
|
||||
#[cfg(feature = "vor4x")]
|
||||
pub const TIM_IRQ_OFFSET: usize = 48;
|
||||
|
||||
//==================================================================================================
|
||||
// Defintions
|
||||
//==================================================================================================
|
||||
|
||||
#[derive(Default, Debug, PartialEq, Eq, Copy, Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct CascadeControl {
|
||||
/// Enable Cascade 0 signal active as a requirement for counting
|
||||
pub enable_src_0: bool,
|
||||
/// Invert Cascade 0, making it active low
|
||||
pub inv_src_0: regs::CascadeInvert,
|
||||
/// Enable Cascade 1 signal active as a requirement for counting
|
||||
pub enable_src_1: bool,
|
||||
/// Invert Cascade 1, making it active low
|
||||
pub inv_src_1: regs::CascadeInvert,
|
||||
/// Specify required operation if both Cascade 0 and Cascade 1 are active.
|
||||
/// 0 is a logical AND of both cascade signals, 1 is a logical OR
|
||||
pub dual_operation: regs::DualCascadeOp,
|
||||
/// Enable trigger mode for Cascade 0. In trigger mode, couting will start with the selected
|
||||
/// cascade signal active, but once the counter is active, cascade control will be ignored
|
||||
pub trigger_mode_0: bool,
|
||||
/// Trigger mode, identical to [Self::trigger_mode_0] but for Cascade 1
|
||||
pub trigger_mode_1: bool,
|
||||
/// Enable Cascade 2 signal active as a requirement to stop counting. This mode is similar
|
||||
/// to the REQ_STOP control bit, but signalled by a Cascade source
|
||||
pub enable_stop_src_2: bool,
|
||||
/// Invert Cascade 2, making it active low
|
||||
pub inv_src_2: regs::CascadeInvert,
|
||||
/// The counter is automatically disabled if the corresponding Cascade 2 level-sensitive input
|
||||
/// souce is active when the count reaches 0. If the counter is not 0, the cascade control is
|
||||
/// ignored
|
||||
pub trigger_mode_2: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum CascadeSelect {
|
||||
Csd0 = 0,
|
||||
Csd1 = 1,
|
||||
Csd2 = 2,
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Valid TIM and PIN combinations
|
||||
//==================================================================================================
|
||||
|
||||
pub trait TimPin: AnyPin {
|
||||
const PIN_ID: DynPinId;
|
||||
const FUN_SEL: FunctionSelect;
|
||||
const TIM_ID: TimId;
|
||||
}
|
||||
|
||||
pub trait TimInstance: Sealed {
|
||||
// TIM ID ranging from 0 to 23 for 24 TIM peripherals
|
||||
const ID: TimId;
|
||||
#[cfg(feature = "vor4x")]
|
||||
const IRQ: va416xx::Interrupt;
|
||||
|
||||
#[cfg(feature = "vor4x")]
|
||||
fn clock(clocks: &crate::clock::Clocks) -> Hertz {
|
||||
if Self::ID.value() <= 15 {
|
||||
clocks.apb1()
|
||||
} else {
|
||||
clocks.apb2()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! tim_marker {
|
||||
($TIMX:path, $ID:expr) => {
|
||||
impl TimInstance for $TIMX {
|
||||
const ID: TimId = TimId::new_unchecked($ID);
|
||||
}
|
||||
|
||||
impl Sealed for $TIMX {}
|
||||
};
|
||||
($TIMX:path, $ID:expr, $IrqId:ident) => {
|
||||
impl TimInstance for $TIMX {
|
||||
const ID: TimId = TimId::new_unchecked($ID);
|
||||
const IRQ: va416xx::Interrupt = va416xx::Interrupt::$IrqId;
|
||||
}
|
||||
|
||||
impl Sealed for $TIMX {}
|
||||
};
|
||||
}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "vor1x")] {
|
||||
tim_marker!(pac::Tim0, 0);
|
||||
tim_marker!(pac::Tim1, 1);
|
||||
tim_marker!(pac::Tim2, 2);
|
||||
tim_marker!(pac::Tim3, 3);
|
||||
tim_marker!(pac::Tim4, 4);
|
||||
tim_marker!(pac::Tim5, 5);
|
||||
tim_marker!(pac::Tim6, 6);
|
||||
tim_marker!(pac::Tim7, 7);
|
||||
tim_marker!(pac::Tim8, 8);
|
||||
tim_marker!(pac::Tim9, 9);
|
||||
tim_marker!(pac::Tim10, 10);
|
||||
tim_marker!(pac::Tim11, 11);
|
||||
tim_marker!(pac::Tim12, 12);
|
||||
tim_marker!(pac::Tim13, 13);
|
||||
tim_marker!(pac::Tim14, 14);
|
||||
tim_marker!(pac::Tim15, 15);
|
||||
tim_marker!(pac::Tim16, 16);
|
||||
tim_marker!(pac::Tim17, 17);
|
||||
tim_marker!(pac::Tim18, 18);
|
||||
tim_marker!(pac::Tim19, 19);
|
||||
tim_marker!(pac::Tim20, 20);
|
||||
tim_marker!(pac::Tim21, 21);
|
||||
tim_marker!(pac::Tim22, 22);
|
||||
tim_marker!(pac::Tim23, 23);
|
||||
} else if #[cfg(feature = "vor4x")] {
|
||||
tim_marker!(pac::Tim0, 0, TIM0);
|
||||
tim_marker!(pac::Tim1, 1, TIM1);
|
||||
tim_marker!(pac::Tim2, 2, TIM2);
|
||||
tim_marker!(pac::Tim3, 3, TIM3);
|
||||
tim_marker!(pac::Tim4, 4, TIM4);
|
||||
tim_marker!(pac::Tim5, 5, TIM5);
|
||||
tim_marker!(pac::Tim6, 6, TIM6);
|
||||
tim_marker!(pac::Tim7, 7, TIM7);
|
||||
tim_marker!(pac::Tim8, 8, TIM8);
|
||||
tim_marker!(pac::Tim9, 9, TIM9);
|
||||
tim_marker!(pac::Tim10, 10, TIM10);
|
||||
tim_marker!(pac::Tim11, 11, TIM11);
|
||||
tim_marker!(pac::Tim12, 12, TIM12);
|
||||
tim_marker!(pac::Tim13, 13, TIM13);
|
||||
tim_marker!(pac::Tim14, 14, TIM14);
|
||||
tim_marker!(pac::Tim15, 15, TIM15);
|
||||
tim_marker!(pac::Tim16, 16, TIM16);
|
||||
tim_marker!(pac::Tim17, 17, TIM17);
|
||||
tim_marker!(pac::Tim18, 18, TIM18);
|
||||
tim_marker!(pac::Tim19, 19, TIM19);
|
||||
tim_marker!(pac::Tim20, 20, TIM20);
|
||||
tim_marker!(pac::Tim21, 21, TIM21);
|
||||
tim_marker!(pac::Tim22, 22, TIM22);
|
||||
tim_marker!(pac::Tim23, 23, TIM23);
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ValidTimAndPin<Pin: TimPin, Tim: TimInstance>: Sealed {}
|
||||
|
||||
#[macro_use]
|
||||
mod macros {
|
||||
macro_rules! pin_and_tim {
|
||||
($Px:ident, $FunSel:path, $ID:expr) => {
|
||||
impl TimPin for Pin<$Px>
|
||||
where
|
||||
$Px: PinId,
|
||||
{
|
||||
const PIN_ID: DynPinId = $Px::ID;
|
||||
const FUN_SEL: FunctionSelect = $FunSel;
|
||||
const TIM_ID: TimId = TimId::new_unchecked($ID);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "vor1x")]
|
||||
pub mod pins_vor1x;
|
||||
#[cfg(feature = "vor4x")]
|
||||
pub mod pins_vor4x;
|
||||
|
||||
//==================================================================================================
|
||||
// Timers
|
||||
//==================================================================================================
|
||||
|
||||
/// Hardware timers
|
||||
pub struct CountdownTimer {
|
||||
id: TimId,
|
||||
regs: regs::MmioTimer<'static>,
|
||||
curr_freq: Hertz,
|
||||
ref_clk: Hertz,
|
||||
rst_val: u32,
|
||||
last_cnt: u32,
|
||||
}
|
||||
|
||||
impl CountdownTimer {
|
||||
/// Create a countdown timer structure for a given TIM peripheral.
|
||||
///
|
||||
/// This does not enable the timer. You can use the [Self::load], [Self::start],
|
||||
/// [Self::enable_interrupt] and [Self::enable] API to set up and configure the countdown
|
||||
/// timer.
|
||||
#[cfg(feature = "vor1x")]
|
||||
pub fn new<Tim: TimInstance>(_tim: Tim, sys_clk: Hertz) -> Self {
|
||||
enable_tim_clk(Tim::ID);
|
||||
assert_tim_reset_for_cycles(Tim::ID, 2);
|
||||
CountdownTimer {
|
||||
id: Tim::ID,
|
||||
regs: regs::Timer::new_mmio(Tim::ID),
|
||||
ref_clk: sys_clk,
|
||||
rst_val: 0,
|
||||
curr_freq: 0.Hz(),
|
||||
last_cnt: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a countdown timer structure for a given TIM peripheral.
|
||||
///
|
||||
/// This does not enable the timer. You can use the [Self::load], [Self::start],
|
||||
/// [Self::enable_interrupt] and [Self::enable] API to set up and configure the countdown
|
||||
/// timer.
|
||||
#[cfg(feature = "vor4x")]
|
||||
pub fn new<Tim: TimInstance>(_tim: Tim, clks: &crate::clock::Clocks) -> Self {
|
||||
enable_tim_clk(Tim::ID);
|
||||
assert_tim_reset_for_cycles(Tim::ID, 2);
|
||||
CountdownTimer {
|
||||
id: Tim::ID,
|
||||
regs: regs::Timer::new_mmio(Tim::ID),
|
||||
ref_clk: clks.apb1(),
|
||||
rst_val: 0,
|
||||
curr_freq: 0.Hz(),
|
||||
last_cnt: 0,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn perid(&self) -> u32 {
|
||||
self.regs.read_perid()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn enable(&mut self) {
|
||||
self.regs
|
||||
.write_enable_control(regs::EnableControl::new_enable());
|
||||
}
|
||||
#[inline(always)]
|
||||
pub fn disable(&mut self) {
|
||||
self.regs
|
||||
.write_enable_control(regs::EnableControl::new_disable());
|
||||
}
|
||||
|
||||
#[cfg(feature = "vor1x")]
|
||||
pub fn enable_interrupt(&mut self, irq_cfg: InterruptConfig) {
|
||||
if irq_cfg.route {
|
||||
let irqsel = unsafe { pac::Irqsel::steal() };
|
||||
enable_peripheral_clock(PeripheralSelect::Irqsel);
|
||||
irqsel
|
||||
.tim(self.id.value() as usize)
|
||||
.write(|w| unsafe { w.bits(irq_cfg.id as u32) });
|
||||
}
|
||||
if irq_cfg.enable_in_nvic {
|
||||
unsafe { enable_nvic_interrupt(irq_cfg.id) };
|
||||
}
|
||||
self.regs.modify_control(|mut value| {
|
||||
value.set_irq_enable(true);
|
||||
value
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(feature = "vor4x")]
|
||||
#[inline(always)]
|
||||
pub fn enable_interrupt(&mut self, enable_in_nvic: bool) {
|
||||
if enable_in_nvic {
|
||||
unsafe { enable_nvic_interrupt(self.id.interrupt_id()) };
|
||||
}
|
||||
self.regs.modify_control(|mut value| {
|
||||
value.set_irq_enable(true);
|
||||
value
|
||||
});
|
||||
}
|
||||
|
||||
/// This function only clears the interrupt enable bit.
|
||||
///
|
||||
/// It does not mask the interrupt in the NVIC or un-route the IRQ.
|
||||
#[inline(always)]
|
||||
pub fn disable_interrupt(&mut self) {
|
||||
self.regs.modify_control(|mut value| {
|
||||
value.set_irq_enable(false);
|
||||
value
|
||||
});
|
||||
}
|
||||
|
||||
/// Calls [Self::load] to configure the specified frequency and then calls [Self::enable].
|
||||
pub fn start(&mut self, frequency: impl Into<Hertz>) {
|
||||
self.load(frequency);
|
||||
self.enable();
|
||||
}
|
||||
|
||||
/// Return `Ok` if the timer has wrapped. Peripheral will automatically clear the
|
||||
/// flag and restart the time if configured correctly
|
||||
pub fn wait(&mut self) -> nb::Result<(), Infallible> {
|
||||
let cnt = self.counter();
|
||||
if (cnt > self.last_cnt) || cnt == 0 {
|
||||
self.last_cnt = self.rst_val;
|
||||
Ok(())
|
||||
} else {
|
||||
self.last_cnt = cnt;
|
||||
Err(nb::Error::WouldBlock)
|
||||
}
|
||||
}
|
||||
|
||||
/// Load the count down timer with a timeout but do not start it.
|
||||
pub fn load(&mut self, timeout: impl Into<Hertz>) {
|
||||
self.disable();
|
||||
self.curr_freq = timeout.into();
|
||||
self.rst_val = self.ref_clk.raw() / self.curr_freq.raw();
|
||||
self.set_reload(self.rst_val);
|
||||
self.set_count(self.rst_val);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn set_reload(&mut self, val: u32) {
|
||||
self.regs.write_reset_value(val);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn set_count(&mut self, val: u32) {
|
||||
self.regs.write_count_value(val);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn counter(&self) -> u32 {
|
||||
self.regs.read_count_value()
|
||||
}
|
||||
|
||||
/// Disable the counter, setting both enable and active bit to 0
|
||||
#[inline]
|
||||
pub fn auto_disable(&mut self, enable: bool) {
|
||||
self.regs.modify_control(|mut value| {
|
||||
value.set_auto_disable(enable);
|
||||
value
|
||||
});
|
||||
}
|
||||
|
||||
/// This option only applies when the Auto-Disable functionality is 0.
|
||||
///
|
||||
/// The active bit is changed to 0 when count reaches 0, but the counter stays
|
||||
/// enabled. When Auto-Disable is 1, Auto-Deactivate is implied
|
||||
#[inline]
|
||||
pub fn auto_deactivate(&mut self, enable: bool) {
|
||||
self.regs.modify_control(|mut value| {
|
||||
value.set_auto_deactivate(enable);
|
||||
value
|
||||
});
|
||||
}
|
||||
|
||||
/// Configure the cascade parameters
|
||||
pub fn cascade_control(&mut self, ctrl: CascadeControl) {
|
||||
self.regs.write_cascade_control(
|
||||
regs::CascadeControl::builder()
|
||||
.with_trigger2(ctrl.trigger_mode_2)
|
||||
.with_inv2(ctrl.inv_src_2)
|
||||
.with_en2(ctrl.enable_stop_src_2)
|
||||
.with_trigger1(ctrl.trigger_mode_1)
|
||||
.with_trigger0(ctrl.trigger_mode_0)
|
||||
.with_dual_cascade_op(ctrl.dual_operation)
|
||||
.with_inv1(ctrl.inv_src_1)
|
||||
.with_en1(ctrl.enable_src_1)
|
||||
.with_inv0(ctrl.inv_src_0)
|
||||
.with_en0(ctrl.enable_src_0)
|
||||
.build(),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn cascade_source(
|
||||
&mut self,
|
||||
cascade_index: CascadeSelect,
|
||||
src: regs::CascadeSource,
|
||||
) -> Result<(), regs::InvalidCascadeSourceId> {
|
||||
// Safety: Index range safe by enum values.
|
||||
unsafe {
|
||||
self.regs
|
||||
.write_cascade_unchecked(cascade_index as usize, regs::CascadeSourceReg::new(src)?);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn curr_freq(&self) -> Hertz {
|
||||
self.curr_freq
|
||||
}
|
||||
|
||||
/// Disables the TIM and the dedicated TIM clock.
|
||||
pub fn stop_with_clock_disable(mut self) {
|
||||
self.disable();
|
||||
unsafe { pac::Sysconfig::steal() }
|
||||
.tim_clk_enable()
|
||||
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << self.id.value())) });
|
||||
}
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Delay implementations
|
||||
//==================================================================================================
|
||||
//
|
||||
impl embedded_hal::delay::DelayNs for CountdownTimer {
|
||||
fn delay_ns(&mut self, ns: u32) {
|
||||
let ticks = (u64::from(ns)) * (u64::from(self.ref_clk.raw())) / 1_000_000_000;
|
||||
|
||||
let full_cycles = ticks >> 32;
|
||||
let mut last_count;
|
||||
let mut new_count;
|
||||
if full_cycles > 0 {
|
||||
self.set_reload(u32::MAX);
|
||||
self.set_count(u32::MAX);
|
||||
self.enable();
|
||||
|
||||
for _ in 0..full_cycles {
|
||||
// Always ensure that both values are the same at the start.
|
||||
new_count = self.counter();
|
||||
last_count = new_count;
|
||||
loop {
|
||||
new_count = self.counter();
|
||||
if new_count == 0 {
|
||||
// Wait till timer has wrapped.
|
||||
while self.counter() == 0 {
|
||||
cortex_m::asm::nop()
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Timer has definitely wrapped.
|
||||
if new_count > last_count {
|
||||
break;
|
||||
}
|
||||
last_count = new_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
let ticks = (ticks & u32::MAX as u64) as u32;
|
||||
self.disable();
|
||||
if ticks > 1 {
|
||||
self.set_reload(ticks);
|
||||
self.set_count(ticks);
|
||||
self.enable();
|
||||
last_count = ticks;
|
||||
|
||||
loop {
|
||||
new_count = self.counter();
|
||||
if new_count == 0 || (new_count > last_count) {
|
||||
break;
|
||||
}
|
||||
last_count = new_count;
|
||||
}
|
||||
}
|
||||
|
||||
self.disable();
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn enable_tim_clk(id: TimId) {
|
||||
unsafe { pac::Sysconfig::steal() }
|
||||
.tim_clk_enable()
|
||||
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << id.value())) });
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn disable_tim_clk(id: TimId) {
|
||||
unsafe { pac::Sysconfig::steal() }
|
||||
.tim_clk_enable()
|
||||
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << (id.value()))) });
|
||||
}
|
||||
|
||||
/// Clear the reset bit of the TIM, holding it in reset
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Only the bit related to the corresponding TIM peripheral is modified
|
||||
#[inline]
|
||||
pub fn assert_tim_reset(id: TimId) {
|
||||
unsafe { pac::Peripherals::steal() }
|
||||
.sysconfig
|
||||
.tim_reset()
|
||||
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << id.value())) });
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn deassert_tim_reset(tim: TimId) {
|
||||
unsafe { pac::Peripherals::steal() }
|
||||
.sysconfig
|
||||
.tim_reset()
|
||||
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << tim.value())) });
|
||||
}
|
||||
|
||||
pub fn assert_tim_reset_for_cycles(tim: TimId, cycles: u32) {
|
||||
assert_tim_reset(tim);
|
||||
cortex_m::asm::delay(cycles);
|
||||
deassert_tim_reset(tim);
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
use super::{TimId, TimPin};
|
||||
use crate::FunctionSelect;
|
||||
use crate::pins::{
|
||||
DynPinId, Pa0, Pa1, Pa2, Pa3, Pa4, Pa5, Pa6, Pa7, Pa8, Pa9, Pa10, Pa11, Pa12, Pa13, Pa14, Pa15,
|
||||
Pa24, Pa25, Pa26, Pa27, Pa28, Pa29, Pa30, Pa31, Pb0, Pb1, Pb2, Pb3, Pb4, Pb5, Pb6, Pb10, Pb11,
|
||||
Pb12, Pb13, Pb14, Pb15, Pb16, Pb17, Pb18, Pb19, Pb20, Pb21, Pb22, Pb23, Pin, PinId,
|
||||
};
|
||||
|
||||
pin_and_tim!(Pa0, FunctionSelect::Sel1, 0);
|
||||
pin_and_tim!(Pa1, FunctionSelect::Sel1, 1);
|
||||
pin_and_tim!(Pa2, FunctionSelect::Sel1, 2);
|
||||
pin_and_tim!(Pa3, FunctionSelect::Sel1, 3);
|
||||
pin_and_tim!(Pa4, FunctionSelect::Sel1, 4);
|
||||
pin_and_tim!(Pa5, FunctionSelect::Sel1, 5);
|
||||
pin_and_tim!(Pa6, FunctionSelect::Sel1, 6);
|
||||
pin_and_tim!(Pa7, FunctionSelect::Sel1, 7);
|
||||
pin_and_tim!(Pa8, FunctionSelect::Sel1, 8);
|
||||
pin_and_tim!(Pa9, FunctionSelect::Sel1, 9);
|
||||
pin_and_tim!(Pa10, FunctionSelect::Sel1, 10);
|
||||
pin_and_tim!(Pa11, FunctionSelect::Sel1, 11);
|
||||
pin_and_tim!(Pa12, FunctionSelect::Sel1, 12);
|
||||
pin_and_tim!(Pa13, FunctionSelect::Sel1, 13);
|
||||
pin_and_tim!(Pa14, FunctionSelect::Sel1, 14);
|
||||
pin_and_tim!(Pa15, FunctionSelect::Sel1, 15);
|
||||
|
||||
pin_and_tim!(Pa24, FunctionSelect::Sel2, 16);
|
||||
pin_and_tim!(Pa25, FunctionSelect::Sel2, 17);
|
||||
pin_and_tim!(Pa26, FunctionSelect::Sel2, 18);
|
||||
pin_and_tim!(Pa27, FunctionSelect::Sel2, 19);
|
||||
pin_and_tim!(Pa28, FunctionSelect::Sel2, 20);
|
||||
pin_and_tim!(Pa29, FunctionSelect::Sel2, 21);
|
||||
pin_and_tim!(Pa30, FunctionSelect::Sel2, 22);
|
||||
pin_and_tim!(Pa31, FunctionSelect::Sel2, 23);
|
||||
|
||||
pin_and_tim!(Pb0, FunctionSelect::Sel3, 0);
|
||||
pin_and_tim!(Pb1, FunctionSelect::Sel3, 1);
|
||||
pin_and_tim!(Pb2, FunctionSelect::Sel3, 2);
|
||||
pin_and_tim!(Pb3, FunctionSelect::Sel3, 3);
|
||||
pin_and_tim!(Pb4, FunctionSelect::Sel3, 4);
|
||||
pin_and_tim!(Pb5, FunctionSelect::Sel3, 5);
|
||||
pin_and_tim!(Pb6, FunctionSelect::Sel3, 6);
|
||||
|
||||
pin_and_tim!(Pb10, FunctionSelect::Sel3, 10);
|
||||
pin_and_tim!(Pb11, FunctionSelect::Sel3, 11);
|
||||
pin_and_tim!(Pb12, FunctionSelect::Sel3, 12);
|
||||
pin_and_tim!(Pb13, FunctionSelect::Sel3, 13);
|
||||
pin_and_tim!(Pb14, FunctionSelect::Sel3, 14);
|
||||
pin_and_tim!(Pb15, FunctionSelect::Sel3, 15);
|
||||
pin_and_tim!(Pb16, FunctionSelect::Sel3, 16);
|
||||
pin_and_tim!(Pb17, FunctionSelect::Sel3, 17);
|
||||
pin_and_tim!(Pb18, FunctionSelect::Sel3, 18);
|
||||
pin_and_tim!(Pb19, FunctionSelect::Sel3, 19);
|
||||
pin_and_tim!(Pb20, FunctionSelect::Sel3, 20);
|
||||
pin_and_tim!(Pb21, FunctionSelect::Sel3, 21);
|
||||
pin_and_tim!(Pb22, FunctionSelect::Sel3, 22);
|
||||
pin_and_tim!(Pb23, FunctionSelect::Sel3, 23);
|
||||
@@ -0,0 +1,132 @@
|
||||
use super::{FunctionSelect, TimId, TimPin};
|
||||
use crate::pins::{
|
||||
DynPinId, Pa0, Pa1, Pa2, Pa3, Pa4, Pa5, Pa6, Pa7, Pa8, Pa10, Pa11, Pa12, Pa13, Pa14, Pa15, Pb0,
|
||||
Pb1, Pb2, Pb3, Pb4, Pb12, Pb13, Pb14, Pb15, Pc0, Pc1, Pd10, Pd11, Pd12, Pd13, Pd14, Pd15, Pe0,
|
||||
Pe1, Pe2, Pe3, Pe4, Pe5, Pe6, Pe7, Pe8, Pe9, Pe12, Pe13, Pe14, Pe15, Pf0, Pf1, Pf9, Pf11, Pf12,
|
||||
Pf13, Pf14, Pf15, Pg0, Pg1, Pg2, Pg3, Pg6, Pin, PinId,
|
||||
};
|
||||
#[cfg(not(feature = "va41628"))]
|
||||
use crate::pins::{
|
||||
Pb5, Pb6, Pb7, Pb8, Pb9, Pb10, Pb11, Pd0, Pd1, Pd2, Pd3, Pd4, Pd5, Pd6, Pd7, Pd8, Pd9, Pe10,
|
||||
Pe11, Pf2, Pf3, Pf4, Pf5, Pf6, Pf7, Pf8, Pf10,
|
||||
};
|
||||
|
||||
pin_and_tim!(Pa0, FunctionSelect::Sel1, 0);
|
||||
pin_and_tim!(Pa1, FunctionSelect::Sel1, 1);
|
||||
pin_and_tim!(Pa2, FunctionSelect::Sel1, 2);
|
||||
pin_and_tim!(Pa3, FunctionSelect::Sel1, 3);
|
||||
pin_and_tim!(Pa4, FunctionSelect::Sel1, 4);
|
||||
pin_and_tim!(Pa5, FunctionSelect::Sel1, 5);
|
||||
pin_and_tim!(Pa6, FunctionSelect::Sel1, 6);
|
||||
pin_and_tim!(Pa7, FunctionSelect::Sel1, 7);
|
||||
pin_and_tim!(Pa8, FunctionSelect::Sel3, 8);
|
||||
pin_and_tim!(Pa10, FunctionSelect::Sel2, 23);
|
||||
pin_and_tim!(Pa11, FunctionSelect::Sel2, 22);
|
||||
pin_and_tim!(Pa12, FunctionSelect::Sel2, 21);
|
||||
pin_and_tim!(Pa13, FunctionSelect::Sel2, 20);
|
||||
pin_and_tim!(Pa14, FunctionSelect::Sel2, 19);
|
||||
pin_and_tim!(Pa15, FunctionSelect::Sel2, 18);
|
||||
|
||||
pin_and_tim!(Pb0, FunctionSelect::Sel2, 17);
|
||||
pin_and_tim!(Pb1, FunctionSelect::Sel2, 16);
|
||||
pin_and_tim!(Pb2, FunctionSelect::Sel2, 15);
|
||||
pin_and_tim!(Pb3, FunctionSelect::Sel2, 14);
|
||||
pin_and_tim!(Pb4, FunctionSelect::Sel2, 13);
|
||||
#[cfg(not(feature = "va41628"))]
|
||||
pin_and_tim!(Pb5, FunctionSelect::Sel2, 12);
|
||||
#[cfg(not(feature = "va41628"))]
|
||||
pin_and_tim!(Pb6, FunctionSelect::Sel2, 11);
|
||||
#[cfg(not(feature = "va41628"))]
|
||||
pin_and_tim!(Pb7, FunctionSelect::Sel2, 10);
|
||||
#[cfg(not(feature = "va41628"))]
|
||||
pin_and_tim!(Pb8, FunctionSelect::Sel2, 9);
|
||||
#[cfg(not(feature = "va41628"))]
|
||||
pin_and_tim!(Pb9, FunctionSelect::Sel2, 8);
|
||||
#[cfg(not(feature = "va41628"))]
|
||||
pin_and_tim!(Pb10, FunctionSelect::Sel2, 7);
|
||||
#[cfg(not(feature = "va41628"))]
|
||||
pin_and_tim!(Pb11, FunctionSelect::Sel2, 6);
|
||||
pin_and_tim!(Pb12, FunctionSelect::Sel2, 5);
|
||||
pin_and_tim!(Pb13, FunctionSelect::Sel2, 4);
|
||||
pin_and_tim!(Pb14, FunctionSelect::Sel2, 3);
|
||||
pin_and_tim!(Pb15, FunctionSelect::Sel2, 2);
|
||||
|
||||
pin_and_tim!(Pc0, FunctionSelect::Sel2, 1);
|
||||
pin_and_tim!(Pc1, FunctionSelect::Sel2, 0);
|
||||
|
||||
#[cfg(not(feature = "va41628"))]
|
||||
pin_and_tim!(Pd0, FunctionSelect::Sel2, 0);
|
||||
#[cfg(not(feature = "va41628"))]
|
||||
pin_and_tim!(Pd1, FunctionSelect::Sel2, 1);
|
||||
#[cfg(not(feature = "va41628"))]
|
||||
pin_and_tim!(Pd2, FunctionSelect::Sel2, 2);
|
||||
#[cfg(not(feature = "va41628"))]
|
||||
pin_and_tim!(Pd3, FunctionSelect::Sel2, 3);
|
||||
#[cfg(not(feature = "va41628"))]
|
||||
pin_and_tim!(Pd4, FunctionSelect::Sel2, 4);
|
||||
#[cfg(not(feature = "va41628"))]
|
||||
pin_and_tim!(Pd5, FunctionSelect::Sel2, 5);
|
||||
#[cfg(not(feature = "va41628"))]
|
||||
pin_and_tim!(Pd6, FunctionSelect::Sel2, 6);
|
||||
#[cfg(not(feature = "va41628"))]
|
||||
pin_and_tim!(Pd7, FunctionSelect::Sel2, 7);
|
||||
#[cfg(not(feature = "va41628"))]
|
||||
pin_and_tim!(Pd8, FunctionSelect::Sel2, 8);
|
||||
#[cfg(not(feature = "va41628"))]
|
||||
pin_and_tim!(Pd9, FunctionSelect::Sel2, 9);
|
||||
pin_and_tim!(Pd10, FunctionSelect::Sel2, 10);
|
||||
pin_and_tim!(Pd11, FunctionSelect::Sel2, 11);
|
||||
pin_and_tim!(Pd12, FunctionSelect::Sel2, 12);
|
||||
pin_and_tim!(Pd13, FunctionSelect::Sel2, 13);
|
||||
pin_and_tim!(Pd14, FunctionSelect::Sel2, 14);
|
||||
pin_and_tim!(Pd15, FunctionSelect::Sel2, 15);
|
||||
|
||||
pin_and_tim!(Pe0, FunctionSelect::Sel2, 16);
|
||||
pin_and_tim!(Pe1, FunctionSelect::Sel2, 17);
|
||||
pin_and_tim!(Pe2, FunctionSelect::Sel2, 18);
|
||||
pin_and_tim!(Pe3, FunctionSelect::Sel2, 19);
|
||||
pin_and_tim!(Pe4, FunctionSelect::Sel2, 20);
|
||||
pin_and_tim!(Pe5, FunctionSelect::Sel2, 21);
|
||||
pin_and_tim!(Pe6, FunctionSelect::Sel2, 22);
|
||||
pin_and_tim!(Pe7, FunctionSelect::Sel2, 23);
|
||||
pin_and_tim!(Pe8, FunctionSelect::Sel3, 16);
|
||||
pin_and_tim!(Pe9, FunctionSelect::Sel3, 17);
|
||||
#[cfg(not(feature = "va41628"))]
|
||||
pin_and_tim!(Pe10, FunctionSelect::Sel3, 18);
|
||||
#[cfg(not(feature = "va41628"))]
|
||||
pin_and_tim!(Pe11, FunctionSelect::Sel3, 19);
|
||||
pin_and_tim!(Pe12, FunctionSelect::Sel3, 20);
|
||||
pin_and_tim!(Pe13, FunctionSelect::Sel3, 21);
|
||||
pin_and_tim!(Pe14, FunctionSelect::Sel3, 22);
|
||||
pin_and_tim!(Pe15, FunctionSelect::Sel3, 23);
|
||||
|
||||
pin_and_tim!(Pf0, FunctionSelect::Sel3, 0);
|
||||
pin_and_tim!(Pf1, FunctionSelect::Sel3, 1);
|
||||
#[cfg(not(feature = "va41628"))]
|
||||
pin_and_tim!(Pf2, FunctionSelect::Sel3, 2);
|
||||
#[cfg(not(feature = "va41628"))]
|
||||
pin_and_tim!(Pf3, FunctionSelect::Sel3, 3);
|
||||
#[cfg(not(feature = "va41628"))]
|
||||
pin_and_tim!(Pf4, FunctionSelect::Sel3, 4);
|
||||
#[cfg(not(feature = "va41628"))]
|
||||
pin_and_tim!(Pf5, FunctionSelect::Sel3, 5);
|
||||
#[cfg(not(feature = "va41628"))]
|
||||
pin_and_tim!(Pf6, FunctionSelect::Sel3, 6);
|
||||
#[cfg(not(feature = "va41628"))]
|
||||
pin_and_tim!(Pf7, FunctionSelect::Sel3, 7);
|
||||
#[cfg(not(feature = "va41628"))]
|
||||
pin_and_tim!(Pf8, FunctionSelect::Sel3, 8);
|
||||
pin_and_tim!(Pf9, FunctionSelect::Sel3, 9);
|
||||
#[cfg(not(feature = "va41628"))]
|
||||
pin_and_tim!(Pf10, FunctionSelect::Sel3, 10);
|
||||
pin_and_tim!(Pf11, FunctionSelect::Sel3, 11);
|
||||
pin_and_tim!(Pf12, FunctionSelect::Sel3, 12);
|
||||
pin_and_tim!(Pf13, FunctionSelect::Sel2, 19);
|
||||
pin_and_tim!(Pf14, FunctionSelect::Sel2, 20);
|
||||
pin_and_tim!(Pf15, FunctionSelect::Sel2, 21);
|
||||
|
||||
pin_and_tim!(Pg0, FunctionSelect::Sel2, 22);
|
||||
pin_and_tim!(Pg1, FunctionSelect::Sel2, 23);
|
||||
pin_and_tim!(Pg2, FunctionSelect::Sel1, 9);
|
||||
pin_and_tim!(Pg3, FunctionSelect::Sel1, 10);
|
||||
pin_and_tim!(Pg6, FunctionSelect::Sel1, 12);
|
||||
@@ -0,0 +1,431 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use arbitrary_int::{prelude::*, u7};
|
||||
|
||||
#[cfg(feature = "vor1x")]
|
||||
const BASE_ADDR: usize = 0x4002_0000;
|
||||
#[cfg(feature = "vor4x")]
|
||||
const BASE_ADDR: usize = 0x4001_8000;
|
||||
|
||||
#[bitbybit::bitenum(u3)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum StatusSelect {
|
||||
/// Pulse when timer reaches 0.
|
||||
OneCyclePulse = 0b000,
|
||||
OutputActiveBit = 0b001,
|
||||
/// Creates a divide by two output clock of the timer.
|
||||
ToggleOnEachCycle = 0b010,
|
||||
/// 1 when count value >= PWM A value, 0 otherwise
|
||||
PwmaOutput = 0b011,
|
||||
/// 1 when count value < PWM A value and >= PWM B, 0 when counter value >= PWM A value or < PWM
|
||||
/// B value
|
||||
PwmbOutput = 0b100,
|
||||
EnabledBit = 0b101,
|
||||
/// 1 when counter value <= PWM A value and 0 otherwise.
|
||||
PwmaActiveBit = 0b110,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, debug, defmt_fields(feature = "defmt"))]
|
||||
pub struct Control {
|
||||
/// The counter is requested to stop on the next normal count cycle.
|
||||
#[bit(9, rw)]
|
||||
request_stop: bool,
|
||||
#[bit(8, rw)]
|
||||
status_invert: bool,
|
||||
#[bits(5..=7, rw)]
|
||||
status_sel: Option<StatusSelect>,
|
||||
#[bit(4, rw)]
|
||||
irq_enable: bool,
|
||||
/// Only applies if the Auto-Disable bit is 0. The ACTIVE bit goes to 0 when the count reaches
|
||||
/// 0, but the timer remains enabled.
|
||||
#[bit(3, rw)]
|
||||
auto_deactivate: bool,
|
||||
/// Counter is fully disabled when count reaches 0, which means that both the ENABLE
|
||||
/// and ACTIVE bits go to 0.
|
||||
#[bit(2, rw)]
|
||||
auto_disable: bool,
|
||||
#[bit(1, r)]
|
||||
active: bool,
|
||||
#[bit(0, rw)]
|
||||
enable: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct EnableControl(arbitrary_int::UInt<u32, 1>);
|
||||
|
||||
impl EnableControl {
|
||||
pub fn new_disable() -> Self {
|
||||
EnableControl(arbitrary_int::UInt::<u32, 1>::from_u32(0))
|
||||
}
|
||||
|
||||
pub fn new_enable() -> Self {
|
||||
EnableControl(arbitrary_int::UInt::<u32, 1>::from_u32(1))
|
||||
}
|
||||
|
||||
pub fn enabled(&self) -> bool {
|
||||
self.0.value() != 0
|
||||
}
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Default, Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum CascadeInvert {
|
||||
#[default]
|
||||
ActiveHigh = 0,
|
||||
ActiveLow = 1,
|
||||
}
|
||||
|
||||
/// When two cascade sources are selected, configure the required operation.
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Default, Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum DualCascadeOp {
|
||||
#[default]
|
||||
LogicalAnd = 0,
|
||||
LogicalOr = 1,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug, defmt_fields(feature = "defmt"))]
|
||||
pub struct CascadeControl {
|
||||
/// The counter is automatically disabled if the corresponding Cascade 2 level-sensitive input
|
||||
/// souce is active when the count reaches 0. If the counter is not 0, the cascade control is
|
||||
/// ignored.
|
||||
#[bit(10, rw)]
|
||||
trigger2: bool,
|
||||
#[bit(9, rw)]
|
||||
inv2: CascadeInvert,
|
||||
/// Enable Cascade 2 signal active as a requirement to stop counting. This mode is similar
|
||||
/// to the REQ_STOP control bit, but signalled by a Cascade source.
|
||||
#[bit(8, rw)]
|
||||
en2: bool,
|
||||
/// Same as the trigger field for Cascade 0.
|
||||
#[bit(7, rw)]
|
||||
trigger1: bool,
|
||||
/// Enable trigger mode for Cascade 0. In trigger mode, couting will start with the selected
|
||||
/// cascade signal active, but once the counter is active, cascade control will be ignored.
|
||||
#[bit(6, rw)]
|
||||
trigger0: bool,
|
||||
/// Specify required operation if both Cascade 0 and Cascade 1 are active.
|
||||
/// 0 is a logical AND of both cascade signals, 1 is a logical OR.
|
||||
#[bit(4, rw)]
|
||||
dual_cascade_op: DualCascadeOp,
|
||||
/// Inversion bit for Cascade 1
|
||||
#[bit(3, rw)]
|
||||
inv1: CascadeInvert,
|
||||
/// Enable Cascade 1 signal active as a requirement for counting.
|
||||
#[bit(2, rw)]
|
||||
en1: bool,
|
||||
/// Inversion bit for Cascade 0.
|
||||
#[bit(1, rw)]
|
||||
inv0: CascadeInvert,
|
||||
/// Enable Cascade 0 signal active as a requirement for counting.
|
||||
#[bit(0, rw)]
|
||||
en0: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct InvalidCascadeSourceId;
|
||||
|
||||
#[cfg(feature = "vor1x")]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[repr(u8)]
|
||||
pub enum CascadeSource {
|
||||
PortA(u8),
|
||||
PortB(u8),
|
||||
Tim(u8),
|
||||
RamSbe = 96,
|
||||
RamMbe = 97,
|
||||
RomSbe = 98,
|
||||
RomMbe = 99,
|
||||
Txev = 100,
|
||||
ClockDivider(u8),
|
||||
}
|
||||
|
||||
#[cfg(feature = "vor4x")]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[repr(u8)]
|
||||
pub enum CascadeSource {
|
||||
PortA(u8),
|
||||
PortB(u8),
|
||||
PortC(u8),
|
||||
PortD(u8),
|
||||
PortE(u8),
|
||||
Tim(u8),
|
||||
TxEv,
|
||||
AdcIrq,
|
||||
RomSbe,
|
||||
RomMbe,
|
||||
Ram0Sbe,
|
||||
Ram0Mbe,
|
||||
Ram1Sbe,
|
||||
Ram1Mbe,
|
||||
WdogIrq,
|
||||
}
|
||||
|
||||
impl CascadeSource {
|
||||
#[cfg(feature = "vor1x")]
|
||||
pub fn id(&self) -> Result<u7, InvalidCascadeSourceId> {
|
||||
let port_check = |base: u8, id: u8, len: u8| -> Result<u7, InvalidCascadeSourceId> {
|
||||
if id > len - 1 {
|
||||
return Err(InvalidCascadeSourceId);
|
||||
}
|
||||
Ok(u7::new(base + id))
|
||||
};
|
||||
match self {
|
||||
CascadeSource::PortA(id) => port_check(0, *id, 32),
|
||||
CascadeSource::PortB(id) => port_check(32, *id, 32),
|
||||
CascadeSource::Tim(id) => port_check(64, *id, 24),
|
||||
CascadeSource::RamSbe => Ok(u7::new(96)),
|
||||
CascadeSource::RamMbe => Ok(u7::new(97)),
|
||||
CascadeSource::RomSbe => Ok(u7::new(98)),
|
||||
CascadeSource::RomMbe => Ok(u7::new(99)),
|
||||
CascadeSource::Txev => Ok(u7::new(100)),
|
||||
CascadeSource::ClockDivider(id) => port_check(120, *id, 8),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "vor4x")]
|
||||
fn id(&self) -> Result<u7, InvalidCascadeSourceId> {
|
||||
let port_check = |base: u8, id: u8| -> Result<u7, InvalidCascadeSourceId> {
|
||||
if id > 15 {
|
||||
return Err(InvalidCascadeSourceId);
|
||||
}
|
||||
Ok(u7::new(base + id))
|
||||
};
|
||||
match self {
|
||||
CascadeSource::PortA(id) => port_check(0, *id),
|
||||
CascadeSource::PortB(id) => port_check(16, *id),
|
||||
CascadeSource::PortC(id) => port_check(32, *id),
|
||||
CascadeSource::PortD(id) => port_check(48, *id),
|
||||
CascadeSource::PortE(id) => port_check(64, *id),
|
||||
CascadeSource::Tim(id) => {
|
||||
if *id > 23 {
|
||||
return Err(InvalidCascadeSourceId);
|
||||
}
|
||||
Ok(u7::new(80 + id))
|
||||
}
|
||||
CascadeSource::TxEv => Ok(u7::new(104)),
|
||||
CascadeSource::AdcIrq => Ok(u7::new(105)),
|
||||
CascadeSource::RomSbe => Ok(u7::new(106)),
|
||||
CascadeSource::RomMbe => Ok(u7::new(106)),
|
||||
CascadeSource::Ram0Sbe => Ok(u7::new(108)),
|
||||
CascadeSource::Ram0Mbe => Ok(u7::new(109)),
|
||||
CascadeSource::Ram1Sbe => Ok(u7::new(110)),
|
||||
CascadeSource::Ram1Mbe => Ok(u7::new(111)),
|
||||
CascadeSource::WdogIrq => Ok(u7::new(112)),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "vor1x")]
|
||||
pub fn from_raw(raw: u32) -> Result<Self, InvalidCascadeSourceId> {
|
||||
let id = u7::new((raw & 0x7F) as u8);
|
||||
if id.value() > 127 {
|
||||
return Err(InvalidCascadeSourceId);
|
||||
}
|
||||
let id = id.as_u8();
|
||||
if id < 32 {
|
||||
return Ok(CascadeSource::PortA(id));
|
||||
} else if (32..56).contains(&id) {
|
||||
return Ok(CascadeSource::PortB(id - 32));
|
||||
} else if (64..88).contains(&id) {
|
||||
return Ok(CascadeSource::Tim(id - 64));
|
||||
} else if id > 120 {
|
||||
return Ok(CascadeSource::ClockDivider(id - 120));
|
||||
}
|
||||
match id {
|
||||
96 => Ok(CascadeSource::RamSbe),
|
||||
97 => Ok(CascadeSource::RamMbe),
|
||||
98 => Ok(CascadeSource::RomSbe),
|
||||
99 => Ok(CascadeSource::RomMbe),
|
||||
100 => Ok(CascadeSource::Txev),
|
||||
_ => Err(InvalidCascadeSourceId),
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "vor4x")]
|
||||
pub fn from_raw(raw: u32) -> Result<Self, InvalidCascadeSourceId> {
|
||||
use crate::NUM_PORT_DEFAULT;
|
||||
|
||||
let id = u7::new((raw & 0x7F) as u8);
|
||||
if id.value() > 127 {
|
||||
return Err(InvalidCascadeSourceId);
|
||||
}
|
||||
let id = id.as_u8();
|
||||
if id < 16 {
|
||||
return Ok(CascadeSource::PortA(id));
|
||||
} else if (16..16 + NUM_PORT_DEFAULT as u8).contains(&id) {
|
||||
return Ok(CascadeSource::PortB(id - 16));
|
||||
} else if (32..32 + NUM_PORT_DEFAULT as u8).contains(&id) {
|
||||
return Ok(CascadeSource::PortC(id - 32));
|
||||
} else if (48..48 + NUM_PORT_DEFAULT as u8).contains(&id) {
|
||||
return Ok(CascadeSource::PortD(id - 48));
|
||||
} else if (64..64 + NUM_PORT_DEFAULT as u8).contains(&id) {
|
||||
return Ok(CascadeSource::PortE(id - 64));
|
||||
} else if (80..104).contains(&id) {
|
||||
return Ok(CascadeSource::Tim(id - 80));
|
||||
}
|
||||
match id {
|
||||
104 => Ok(CascadeSource::TxEv),
|
||||
105 => Ok(CascadeSource::AdcIrq),
|
||||
106 => Ok(CascadeSource::RomSbe),
|
||||
107 => Ok(CascadeSource::RomMbe),
|
||||
108 => Ok(CascadeSource::Ram0Sbe),
|
||||
109 => Ok(CascadeSource::Ram0Mbe),
|
||||
110 => Ok(CascadeSource::Ram1Sbe),
|
||||
111 => Ok(CascadeSource::Ram1Mbe),
|
||||
112 => Ok(CascadeSource::WdogIrq),
|
||||
_ => Err(InvalidCascadeSourceId),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
pub struct CascadeSourceReg {
|
||||
#[bits(0..=6, rw)]
|
||||
raw: u7,
|
||||
}
|
||||
|
||||
impl CascadeSourceReg {
|
||||
pub fn new(source: CascadeSource) -> Result<Self, InvalidCascadeSourceId> {
|
||||
let id = source.id()?;
|
||||
Ok(Self::new_with_raw_value(id.as_u32()))
|
||||
}
|
||||
|
||||
pub fn as_cascade_source(&self) -> Result<CascadeSource, InvalidCascadeSourceId> {
|
||||
CascadeSource::from_raw(self.raw().as_u32())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(derive_mmio::Mmio)]
|
||||
#[mmio(no_ctors)]
|
||||
#[repr(C)]
|
||||
pub struct Timer {
|
||||
control: Control,
|
||||
reset_value: u32,
|
||||
count_value: u32,
|
||||
enable_control: EnableControl,
|
||||
cascade_control: CascadeControl,
|
||||
/// CASCADE0 and CASCADE1 are used to control the counting and activation of the counter.
|
||||
/// CASCADE2 is used to request stopping of the timer.
|
||||
cascade: [CascadeSourceReg; 3],
|
||||
/// PWM A compare value.
|
||||
pwma_value: u32,
|
||||
/// PWM B compare value.
|
||||
pwmb_value: u32,
|
||||
#[cfg(feature = "vor1x")]
|
||||
_reserved: [u32; 0x3f5],
|
||||
#[cfg(feature = "vor4x")]
|
||||
_reserved: [u32; 0xf5],
|
||||
/// Vorago 1x: 0x0111_07E1. Vorago 4x: 0x0211_07E9
|
||||
perid: u32,
|
||||
}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "vor1x")] {
|
||||
static_assertions::const_assert_eq!(core::mem::size_of::<Timer>(), 0x1000);
|
||||
} else if #[cfg(feature = "vor4x")] {
|
||||
static_assertions::const_assert_eq!(core::mem::size_of::<Timer>(), 0x400);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct InvalidTimerIndex(pub usize);
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct TimId(u8);
|
||||
|
||||
impl TimId {
|
||||
pub const fn new(index: usize) -> Result<Self, InvalidTimerIndex> {
|
||||
if index > 23 {
|
||||
return Err(InvalidTimerIndex(index));
|
||||
}
|
||||
Ok(TimId(index as u8))
|
||||
}
|
||||
|
||||
pub const fn new_unchecked(index: usize) -> Self {
|
||||
if index > 23 {
|
||||
panic!("invalid timer index");
|
||||
}
|
||||
TimId(index as u8)
|
||||
}
|
||||
|
||||
/// Unsafely steal the TIM peripheral block for the TIM ID.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Circumvents ownership and safety guarantees by the HAL.
|
||||
pub const unsafe fn steal_regs(&self) -> MmioTimer<'static> {
|
||||
Timer::new_mmio(*self)
|
||||
}
|
||||
|
||||
pub const fn value(&self) -> u8 {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[cfg(feature = "vor4x")]
|
||||
pub const fn interrupt_id(&self) -> va416xx::Interrupt {
|
||||
match self.value() {
|
||||
0 => va416xx::Interrupt::TIM0,
|
||||
1 => va416xx::Interrupt::TIM1,
|
||||
2 => va416xx::Interrupt::TIM2,
|
||||
3 => va416xx::Interrupt::TIM3,
|
||||
4 => va416xx::Interrupt::TIM4,
|
||||
5 => va416xx::Interrupt::TIM5,
|
||||
6 => va416xx::Interrupt::TIM6,
|
||||
7 => va416xx::Interrupt::TIM7,
|
||||
8 => va416xx::Interrupt::TIM8,
|
||||
9 => va416xx::Interrupt::TIM9,
|
||||
10 => va416xx::Interrupt::TIM10,
|
||||
11 => va416xx::Interrupt::TIM11,
|
||||
12 => va416xx::Interrupt::TIM12,
|
||||
13 => va416xx::Interrupt::TIM13,
|
||||
14 => va416xx::Interrupt::TIM14,
|
||||
15 => va416xx::Interrupt::TIM15,
|
||||
16 => va416xx::Interrupt::TIM16,
|
||||
17 => va416xx::Interrupt::TIM17,
|
||||
18 => va416xx::Interrupt::TIM18,
|
||||
19 => va416xx::Interrupt::TIM19,
|
||||
20 => va416xx::Interrupt::TIM20,
|
||||
21 => va416xx::Interrupt::TIM21,
|
||||
22 => va416xx::Interrupt::TIM22,
|
||||
23 => va416xx::Interrupt::TIM23,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Timer {
|
||||
const fn new_mmio_at(base: usize) -> MmioTimer<'static> {
|
||||
MmioTimer {
|
||||
ptr: base as *mut _,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn new_mmio(id: TimId) -> MmioTimer<'static> {
|
||||
if cfg!(feature = "vor1x") {
|
||||
Timer::new_mmio_at(BASE_ADDR + 0x1000 * id.value() as usize)
|
||||
} else {
|
||||
Timer::new_mmio_at(BASE_ADDR + 0x400 * id.value() as usize)
|
||||
}
|
||||
}
|
||||
pub fn new_mmio_with_raw_index(
|
||||
timer_index: usize,
|
||||
) -> Result<MmioTimer<'static>, InvalidTimerIndex> {
|
||||
if timer_index > 23 {
|
||||
return Err(InvalidTimerIndex(timer_index));
|
||||
}
|
||||
if cfg!(feature = "vor1x") {
|
||||
Ok(Timer::new_mmio_at(BASE_ADDR + 0x1000 * timer_index))
|
||||
} else {
|
||||
Ok(Timer::new_mmio_at(BASE_ADDR + 0x400 * timer_index))
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user