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

This commit is contained in:
Robin Mueller
2025-10-28 21:36:14 +01:00
commit d413f01d91
989 changed files with 108422 additions and 0 deletions
+504
View File
@@ -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);
}
+56
View File
@@ -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);
+132
View File
@@ -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);
+431
View File
@@ -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))
}
}
}