>(mut self, freq: T) -> Self {
+ self.count = CountSettings::Frequency(freq.into());
+
+ self
+ }
+
+ /// Set the prescaler; PWM count runs at base_frequency/(prescaler+1)
+ pub fn prescaler(self, _prescaler: P) -> HrPwmBuilder<$TIMX, P, $PS, PINS>
+ where
+ P: HrtimPrescaler,
+ {
+ let HrPwmBuilder {
+ _tim,
+ _prescaler: _,
+ pins,
+ timer_mode,
+ fault_enable_bits,
+ fault1_bits,
+ fault2_bits,
+ enable_push_pull,
+ interleaved_mode,
+ counting_direction,
+ base_freq,
+ count,
+ preload_source,
+ repetition_counter,
+ deadtime,
+ enable_repetition_interrupt,
+ eev_cfg,
+ out1_polarity,
+ out2_polarity,
+ } = self;
+
+ let period = match count {
+ CountSettings::Frequency(_) => u16::MAX,
+ CountSettings::Period(period) => period,
+ };
+
+ let count = CountSettings::Period(period);
+
+ HrPwmBuilder {
+ _tim,
+ _prescaler: PhantomData,
+ pins,
+ timer_mode,
+ fault_enable_bits,
+ fault1_bits,
+ fault2_bits,
+ enable_push_pull,
+ interleaved_mode,
+ counting_direction,
+ base_freq,
+ count,
+ preload_source,
+ repetition_counter,
+ deadtime,
+ enable_repetition_interrupt,
+ eev_cfg,
+ out1_polarity,
+ out2_polarity,
+ }
+ }
+
+ pub fn timer_mode(mut self, timer_mode: HrTimerMode) -> Self {
+ self.timer_mode = timer_mode;
+ self
+ }
+
+ // TODO: Allow setting multiple?
+ pub fn preload(mut self, preload_source: $PS) -> Self {
+ self.preload_source = Some(preload_source);
+ self
+ }
+
+ /// Set the period; PWM count runs from 0 to period, repeating every (period+1) counts
+ pub fn period(mut self, period: u16) -> Self {
+ self.count = CountSettings::Period(period);
+ self
+ }
+
+ /// Set repetition counter, useful to reduce interrupts generated
+ /// from timer by a factor (repetition_counter + 1)
+ pub fn repetition_counter(mut self, repetition_counter: u8) -> Self {
+ self.repetition_counter = repetition_counter;
+ self
+ }
+
+ pub fn enable_repetition_interrupt(mut self) -> Self {
+ self.enable_repetition_interrupt = true;
+ self
+ }
+
+ pub fn eev_cfg(mut self, eev_cfg: EevCfgs<$TIMX>) -> Self {
+ self.eev_cfg = eev_cfg;
+ self
+ }
+ };
+}
+
+// Implement PWM configuration for timer
+macro_rules! hrtim_hal {
+ ($($TIMX:ident: $($out:ident)*,)+) => {
+ $(
+ impl HrPwmAdvExt for $TIMX {
+ type PreloadSource = PreloadSource;
+
+ fn pwm_advanced(
+ self,
+ pins: PINS,
+ rcc: &mut Rcc,
+ ) -> HrPwmBuilder
+ where
+ PINS: ToHrOut<$TIMX>,
+ {
+ // TODO: That 32x factor... Is that included below, or should we
+ // do that? Also that will likely risk overflowing u32 since
+ // 170MHz * 32 = 5.44GHz > u32::MAX.Hz()
+ let clk = HertzU64::from(HRTIM_COMMON::get_timer_frequency(&rcc.clocks)) * 32;
+
+ HrPwmBuilder {
+ _tim: PhantomData,
+ _prescaler: PhantomData,
+ pins,
+ timer_mode: HrTimerMode::Continuous,
+ fault_enable_bits: 0b000000,
+ fault1_bits: 0b00,
+ fault2_bits: 0b00,
+ counting_direction: HrCountingDirection::Up,
+ base_freq: clk,
+ count: CountSettings::Period(u16::MAX),
+ preload_source: None,
+ enable_push_pull: false,
+ interleaved_mode: InterleavedMode::Disabled,
+ repetition_counter: 0,
+ deadtime: None,
+ enable_repetition_interrupt: false,
+ eev_cfg: EevCfgs::default(),
+ out1_polarity: Polarity::ActiveHigh,
+ out2_polarity: Polarity::ActiveHigh,
+ }
+ }
+ }
+
+ impl
+ HrPwmBuilder<$TIMX, PSCL, PreloadSource, PINS>
+ where
+ PSCL: HrtimPrescaler,
+ PINS: ToHrOut<$TIMX>,
+ {
+ pub fn finalize(self, _control: &mut HrPwmControl) -> HrParts<$TIMX, PSCL, PINS::Out> {
+ hrtim_finalize_body!(
+ self, PreloadSource,
+ $TIMX, $($out)*
+ )
+ }
+
+ hrtim_common_methods!($TIMX, PreloadSource);
+
+ pub fn with_fault_source(mut self, _fault_source: FS) -> Self
+ where FS: FaultSource
+ {
+ self.fault_enable_bits |= FS::ENABLE_BITS;
+
+ self
+ }
+
+ pub fn fault_action1(mut self, fault_action1: FaultAction) -> Self {
+ self.fault1_bits = fault_action1 as _;
+
+ self
+ }
+
+ pub fn fault_action2(mut self, fault_action2: FaultAction) -> Self {
+ self.fault2_bits = fault_action2 as _;
+
+ self
+ }
+
+ pub fn out1_polarity(mut self, polarity: Polarity) -> Self {
+ self.out1_polarity = polarity;
+
+ self
+ }
+
+ pub fn out2_polarity(mut self, polarity: Polarity) -> Self {
+ self.out2_polarity = polarity;
+
+ self
+ }
+
+ /// Enable or disable Push-Pull mode
+ ///
+ /// Enabling Push-Pull mode will make output 1 and 2
+ /// alternate every period with one being
+ /// inactive and the other getting to output its wave form
+ /// as normal
+ ///
+ /// ---- . ----
+ ///out1 | | . | |
+ /// | | . | |
+ /// -------- ---------------------------- --------------------
+ /// . ------ . ------
+ ///out2 . | | . | |
+ /// . | | . | |
+ /// ------------------------ ---------------------------- --
+ ///
+ /// NOTE: setting this will overide any 'Swap Mode' set
+ pub fn push_pull_mode(mut self, enable: bool) -> Self {
+ // TODO: add check for incompatible modes
+ self.enable_push_pull = enable;
+
+ self
+ }
+
+ /// Set counting direction
+ ///
+ /// See [`HrCountingDirection`]
+ pub fn counting_direction(mut self, counting_direction: HrCountingDirection) -> Self {
+ self.counting_direction = counting_direction;
+
+ self
+ }
+
+ /// Set interleaved or half modes
+ ///
+ /// NOTE: Check [`InterleavedMode`] for more info about special cases
+ pub fn interleaved_mode(mut self, mode: InterleavedMode) -> Self {
+ self.interleaved_mode = mode;
+
+ self
+ }
+
+ pub fn deadtime(mut self, deadtime: DeadtimeConfig) -> Self {
+ self.deadtime = Some(deadtime);
+
+ self
+ }
+
+ //pub fn swap_mode(mut self, enable: bool) -> Self
+ }
+ )+
+ };
+}
+
+impl HrPwmAdvExt for HRTIM_MASTER {
+ type PreloadSource = MasterPreloadSource;
+
+ fn pwm_advanced(
+ self,
+ pins: PINS,
+ rcc: &mut Rcc,
+ ) -> HrPwmBuilder
+ where
+ PINS: ToHrOut,
+ {
+ // TODO: That 32x factor... Is that included below, or should we
+ // do that? Also that will likely risk overflowing u32 since
+ // 170MHz * 32 = 5.44GHz > u32::MAX.Hz()
+ let clk = HertzU64::from(HRTIM_COMMON::get_timer_frequency(&rcc.clocks)) * 32;
+
+ HrPwmBuilder {
+ _tim: PhantomData,
+ _prescaler: PhantomData,
+ pins,
+ timer_mode: HrTimerMode::Continuous,
+ fault_enable_bits: 0b000000,
+ fault1_bits: 0b00,
+ fault2_bits: 0b00,
+ counting_direction: HrCountingDirection::Up,
+ base_freq: clk,
+ count: CountSettings::Period(u16::MAX),
+ preload_source: None,
+ enable_push_pull: false,
+ interleaved_mode: InterleavedMode::Disabled,
+ repetition_counter: 0,
+ deadtime: None,
+ enable_repetition_interrupt: false,
+ eev_cfg: EevCfgs::default(),
+ out1_polarity: Polarity::ActiveHigh,
+ out2_polarity: Polarity::ActiveHigh,
+ }
+ }
+}
+
+impl HrPwmBuilder
+where
+ PSCL: HrtimPrescaler,
+ PINS: ToHrOut,
+{
+ pub fn finalize(self, _control: &mut HrPwmControl) -> HrParts {
+ hrtim_finalize_body!(self, MasterPreloadSource, HRTIM_MASTER,)
+ }
+
+ hrtim_common_methods!(HRTIM_MASTER, MasterPreloadSource);
+}
+
+hrtim_hal! {
+ HRTIM_TIMA: out,
+ HRTIM_TIMB: out,
+ HRTIM_TIMC: out,
+ HRTIM_TIMD: out,
+ HRTIM_TIME: out,
+ HRTIM_TIMF: out,
+}
+
+/// # Safety
+/// Only implement for valid prescalers with correct values
+pub unsafe trait HrtimPrescaler: Default {
+ const BITS: u8;
+ const VALUE: u8;
+
+ /// Minimum allowed value for compare registers used with the timer with this prescaler
+ ///
+ /// NOTE: That for CR1 and CR3, 0 is also allowed
+ const MIN_CR: u16;
+
+ /// Maximum allowed value for compare registers used with the timer with this prescaler
+ const MAX_CR: u16;
+}
+
+macro_rules! impl_pscl {
+ ($($t:ident => $b:literal, $v:literal, $min:literal, $max:literal)+) => {$(
+ #[derive(Copy, Clone, Default)]
+ pub struct $t;
+ unsafe impl HrtimPrescaler for $t {
+ const BITS: u8 = $b;
+ const VALUE: u8 = $v;
+ const MIN_CR: u16 = $min;
+ const MAX_CR: u16 = $max;
+ }
+ )+};
+}
+
+impl_pscl! {
+ Pscl1 => 0b000, 1, 0x0060, 0xFFDF
+ Pscl2 => 0b001, 2, 0x0030, 0xFFEF
+ Pscl4 => 0b010, 4, 0x0018, 0xFFF7
+ Pscl8 => 0b011, 8, 0x000C, 0xFFFB
+ Pscl16 => 0b100, 16, 0x0006, 0xFFFD
+ Pscl32 => 0b101, 32, 0x0003, 0xFFFD
+ Pscl64 => 0b110, 64, 0x0003, 0xFFFD
+ Pscl128 => 0b111, 128, 0x0003, 0xFFFD
+}
+
+/// HrTim timer
+struct TimerHrTim(PhantomData);
+
+impl pwm::TimerType for TimerHrTim {
+ // Period calculator for 16-bit hrtimers
+ //
+ // NOTE: This function will panic if the calculated period can not fit into 16 bits
+ fn calculate_frequency(base_freq: HertzU64, freq: Hertz, alignment: Alignment) -> (u32, u16) {
+ let ideal_period = pwm::Timer32Bit::calculate_frequency(base_freq, freq, alignment).0 + 1;
+
+ let prescale = u32::from(PSC::VALUE);
+
+ // Round to the nearest period
+ let period = (ideal_period + (prescale >> 1)) / prescale - 1;
+
+ // It IS possible to fail this assert
+ assert!(period <= 0xFFFF);
+
+ (period, PSC::BITS.into())
+ }
+}
diff --git a/src/hrtim/output.rs b/src/hrtim/output.rs
new file mode 100644
index 00000000..6d80b78d
--- /dev/null
+++ b/src/hrtim/output.rs
@@ -0,0 +1,220 @@
+use crate::stm32::{HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME, HRTIM_TIMF};
+use core::marker::PhantomData;
+
+use super::event::EventSource;
+use crate::{
+ gpio::{
+ self,
+ gpioa::{PA10, PA11, PA8, PA9},
+ gpiob::{PB12, PB13, PB14, PB15},
+ gpioc::{PC6, PC7, PC8, PC9},
+ Alternate, AF13, AF3,
+ },
+ pwm::{ComplementaryImpossible, Pins},
+ stm32::HRTIM_COMMON,
+};
+
+mod sealed {
+ pub trait Sealed {}
+}
+
+macro_rules! hrtim_out {
+ ($($TIMX:ident: $out_type:ident: $tXYoen:ident, $tXYodis:ident, $tXYods:ident, $setXYr:ident, $rstXYr:ident,)+) => {$(
+ impl HrOutput<$TIMX, PSCL> for $out_type<$TIMX, PSCL> {
+ fn enable(&mut self) {
+ let common = unsafe { &*HRTIM_COMMON::ptr() };
+ common.oenr().write(|w| { w.$tXYoen().set_bit() });
+ }
+
+ fn disable(&mut self) {
+ let common = unsafe { &*HRTIM_COMMON::ptr() };
+ common.odisr().write(|w| { w.$tXYodis().set_bit() });
+ }
+
+ fn enable_set_event>(&mut self, _set_event: &ES) {
+ let tim = unsafe { &*$TIMX::ptr() };
+ unsafe { tim.$setXYr().modify(|r, w| w.bits(r.bits() | ES::BITS)); }
+ }
+ fn disable_set_event>(&mut self, _set_event: &ES) {
+ let tim = unsafe { &*$TIMX::ptr() };
+ unsafe { tim.$setXYr().modify(|r, w| w.bits(r.bits() & !ES::BITS)); }
+ }
+
+ fn enable_rst_event>(&mut self, _reset_event: &ES) {
+ let tim = unsafe { &*$TIMX::ptr() };
+ unsafe { tim.$rstXYr().modify(|r, w| w.bits(r.bits() | ES::BITS)); }
+ }
+ fn disable_rst_event>(&mut self, _reset_event: &ES) {
+ let tim = unsafe { &*$TIMX::ptr() };
+ unsafe { tim.$rstXYr().modify(|r, w| w.bits(r.bits() & !ES::BITS)); }
+ }
+
+ fn get_state(&self) -> State {
+ let ods;
+ let oen;
+
+ unsafe {
+ let common = &*HRTIM_COMMON::ptr();
+ ods = common.odsr().read().$tXYods().bit_is_set();
+ oen = common.oenr().read().$tXYoen().bit_is_set();
+ }
+
+ match (oen, ods) {
+ (true, _) => State::Running,
+ (false, false) => State::Idle,
+ (false, true) => State::Fault
+ }
+ }
+ }
+ )+};
+}
+
+hrtim_out! {
+ HRTIM_TIMA: HrOut1: ta1oen, ta1odis, ta1ods, set1r, rst1r,
+ HRTIM_TIMA: HrOut2: ta2oen, ta2odis, ta2ods, set2r, rst2r,
+
+ HRTIM_TIMB: HrOut1: tb1oen, tb1odis, tb1ods, set1r, rst1r,
+ HRTIM_TIMB: HrOut2: tb2oen, tb2odis, tb2ods, set2r, rst2r,
+
+ HRTIM_TIMC: HrOut1: tc1oen, tc1odis, tc1ods, set1r, rst1r,
+ HRTIM_TIMC: HrOut2: tc2oen, tc2odis, tc2ods, set2r, rst2r,
+
+ HRTIM_TIMD: HrOut1: td1oen, td1odis, td1ods, set1r, rst1r,
+ HRTIM_TIMD: HrOut2: td2oen, td2odis, td2ods, set2r, rst2r,
+
+ HRTIM_TIME: HrOut1: te1oen, te1odis, te1ods, set1r, rst1r,
+ HRTIM_TIME: HrOut2: te2oen, te2odis, te2ods, set2r, rst2r,
+
+ HRTIM_TIMF: HrOut1: tf1oen, tf1odis, tf1ods, set1r, rst1r,
+ HRTIM_TIMF: HrOut2: tf2oen, tf2odis, tf2ods, set2r, rst2r,
+}
+
+pub trait HrOutput {
+ /// Enable this output
+ fn enable(&mut self);
+
+ /// Disable this output
+ fn disable(&mut self);
+
+ /// Set this output to active every time the specified event occurs
+ ///
+ /// NOTE: Enabling the same event for both SET and RESET
+ /// will make that event TOGGLE the output
+ fn enable_set_event>(&mut self, set_event: &ES);
+
+ /// Stop listening to the specified event
+ fn disable_set_event>(&mut self, set_event: &ES);
+
+ /// Set this output to *not* active every time the specified event occurs
+ ///
+ /// NOTE: Enabling the same event for both SET and RESET
+ /// will make that event TOGGLE the output
+ fn enable_rst_event>(&mut self, reset_event: &ES);
+
+ /// Stop listening to the specified event
+ fn disable_rst_event>(&mut self, reset_event: &ES);
+
+ /// Get current state of the output
+ fn get_state(&self) -> State;
+}
+
+#[derive(Debug, PartialEq, Copy, Clone)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub enum State {
+ Idle,
+ Running,
+ Fault,
+}
+
+impl State {
+ pub fn is_idle(self) -> bool {
+ matches!(self, State::Idle)
+ }
+
+ pub fn is_running(self) -> bool {
+ matches!(self, State::Running)
+ }
+
+ pub fn is_fault(self) -> bool {
+ matches!(self, State::Fault)
+ }
+}
+
+pub trait ToHrOut: sealed::Sealed {
+ type Out;
+
+ fn connect_to_hrtim(self);
+}
+
+impl sealed::Sealed for (PA, PB)
+where
+ PA: ToHrOut,
+ PB: ToHrOut,
+{
+}
+
+impl ToHrOut for (PA, PB)
+where
+ PA: ToHrOut,
+ PB: ToHrOut,
+{
+ type Out = (PA::Out, PB::Out);
+
+ fn connect_to_hrtim(self) {
+ self.0.connect_to_hrtim();
+ self.1.connect_to_hrtim();
+ }
+}
+
+pub struct HrOut1(PhantomData<(TIM, PSCL)>);
+pub struct HrOut2(PhantomData<(TIM, PSCL)>);
+
+macro_rules! pins {
+ ($($TIMX:ty: CH1: $CH1:ident<$CH1_AF:ident>, CH2: $CH2:ident<$CH2_AF:ident>)+) => {
+ $(
+ impl sealed::Sealed<$TIMX> for $CH1> {}
+ impl sealed::Sealed<$TIMX> for $CH2> {}
+
+ impl ToHrOut<$TIMX> for $CH1> {
+ type Out = HrOut1<$TIMX, PSCL>;
+
+ fn connect_to_hrtim(self) {
+ let _: $CH1> = self.into_alternate();
+ }
+ }
+
+ impl ToHrOut<$TIMX> for $CH2> {
+ type Out = HrOut2<$TIMX, PSCL>;
+
+ fn connect_to_hrtim(self) {
+ let _: $CH2> = self.into_alternate();
+ }
+ }
+ )+
+ }
+}
+
+pins! {
+ HRTIM_TIMA: CH1: PA8, CH2: PA9
+
+ HRTIM_TIMB: CH1: PA10, CH2: PA11
+ HRTIM_TIMC: CH1: PB12, CH2: PB13
+ HRTIM_TIMD: CH1: PB14, CH2: PB15
+
+ HRTIM_TIME: CH1: PC8, CH2: PC9
+ HRTIM_TIMF: CH1: PC6, CH2: PC7
+}
+
+impl Pins for () {
+ type Channel = ();
+}
+
+impl sealed::Sealed for () {}
+impl ToHrOut for () {
+ type Out = ();
+
+ fn connect_to_hrtim(self) {}
+}
+
+pub struct CH1(PhantomData);
+pub struct CH2(PhantomData);
diff --git a/src/hrtim/output.rs_old b/src/hrtim/output.rs_old
new file mode 100644
index 00000000..0ab07d6d
--- /dev/null
+++ b/src/hrtim/output.rs_old
@@ -0,0 +1,300 @@
+use core::marker::PhantomData;
+use stm32g4::stm32g474::{
+ HRTIM_MASTER, HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME, HRTIM_TIMF,
+};
+use crate::hrtim::external_event_old::ExternalEventSource;
+
+use super::event::{EventSource, NeighborTimerEventSource};
+use crate::{
+ gpio::{
+ gpioa::{PA10, PA11, PA8, PA9},
+ gpiob::{PB12, PB13, PB14, PB15},
+ gpioc::{PC6, PC7, PC8, PC9},
+ Alternate, AF13, AF3,
+ },
+ pwm::{ActiveHigh, ComplementaryImpossible, Pins, Pwm},
+ stm32::HRTIM_COMMON,
+};
+
+macro_rules! hrtim_out_common {
+ ($TIMX:ident, $set_event:expr, $register:ident, $action:ident) => {{
+ let tim = unsafe { &*$TIMX::ptr() };
+
+ match $set_event {
+ EventSource::Cr1 { .. } => tim.$register.modify(|_r, w| w.cmp1().$action()),
+ EventSource::Cr2 { .. } => tim.$register.modify(|_r, w| w.cmp2().$action()),
+ EventSource::Cr3 { .. } => tim.$register.modify(|_r, w| w.cmp3().$action()),
+ EventSource::Cr4 { .. } => tim.$register.modify(|_r, w| w.cmp4().$action()),
+ EventSource::Period { .. } => tim.$register.modify(|_r, w| w.per().$action()),
+
+ EventSource::MasterCr1 { .. } => tim.$register.modify(|_r, w| w.mstcmp1().$action()),
+ EventSource::MasterCr2 { .. } => tim.$register.modify(|_r, w| w.mstcmp2().$action()),
+ EventSource::MasterCr3 { .. } => tim.$register.modify(|_r, w| w.mstcmp3().$action()),
+ EventSource::MasterCr4 { .. } => tim.$register.modify(|_r, w| w.mstcmp4().$action()),
+ EventSource::MasterPeriod { .. } => tim.$register.modify(|_r, w| w.mstper().$action()),
+
+ EventSource::ExternalEvent(e) => match e {
+ ExternalEventSource::Eevnt1 { .. } => {
+ tim.$register.modify(|_r, w| w.extevnt1().$action())
+ },
+ ExternalEventSource::Eevnt2 { .. } => {
+ tim.$register.modify(|_r, w| w.extevnt2().$action())
+ },
+ ExternalEventSource::Eevnt3 { .. } => {
+ tim.$register.modify(|_r, w| w.extevnt3().$action())
+ },
+ ExternalEventSource::Eevnt4 { .. } => {
+ tim.$register.modify(|_r, w| w.extevnt4().$action())
+ },
+ ExternalEventSource::Eevnt5 { .. } => {
+ tim.$register.modify(|_r, w| w.extevnt5().$action())
+ },
+ ExternalEventSource::Eevnt6 { .. } => {
+ tim.$register.modify(|_r, w| w.extevnt6().$action())
+ },
+ ExternalEventSource::Eevnt7 { .. } => {
+ tim.$register.modify(|_r, w| w.extevnt7().$action())
+ },
+ ExternalEventSource::Eevnt8 { .. } => {
+ tim.$register.modify(|_r, w| w.extevnt8().$action())
+ },
+ ExternalEventSource::Eevnt9 { .. } => {
+ tim.$register.modify(|_r, w| w.extevnt9().$action())
+ },
+ ExternalEventSource::Eevnt10 { .. } => {
+ tim.$register.modify(|_r, w| w.extevnt10().$action())
+ },
+ }
+
+ EventSource::NeighborTimer { n } => match n {
+ NeighborTimerEventSource::TimEvent1 { .. } => {
+ tim.$register.modify(|_r, w| w.timevnt1().$action())
+ }
+ NeighborTimerEventSource::TimEvent2 { .. } => {
+ tim.$register.modify(|_r, w| w.timevnt2().$action())
+ }
+ NeighborTimerEventSource::TimEvent3 { .. } => {
+ tim.$register.modify(|_r, w| w.timevnt3().$action())
+ }
+ NeighborTimerEventSource::TimEvent4 { .. } => {
+ tim.$register.modify(|_r, w| w.timevnt4().$action())
+ }
+ NeighborTimerEventSource::TimEvent5 { .. } => {
+ tim.$register.modify(|_r, w| w.timevnt5().$action())
+ }
+ NeighborTimerEventSource::TimEvent6 { .. } => {
+ tim.$register.modify(|_r, w| w.timevnt6().$action())
+ }
+ NeighborTimerEventSource::TimEvent7 { .. } => {
+ tim.$register.modify(|_r, w| w.timevnt7().$action())
+ }
+ NeighborTimerEventSource::TimEvent8 { .. } => {
+ tim.$register.modify(|_r, w| w.timevnt8().$action())
+ }
+ NeighborTimerEventSource::TimEvent9 { .. } => {
+ tim.$register.modify(|_r, w| w.timevnt9().$action())
+ }
+ },
+ }
+ }};
+}
+
+macro_rules! hrtim_out {
+ ($($TIMX:ident: $out_type:ident: $tXYoen:ident, $tXYodis:ident, $tXYods:ident, $setXYr:ident, $rstXYr:ident,)+) => {$(
+ impl HrOutput for $out_type<$TIMX, PSCL> {
+ fn enable(&mut self) {
+ let common = unsafe { &*HRTIM_COMMON::ptr() };
+ common.oenr.write(|w| { w.$tXYoen().set_bit() });
+ }
+
+ fn disable(&mut self) {
+ let common = unsafe { &*HRTIM_COMMON::ptr() };
+ common.odisr.write(|w| { w.$tXYodis().set_bit() });
+ }
+
+ fn enable_set_event(&mut self, set_event: impl Into>) {
+ hrtim_out_common!($TIMX, set_event.into(), $setXYr, set_bit)
+ }
+ fn disable_set_event(&mut self, set_event: impl Into>) {
+ hrtim_out_common!($TIMX, set_event.into(), $setXYr, clear_bit)
+ }
+
+ fn enable_rst_event(&mut self, reset_event: impl Into>) {
+ hrtim_out_common!($TIMX, reset_event.into(), $rstXYr, set_bit)
+ }
+ fn disable_rst_event(&mut self, reset_event: impl Into>) {
+ hrtim_out_common!($TIMX, reset_event.into(), $rstXYr, clear_bit)
+ }
+
+ fn get_state(&self) -> State {
+ let ods;
+ let oen;
+
+ unsafe {
+ let common = &*HRTIM_COMMON::ptr();
+ ods = common.odsr.read().$tXYods().bit_is_set();
+ oen = common.oenr.read().$tXYoen().bit_is_set();
+ }
+
+ match (oen, ods) {
+ (true, _) => State::Running,
+ (false, false) => State::Idle,
+ (false, true) => State::Fault
+ }
+ }
+ }
+ )+};
+}
+
+hrtim_out! {
+ HRTIM_TIMA: HrOut1: ta1oen, ta1odis, ta1ods, seta1r, rsta1r,
+ HRTIM_TIMA: HrOut2: ta2oen, ta2odis, ta2ods, seta2r, rsta2r,
+
+ HRTIM_TIMB: HrOut1: tb1oen, tb1odis, tb1ods, setb1r, rstb1r,
+ HRTIM_TIMB: HrOut2: tb2oen, tb2odis, tb2ods, setb2r, rstb2r,
+
+ HRTIM_TIMC: HrOut1: tc1oen, tc1odis, tc1ods, setc1r, rstc1r,
+ HRTIM_TIMC: HrOut2: tc2oen, tc2odis, tc2ods, setc2r, rstc2r,
+
+ HRTIM_TIMD: HrOut1: td1oen, td1odis, td1ods, setd1r, rstd1r,
+ HRTIM_TIMD: HrOut2: td2oen, td2odis, td2ods, setd2r, rstd2r,
+
+ HRTIM_TIME: HrOut1: te1oen, te1odis, te1ods, sete1r, rste1r,
+ HRTIM_TIME: HrOut2: te2oen, te2odis, te2ods, sete2r, rste2r,
+
+ HRTIM_TIMF: HrOut1: tf1oen, tf1odis, tf1ods, setf1r, rstf1r,
+ HRTIM_TIMF: HrOut2: tf2oen, tf2odis, tf2ods, setf2r, rstf2r,
+}
+
+pub trait HrOutput {
+ /// Enable this output
+ fn enable(&mut self);
+
+ /// Disable this output
+ fn disable(&mut self);
+
+ /// Set this output to active every time the specified event occurs
+ ///
+ /// NOTE: Enabling the same event for both SET and RESET
+ /// will make that event TOGGLE the output
+ fn enable_set_event(&mut self, set_event: impl Into>);
+
+ /// Stop listening to the specified event
+ fn disable_set_event(&mut self, set_event: impl Into>);
+
+ /// Set this output to *not* active every time the specified event occurs
+ ///
+ /// NOTE: Enabling the same event for both SET and RESET
+ /// will make that event TOGGLE the output
+ fn enable_rst_event(&mut self, reset_event: impl Into>);
+
+ /// Stop listening to the specified event
+ fn disable_rst_event(&mut self, reset_event: impl Into>);
+
+ /// Get current state of the output
+ fn get_state(&self) -> State;
+}
+
+#[derive(Debug, PartialEq)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub enum State {
+ Idle,
+ Running,
+ Fault,
+}
+
+pub unsafe trait ToHrOut {
+ type Out: ToHrOut;
+}
+
+unsafe impl ToHrOut for (PA, PB)
+where
+ PA: ToHrOut,
+ PB: ToHrOut,
+{
+ type Out = (PA::Out, PB::Out);
+}
+
+pub struct HrOut1(PhantomData<(TIM, PSCL)>);
+pub struct HrOut2(PhantomData<(TIM, PSCL)>);
+
+macro_rules! pins {
+ ($($TIMX:ty: CH1: $CH1:ty, CH2: $CH2:ty)+) => {
+ $(
+ impl Pins<$TIMX, CH1, ComplementaryImpossible> for $CH1 {
+ type Channel = Pwm<$TIMX, CH1, ComplementaryImpossible, ActiveHigh, ActiveHigh>;
+ }
+
+ impl Pins<$TIMX, CH2, ComplementaryImpossible> for $CH2 {
+ type Channel = Pwm<$TIMX, CH2, ComplementaryImpossible, ActiveHigh, ActiveHigh>;
+ }
+
+ unsafe impl ToHrOut for $CH1 {
+ type Out = HrOut1<$TIMX, PSCL>;
+ }
+
+ unsafe impl ToHrOut for $CH2 {
+ type Out = HrOut2<$TIMX, PSCL>;
+ }
+
+ unsafe impl ToHrOut for HrOut1<$TIMX, PSCL> {
+ type Out = HrOut1<$TIMX, P>;
+ }
+
+ unsafe impl ToHrOut for HrOut2<$TIMX, PSCL> {
+ type Out = HrOut2<$TIMX, P>;
+ }
+ )+
+ }
+}
+
+pins! {
+ HRTIM_TIMA: CH1: PA8>, CH2: PA9>
+
+ HRTIM_TIMB: CH1: PA10>, CH2: PA11>
+ HRTIM_TIMC: CH1: PB12>, CH2: PB13>
+ HRTIM_TIMD: CH1: PB14>, CH2: PB15>
+
+ HRTIM_TIME: CH1: PC8>, CH2: PC9>
+ HRTIM_TIMF: CH1: PC6>, CH2: PC7>
+}
+
+impl Pins for () {
+ type Channel = ();
+}
+
+unsafe impl ToHrOut for () {
+ type Out = ();
+}
+
+// automatically implement Pins trait for tuples of individual pins
+macro_rules! pins_tuples {
+ // Tuple of two pins
+ ($(($CHA:ident, $CHB:ident)),*) => {
+ $(
+ impl Pins, $CHB), (TA, TB)> for (CHA, CHB)
+ where
+ CHA: Pins, TA>,
+ CHB: Pins, TB>,
+ {
+ type Channel = (Pwm, TA, ActiveHigh, ActiveHigh>, Pwm, TB, ActiveHigh, ActiveHigh>);
+ }
+
+ impl HrtimChannel for ($CHA, $CHB) {}
+ )*
+ };
+}
+
+pins_tuples! {
+ (CH1, CH2),
+ (CH2, CH1)
+}
+
+pub struct CH1(PhantomData);
+pub struct CH2(PhantomData);
+
+impl HrtimChannel