diff --git a/embassy-stm32/src/timer/one_pulse.rs b/embassy-stm32/src/timer/one_pulse.rs index 47c1d7f49..e89ad8390 100644 --- a/embassy-stm32/src/timer/one_pulse.rs +++ b/embassy-stm32/src/timer/one_pulse.rs @@ -7,7 +7,7 @@ use core::pin::Pin; use core::task::{Context, Poll}; use super::low_level::{ - CountingMode, FilterValue, InputCaptureMode, InputTISelection, SlaveMode, Timer, TriggerSource, + CountingMode, FilterValue, InputCaptureMode, InputTISelection, SlaveMode, Timer, TriggerSource as Ts, }; use super::{CaptureCompareInterruptHandler, ExternalTriggerPin, GeneralInstance4Channel, TimerChannel, TimerPin}; pub use super::{Ch1, Ch2}; @@ -46,33 +46,71 @@ pub struct TriggerPin<'d, T, C> { phantom: PhantomData<(T, C)>, } -// TODO: Generify trigger inputs +trait SealedTriggerSource {} -impl<'d, T: GeneralInstance4Channel> TriggerPin<'d, T, Ch1> { +/// Marker trait for a trigger source. +#[expect(private_bounds)] +pub trait TriggerSource: SealedTriggerSource {} + +impl TriggerSource for Ch1 {} +impl TriggerSource for Ch2 {} +impl TriggerSource for Ext {} + +impl SealedTriggerSource for Ch1 {} +impl SealedTriggerSource for Ch2 {} +impl SealedTriggerSource for Ext {} + +trait SealedTimerTriggerPin: crate::gpio::Pin {} + +/// Marker trait for a trigger pin. +#[expect(private_bounds)] +// TODO: find better naming scheme than prefixing all pin traits with "Timer". +// The trait name cannot conflict with the corresponding type's name. +// Applies to other timer submodules as well. +pub trait TimerTriggerPin: SealedTimerTriggerPin { + /// Get the AF number needed to use this pin as a trigger source. + fn af_num(&self) -> u8; +} + +impl TimerTriggerPin for P +where + T: GeneralInstance4Channel, + P: TimerPin, + C: super::Channel + TriggerSource, +{ + fn af_num(&self) -> u8 { + TimerPin::af_num(self) + } +} + +impl TimerTriggerPin for P +where + T: GeneralInstance4Channel, + P: ExternalTriggerPin, +{ + fn af_num(&self) -> u8 { + ExternalTriggerPin::af_num(self) + } +} + +impl SealedTimerTriggerPin for P +where + T: GeneralInstance4Channel, + P: TimerPin, + C: super::Channel + TriggerSource, +{ +} + +impl SealedTimerTriggerPin for P +where + T: GeneralInstance4Channel, + P: ExternalTriggerPin, +{ +} + +impl<'d, T: GeneralInstance4Channel, C: TriggerSource> TriggerPin<'d, T, C> { /// "Create a new Ch1 trigger pin instance. - pub fn new_ch1(pin: Peri<'d, impl TimerPin>, pull: Pull) -> Self { - pin.set_as_af(pin.af_num(), AfType::input(pull)); - TriggerPin { - _pin: pin.into(), - phantom: PhantomData, - } - } -} - -impl<'d, T: GeneralInstance4Channel> TriggerPin<'d, T, Ch2> { - /// "Create a new Ch2 trigger pin instance. - pub fn new_ch2(pin: Peri<'d, impl TimerPin>, pull: Pull) -> Self { - pin.set_as_af(pin.af_num(), AfType::input(pull)); - TriggerPin { - _pin: pin.into(), - phantom: PhantomData, - } - } -} - -impl<'d, T: GeneralInstance4Channel> TriggerPin<'d, T, Ext> { - /// "Create a new EXT trigger pin instance. - pub fn new_ext(pin: Peri<'d, impl ExternalTriggerPin>, pull: Pull) -> Self { + pub fn new(pin: Peri<'d, impl TimerTriggerPin>, pull: Pull) -> Self { pin.set_as_af(pin.af_num(), AfType::input(pull)); TriggerPin { _pin: pin.into(), @@ -103,7 +141,7 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> { ) -> Self { let mut this = Self { inner: Timer::new(tim) }; - this.inner.set_trigger_source(TriggerSource::TI1F_ED); + this.inner.set_trigger_source(Ts::TI1F_ED); this.inner .set_input_ti_selection(TimerChannel::Ch1, InputTISelection::Normal); this.inner @@ -128,7 +166,7 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> { ) -> Self { let mut this = Self { inner: Timer::new(tim) }; - this.inner.set_trigger_source(TriggerSource::TI1FP1); + this.inner.set_trigger_source(Ts::TI1FP1); this.inner .set_input_ti_selection(TimerChannel::Ch1, InputTISelection::Normal); this.inner @@ -154,7 +192,7 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> { ) -> Self { let mut this = Self { inner: Timer::new(tim) }; - this.inner.set_trigger_source(TriggerSource::TI2FP2); + this.inner.set_trigger_source(Ts::TI2FP2); this.inner .set_input_ti_selection(TimerChannel::Ch2, InputTISelection::Normal); this.inner @@ -186,7 +224,7 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> { // No filtering r.set_etf(FilterValue::NO_FILTER); }); - this.inner.set_trigger_source(TriggerSource::ETRF); + this.inner.set_trigger_source(Ts::ETRF); this.new_inner(freq, pulse_end, counting_mode); this diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs index bc7e71290..657052cfa 100644 --- a/embassy-stm32/src/timer/qei.rs +++ b/embassy-stm32/src/timer/qei.rs @@ -8,6 +8,7 @@ use super::low_level::Timer; pub use super::{Ch1, Ch2}; use super::{GeneralInstance4Channel, TimerPin}; use crate::gpio::{AfType, AnyPin, Pull}; +use crate::timer::Channel; use crate::Peri; /// Counting direction @@ -24,28 +25,31 @@ pub struct QeiPin<'d, T, Channel> { phantom: PhantomData<(T, Channel)>, } -// TODO: generify QEI channels - -macro_rules! channel_impl { - ($new_chx:ident, $channel:ident, $pin_trait:ident) => { - impl<'d, T: GeneralInstance4Channel> QeiPin<'d, T, $channel> { - #[doc = concat!("Create a new ", stringify!($channel), " QEI pin instance.")] - pub fn $new_chx(pin: Peri<'d, impl $pin_trait>) -> Self { - critical_section::with(|_| { - pin.set_low(); - pin.set_as_af(pin.af_num(), AfType::input(Pull::None)); - }); - QeiPin { - _pin: pin.into(), - phantom: PhantomData, - } - } +impl<'d, T: GeneralInstance4Channel, C: QeiChannel> QeiPin<'d, T, C> { + /// Create a new QEI pin instance. + pub fn new(pin: Peri<'d, impl TimerPin>) -> Self { + critical_section::with(|_| { + pin.set_low(); + pin.set_as_af(pin.af_num(), AfType::input(Pull::None)); + }); + QeiPin { + _pin: pin.into(), + phantom: PhantomData, } - }; + } } -channel_impl!(new_ch1, Ch1, TimerPin); -channel_impl!(new_ch2, Ch2, TimerPin); +trait SealedQeiChannel: Channel {} + +/// Marker trait for a timer channel eligible for use with QEI. +#[expect(private_bounds)] +pub trait QeiChannel: SealedQeiChannel {} + +impl QeiChannel for Ch1 {} +impl QeiChannel for Ch2 {} + +impl SealedQeiChannel for Ch1 {} +impl SealedQeiChannel for Ch2 {} /// Quadrature decoder driver. pub struct Qei<'d, T: GeneralInstance4Channel> {