diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 8143c9a23..13fc23e54 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1090,21 +1090,21 @@ fn main() { (("fmc", "CLK"), quote!(crate::fmc::ClkPin)), (("fmc", "BA0"), quote!(crate::fmc::BA0Pin)), (("fmc", "BA1"), quote!(crate::fmc::BA1Pin)), - (("timer", "CH1"), quote!(crate::timer::Channel1Pin)), - (("timer", "CH1N"), quote!(crate::timer::Channel1ComplementaryPin)), - (("timer", "CH2"), quote!(crate::timer::Channel2Pin)), - (("timer", "CH2N"), quote!(crate::timer::Channel2ComplementaryPin)), - (("timer", "CH3"), quote!(crate::timer::Channel3Pin)), - (("timer", "CH3N"), quote!(crate::timer::Channel3ComplementaryPin)), - (("timer", "CH4"), quote!(crate::timer::Channel4Pin)), - (("timer", "CH4N"), quote!(crate::timer::Channel4ComplementaryPin)), + (("timer", "CH1"), quote!(crate::timer::TimerPin)), + (("timer", "CH1N"), quote!(crate::timer::TimerComplementaryPin)), + (("timer", "CH2"), quote!(crate::timer::TimerPin)), + (("timer", "CH2N"), quote!(crate::timer::TimerComplementaryPin)), + (("timer", "CH3"), quote!(crate::timer::TimerPin)), + (("timer", "CH3N"), quote!(crate::timer::TimerComplementaryPin)), + (("timer", "CH4"), quote!(crate::timer::TimerPin)), + (("timer", "CH4N"), quote!(crate::timer::TimerComplementaryPin)), (("timer", "ETR"), quote!(crate::timer::ExternalTriggerPin)), - (("timer", "BKIN"), quote!(crate::timer::BreakInputPin)), - (("timer", "BKIN_COMP1"), quote!(crate::timer::BreakInputComparator1Pin)), - (("timer", "BKIN_COMP2"), quote!(crate::timer::BreakInputComparator2Pin)), - (("timer", "BKIN2"), quote!(crate::timer::BreakInput2Pin)), - (("timer", "BKIN2_COMP1"), quote!(crate::timer::BreakInput2Comparator1Pin)), - (("timer", "BKIN2_COMP2"), quote!(crate::timer::BreakInput2Comparator2Pin)), + (("timer", "BKIN"), quote!(crate::timer::BreakInputPin)), + (("timer", "BKIN_COMP1"), quote!(crate::timer::BreakInputComparator1Pin)), + (("timer", "BKIN_COMP2"), quote!(crate::timer::BreakInputComparator2Pin)), + (("timer", "BKIN2"), quote!(crate::timer::BreakInputPin)), + (("timer", "BKIN2_COMP1"), quote!(crate::timer::BreakInputComparator1Pin)), + (("timer", "BKIN2_COMP2"), quote!(crate::timer::BreakInputComparator2Pin)), (("hrtim", "CHA1"), quote!(crate::hrtim::ChannelAPin)), (("hrtim", "CHA2"), quote!(crate::hrtim::ChannelAComplementaryPin)), (("hrtim", "CHB1"), quote!(crate::hrtim::ChannelBPin)), @@ -1475,10 +1475,10 @@ fn main() { (("hash", "IN"), quote!(crate::hash::Dma)), (("cryp", "IN"), quote!(crate::cryp::DmaIn)), (("cryp", "OUT"), quote!(crate::cryp::DmaOut)), - (("timer", "CH1"), quote!(crate::timer::Ch1Dma)), - (("timer", "CH2"), quote!(crate::timer::Ch2Dma)), - (("timer", "CH3"), quote!(crate::timer::Ch3Dma)), - (("timer", "CH4"), quote!(crate::timer::Ch4Dma)), + (("timer", "CH1"), quote!(crate::timer::Dma)), + (("timer", "CH2"), quote!(crate::timer::Dma)), + (("timer", "CH3"), quote!(crate::timer::Dma)), + (("timer", "CH4"), quote!(crate::timer::Dma)), (("cordic", "WRITE"), quote!(crate::cordic::WriteDma)), // FIXME: stm32u5a crash on Cordic driver (("cordic", "READ"), quote!(crate::cordic::ReadDma)), // FIXME: stm32u5a crash on Cordic driver ] diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index 8eec6c0c7..a450705a2 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs @@ -5,14 +5,12 @@ use core::marker::PhantomData; use stm32_metapac::timer::vals::Ckd; use super::low_level::{CountingMode, OutputPolarity, Timer}; -use super::simple_pwm::{Ch1, Ch2, Ch3, Ch4, PwmPin}; -use super::{ - AdvancedInstance4Channel, Channel, Channel1ComplementaryPin, Channel2ComplementaryPin, Channel3ComplementaryPin, - Channel4ComplementaryPin, -}; +use super::simple_pwm::PwmPin; +use super::{AdvancedInstance4Channel, Ch1, Ch2, Ch3, Ch4, Channel, TimerComplementaryPin}; use crate::gpio::{AnyPin, OutputType}; use crate::time::Hertz; use crate::timer::low_level::OutputCompareMode; +use crate::timer::TimerChannel; use crate::Peri; /// Complementary PWM pin wrapper. @@ -23,32 +21,23 @@ pub struct ComplementaryPwmPin<'d, T, C> { phantom: PhantomData<(T, C)>, } -macro_rules! complementary_channel_impl { - ($new_chx:ident, $channel:ident, $pin_trait:ident) => { - impl<'d, T: AdvancedInstance4Channel> ComplementaryPwmPin<'d, T, $channel> { - #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")] - pub fn $new_chx(pin: Peri<'d, impl $pin_trait>, output_type: OutputType) -> Self { - critical_section::with(|_| { - pin.set_low(); - pin.set_as_af( - pin.af_num(), - crate::gpio::AfType::output(output_type, crate::gpio::Speed::VeryHigh), - ); - }); - ComplementaryPwmPin { - _pin: pin.into(), - phantom: PhantomData, - } - } +impl<'d, T: AdvancedInstance4Channel, C: TimerChannel> ComplementaryPwmPin<'d, T, C> { + /// Create a new complementary PWM pin instance. + pub fn new(pin: Peri<'d, impl TimerComplementaryPin>, output_type: OutputType) -> Self { + critical_section::with(|_| { + pin.set_low(); + pin.set_as_af( + pin.af_num(), + crate::gpio::AfType::output(output_type, crate::gpio::Speed::VeryHigh), + ); + }); + ComplementaryPwmPin { + _pin: pin.into(), + phantom: PhantomData, } - }; + } } -complementary_channel_impl!(new_ch1, Ch1, Channel1ComplementaryPin); -complementary_channel_impl!(new_ch2, Ch2, Channel2ComplementaryPin); -complementary_channel_impl!(new_ch3, Ch3, Channel3ComplementaryPin); -complementary_channel_impl!(new_ch4, Ch4, Channel4ComplementaryPin); - /// PWM driver with support for standard and complementary outputs. pub struct ComplementaryPwm<'d, T: AdvancedInstance4Channel> { inner: Timer<'d, T>, diff --git a/embassy-stm32/src/timer/input_capture.rs b/embassy-stm32/src/timer/input_capture.rs index ec8b1ddf1..dda33e7f1 100644 --- a/embassy-stm32/src/timer/input_capture.rs +++ b/embassy-stm32/src/timer/input_capture.rs @@ -6,14 +6,12 @@ use core::pin::Pin; use core::task::{Context, Poll}; use super::low_level::{CountingMode, FilterValue, InputCaptureMode, InputTISelection, Timer}; -use super::{ - CaptureCompareInterruptHandler, Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, - GeneralInstance4Channel, -}; +use super::{CaptureCompareInterruptHandler, Channel, GeneralInstance4Channel, TimerPin}; pub use super::{Ch1, Ch2, Ch3, Ch4}; use crate::gpio::{AfType, AnyPin, Pull}; use crate::interrupt::typelevel::{Binding, Interrupt}; use crate::time::Hertz; +use crate::timer::TimerChannel; use crate::Peri; /// Capture pin wrapper. @@ -23,27 +21,17 @@ pub struct CapturePin<'d, T, C> { _pin: Peri<'d, AnyPin>, phantom: PhantomData<(T, C)>, } - -macro_rules! channel_impl { - ($new_chx:ident, $channel:ident, $pin_trait:ident) => { - impl<'d, T: GeneralInstance4Channel> CapturePin<'d, T, $channel> { - #[doc = concat!("Create a new ", stringify!($channel), " capture pin instance.")] - pub fn $new_chx(pin: Peri<'d, impl $pin_trait>, pull: Pull) -> Self { - pin.set_as_af(pin.af_num(), AfType::input(pull)); - CapturePin { - _pin: pin.into(), - phantom: PhantomData, - } - } +impl<'d, T: GeneralInstance4Channel, C: TimerChannel> CapturePin<'d, T, C> { + /// Create a new capture pin instance. + pub fn new(pin: Peri<'d, impl TimerPin>, pull: Pull) -> Self { + pin.set_as_af(pin.af_num(), AfType::input(pull)); + CapturePin { + _pin: pin.into(), + phantom: PhantomData, } - }; + } } -channel_impl!(new_ch1, Ch1, Channel1Pin); -channel_impl!(new_ch2, Ch2, Channel2Pin); -channel_impl!(new_ch3, Ch3, Channel3Pin); -channel_impl!(new_ch4, Ch4, Channel4Pin); - /// Input capture driver. pub struct InputCapture<'d, T: GeneralInstance4Channel> { inner: Timer<'d, T>, diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index b29382fc8..7062f5f4c 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -51,6 +51,80 @@ pub enum Ch3 {} /// Channel 4 marker type. pub enum Ch4 {} +/// Timer channel trait. +#[allow(private_bounds)] +pub trait TimerChannel: SealedTimerChannel { + /// The runtime channel. + const CHANNEL: Channel; +} + +trait SealedTimerChannel {} + +impl TimerChannel for Ch1 { + const CHANNEL: Channel = Channel::Ch1; +} + +impl TimerChannel for Ch2 { + const CHANNEL: Channel = Channel::Ch2; +} + +impl TimerChannel for Ch3 { + const CHANNEL: Channel = Channel::Ch3; +} + +impl TimerChannel for Ch4 { + const CHANNEL: Channel = Channel::Ch4; +} + +impl SealedTimerChannel for Ch1 {} +impl SealedTimerChannel for Ch2 {} +impl SealedTimerChannel for Ch3 {} +impl SealedTimerChannel for Ch4 {} + +/// Timer break input. +#[derive(Clone, Copy)] +pub enum BkIn { + /// Break input 1. + BkIn1, + /// Break input 2. + BkIn2, +} + +impl BkIn { + /// Get the channel index (0..3) + pub fn index(&self) -> usize { + match self { + BkIn::BkIn1 => 0, + BkIn::BkIn2 => 1, + } + } +} + +/// Break input 1 marker type. +pub enum BkIn1 {} +/// Break input 2 marker type. +pub enum BkIn2 {} + +/// Timer channel trait. +#[allow(private_bounds)] +pub trait BreakInput: SealedBreakInput { + /// The runtim timer channel. + const INPUT: BkIn; +} + +trait SealedBreakInput {} + +impl BreakInput for BkIn1 { + const INPUT: BkIn = BkIn::BkIn1; +} + +impl BreakInput for BkIn2 { + const INPUT: BkIn = BkIn::BkIn2; +} + +impl SealedBreakInput for BkIn1 {} +impl SealedBreakInput for BkIn2 {} + /// Amount of bits of a timer. #[derive(Clone, Copy, PartialEq, Eq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -149,33 +223,20 @@ pub trait AdvancedInstance2Channel: BasicInstance + GeneralInstance2Channel + Ad /// Advanced 16-bit timer with 4 channels instance. pub trait AdvancedInstance4Channel: AdvancedInstance2Channel + GeneralInstance4Channel {} -pin_trait!(Channel1Pin, GeneralInstance4Channel); -pin_trait!(Channel2Pin, GeneralInstance4Channel); -pin_trait!(Channel3Pin, GeneralInstance4Channel); -pin_trait!(Channel4Pin, GeneralInstance4Channel); +pin_trait!(TimerPin, GeneralInstance4Channel, TimerChannel); pin_trait!(ExternalTriggerPin, GeneralInstance4Channel); -pin_trait!(Channel1ComplementaryPin, AdvancedInstance4Channel); -pin_trait!(Channel2ComplementaryPin, AdvancedInstance4Channel); -pin_trait!(Channel3ComplementaryPin, AdvancedInstance4Channel); -pin_trait!(Channel4ComplementaryPin, AdvancedInstance4Channel); +pin_trait!(TimerComplementaryPin, AdvancedInstance4Channel, TimerChannel); -pin_trait!(BreakInputPin, AdvancedInstance4Channel); -pin_trait!(BreakInput2Pin, AdvancedInstance4Channel); +pin_trait!(BreakInputPin, AdvancedInstance4Channel, BreakInput); -pin_trait!(BreakInputComparator1Pin, AdvancedInstance4Channel); -pin_trait!(BreakInputComparator2Pin, AdvancedInstance4Channel); - -pin_trait!(BreakInput2Comparator1Pin, AdvancedInstance4Channel); -pin_trait!(BreakInput2Comparator2Pin, AdvancedInstance4Channel); +pin_trait!(BreakInputComparator1Pin, AdvancedInstance4Channel, BreakInput); +pin_trait!(BreakInputComparator2Pin, AdvancedInstance4Channel, BreakInput); // Update Event trigger DMA for every timer dma_trait!(UpDma, BasicInstance); -dma_trait!(Ch1Dma, GeneralInstance4Channel); -dma_trait!(Ch2Dma, GeneralInstance4Channel); -dma_trait!(Ch3Dma, GeneralInstance4Channel); -dma_trait!(Ch4Dma, GeneralInstance4Channel); +dma_trait!(Dma, GeneralInstance4Channel, TimerChannel); #[allow(unused)] macro_rules! impl_core_timer { diff --git a/embassy-stm32/src/timer/one_pulse.rs b/embassy-stm32/src/timer/one_pulse.rs index 933165ef9..c8f0cafe7 100644 --- a/embassy-stm32/src/timer/one_pulse.rs +++ b/embassy-stm32/src/timer/one_pulse.rs @@ -7,11 +7,9 @@ use core::pin::Pin; use core::task::{Context, Poll}; use super::low_level::{ - CountingMode, FilterValue, InputCaptureMode, InputTISelection, SlaveMode, Timer, TriggerSource, -}; -use super::{ - CaptureCompareInterruptHandler, Channel, Channel1Pin, Channel2Pin, ExternalTriggerPin, GeneralInstance4Channel, + CountingMode, FilterValue, InputCaptureMode, InputTISelection, SlaveMode, Timer, TriggerSource as Ts, }; +use super::{CaptureCompareInterruptHandler, Channel, ExternalTriggerPin, GeneralInstance4Channel, TimerPin}; pub use super::{Ch1, Ch2}; use crate::gpio::{AfType, AnyPin, Pull}; use crate::interrupt::typelevel::{Binding, Interrupt}; @@ -48,24 +46,78 @@ pub struct TriggerPin<'d, T, C> { phantom: PhantomData<(T, C)>, } -macro_rules! channel_impl { - ($new_chx:ident, $channel:ident, $pin_trait:ident) => { - impl<'d, T: GeneralInstance4Channel> TriggerPin<'d, T, $channel> { - #[doc = concat!("Create a new ", stringify!($channel), " trigger pin instance.")] - pub fn $new_chx(pin: Peri<'d, impl $pin_trait>, pull: Pull) -> Self { - pin.set_as_af(pin.af_num(), AfType::input(pull)); - TriggerPin { - _pin: pin.into(), - phantom: PhantomData, - } - } - } - }; +trait SealedTriggerSource {} + +/// 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; } -channel_impl!(new_ch1, Ch1, Channel1Pin); -channel_impl!(new_ch2, Ch2, Channel2Pin); -channel_impl!(new_ext, Ext, ExternalTriggerPin); +impl TimerTriggerPin for P +where + T: GeneralInstance4Channel, + P: TimerPin, + C: super::TimerChannel + 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::TimerChannel + 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(pin: Peri<'d, impl TimerTriggerPin>, pull: Pull) -> Self { + pin.set_as_af(pin.af_num(), AfType::input(pull)); + TriggerPin { + _pin: pin.into(), + phantom: PhantomData, + } + } +} /// One pulse driver. /// @@ -89,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(Channel::Ch1, InputTISelection::Normal); this.inner @@ -114,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(Channel::Ch1, InputTISelection::Normal); this.inner @@ -140,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(Channel::Ch2, InputTISelection::Normal); this.inner @@ -172,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/pwm_input.rs b/embassy-stm32/src/timer/pwm_input.rs index 98b798634..99afb5582 100644 --- a/embassy-stm32/src/timer/pwm_input.rs +++ b/embassy-stm32/src/timer/pwm_input.rs @@ -1,7 +1,7 @@ //! PWM Input driver. use super::low_level::{CountingMode, InputCaptureMode, InputTISelection, SlaveMode, Timer, TriggerSource}; -use super::{Channel, Channel1Pin, Channel2Pin, GeneralInstance4Channel}; +use super::{Ch1, Ch2, Channel, GeneralInstance4Channel, TimerPin}; use crate::gpio::{AfType, Pull}; use crate::time::Hertz; use crate::Peri; @@ -14,14 +14,14 @@ pub struct PwmInput<'d, T: GeneralInstance4Channel> { impl<'d, T: GeneralInstance4Channel> PwmInput<'d, T> { /// Create a new PWM input driver. - pub fn new(tim: Peri<'d, T>, pin: Peri<'d, impl Channel1Pin>, pull: Pull, freq: Hertz) -> Self { + pub fn new(tim: Peri<'d, T>, pin: Peri<'d, impl TimerPin>, pull: Pull, freq: Hertz) -> Self { pin.set_as_af(pin.af_num(), AfType::input(pull)); Self::new_inner(tim, freq, Channel::Ch1, Channel::Ch2) } /// Create a new PWM input driver. - pub fn new_alt(tim: Peri<'d, T>, pin: Peri<'d, impl Channel2Pin>, pull: Pull, freq: Hertz) -> Self { + pub fn new_alt(tim: Peri<'d, T>, pin: Peri<'d, impl TimerPin>, pull: Pull, freq: Hertz) -> Self { pin.set_as_af(pin.af_num(), AfType::input(pull)); Self::new_inner(tim, freq, Channel::Ch2, Channel::Ch1) diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs index f3c81667c..eabe1b22a 100644 --- a/embassy-stm32/src/timer/qei.rs +++ b/embassy-stm32/src/timer/qei.rs @@ -6,8 +6,9 @@ use stm32_metapac::timer::vals; use super::low_level::Timer; pub use super::{Ch1, Ch2}; -use super::{Channel1Pin, Channel2Pin, GeneralInstance4Channel}; +use super::{GeneralInstance4Channel, TimerPin}; use crate::gpio::{AfType, AnyPin, Pull}; +use crate::timer::TimerChannel; use crate::Peri; /// Counting direction @@ -24,26 +25,31 @@ pub struct QeiPin<'d, T, Channel> { phantom: PhantomData<(T, Channel)>, } -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, Channel1Pin); -channel_impl!(new_ch2, Ch2, Channel2Pin); +trait SealedQeiChannel: TimerChannel {} + +/// 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> { diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index f7f433154..c04b1ab97 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -4,22 +4,13 @@ use core::marker::PhantomData; use core::mem::ManuallyDrop; use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer}; -use super::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance4Channel, TimerBits}; +use super::{Ch1, Ch2, Ch3, Ch4, Channel, GeneralInstance4Channel, TimerBits, TimerChannel, TimerPin}; #[cfg(gpio_v2)] use crate::gpio::Pull; use crate::gpio::{AfType, AnyPin, OutputType, Speed}; use crate::time::Hertz; use crate::Peri; -/// Channel 1 marker type. -pub enum Ch1 {} -/// Channel 2 marker type. -pub enum Ch2 {} -/// Channel 3 marker type. -pub enum Ch3 {} -/// Channel 4 marker type. -pub enum Ch4 {} - /// PWM pin wrapper. /// /// This wraps a pin to make it usable with PWM. @@ -43,46 +34,37 @@ pub struct PwmPinConfig { pub pull: Pull, } -macro_rules! channel_impl { - ($new_chx:ident, $new_chx_with_config:ident, $channel:ident, $pin_trait:ident) => { - impl<'d, T: GeneralInstance4Channel> PwmPin<'d, T, $channel> { - #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] - pub fn $new_chx(pin: Peri<'d, impl $pin_trait>, output_type: OutputType) -> Self { - critical_section::with(|_| { - pin.set_low(); - pin.set_as_af(pin.af_num(), AfType::output(output_type, Speed::VeryHigh)); - }); - PwmPin { - _pin: pin.into(), - phantom: PhantomData, - } - } - - #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance with config.")] - pub fn $new_chx_with_config(pin: Peri<'d, impl $pin_trait>, pin_config: PwmPinConfig) -> Self { - critical_section::with(|_| { - pin.set_low(); - pin.set_as_af( - pin.af_num(), - #[cfg(gpio_v1)] - AfType::output(pin_config.output_type, pin_config.speed), - #[cfg(gpio_v2)] - AfType::output_pull(pin_config.output_type, pin_config.speed, pin_config.pull), - ); - }); - PwmPin { - _pin: pin.into(), - phantom: PhantomData, - } - } +impl<'d, T: GeneralInstance4Channel, C: TimerChannel> PwmPin<'d, T, C> { + /// Create a new PWM pin instance. + pub fn new(pin: Peri<'d, impl TimerPin>, output_type: OutputType) -> Self { + critical_section::with(|_| { + pin.set_low(); + pin.set_as_af(pin.af_num(), AfType::output(output_type, Speed::VeryHigh)); + }); + PwmPin { + _pin: pin.into(), + phantom: PhantomData, } - }; -} + } -channel_impl!(new_ch1, new_ch1_with_config, Ch1, Channel1Pin); -channel_impl!(new_ch2, new_ch2_with_config, Ch2, Channel2Pin); -channel_impl!(new_ch3, new_ch3_with_config, Ch3, Channel3Pin); -channel_impl!(new_ch4, new_ch4_with_config, Ch4, Channel4Pin); + /// Create a new PWM pin instance with config. + pub fn new_with_config(pin: Peri<'d, impl TimerPin>, pin_config: PwmPinConfig) -> Self { + critical_section::with(|_| { + pin.set_low(); + pin.set_as_af( + pin.af_num(), + #[cfg(gpio_v1)] + AfType::output(pin_config.output_type, pin_config.speed), + #[cfg(gpio_v2)] + AfType::output_pull(pin_config.output_type, pin_config.speed, pin_config.pull), + ); + }); + PwmPin { + _pin: pin.into(), + phantom: PhantomData, + } + } +} /// A single channel of a pwm, obtained from [`SimplePwm::split`], /// [`SimplePwm::channel`], [`SimplePwm::ch1`], etc. @@ -466,106 +448,97 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { } } -macro_rules! impl_waveform_chx { - ($fn_name:ident, $dma_ch:ident, $cc_ch:ident) => { - impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { - /// Generate a sequence of PWM waveform - pub async fn $fn_name(&mut self, dma: Peri<'_, impl super::$dma_ch>, duty: &[u16]) { - use crate::pac::timer::vals::Ccds; +impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { + /// Generate a sequence of PWM waveform + pub async fn waveform(&mut self, dma: Peri<'_, impl super::Dma>, duty: &[u16]) { + use crate::pac::timer::vals::Ccds; - #[allow(clippy::let_unit_value)] // eg. stm32f334 - let req = dma.request(); + #[allow(clippy::let_unit_value)] // eg. stm32f334 + let req = dma.request(); - let cc_channel = Channel::$cc_ch; + let cc_channel = C::CHANNEL; - let original_duty_state = self.channel(cc_channel).current_duty_cycle(); - let original_enable_state = self.channel(cc_channel).is_enabled(); - let original_cc_dma_on_update = self.inner.get_cc_dma_selection() == Ccds::ON_UPDATE; - let original_cc_dma_enabled = self.inner.get_cc_dma_enable_state(cc_channel); + let original_duty_state = self.channel(cc_channel).current_duty_cycle(); + let original_enable_state = self.channel(cc_channel).is_enabled(); + let original_cc_dma_on_update = self.inner.get_cc_dma_selection() == Ccds::ON_UPDATE; + let original_cc_dma_enabled = self.inner.get_cc_dma_enable_state(cc_channel); - // redirect CC DMA request onto Update Event - if !original_cc_dma_on_update { - self.inner.set_cc_dma_selection(Ccds::ON_UPDATE) - } - - if !original_cc_dma_enabled { - self.inner.set_cc_dma_enable_state(cc_channel, true); - } - - if !original_enable_state { - self.channel(cc_channel).enable(); - } - - unsafe { - #[cfg(not(any(bdma, gpdma)))] - use crate::dma::{Burst, FifoThreshold}; - use crate::dma::{Transfer, TransferOptions}; - - let dma_transfer_option = TransferOptions { - #[cfg(not(any(bdma, gpdma)))] - fifo_threshold: Some(FifoThreshold::Full), - #[cfg(not(any(bdma, gpdma)))] - mburst: Burst::Incr8, - ..Default::default() - }; - - match self.inner.bits() { - TimerBits::Bits16 => { - Transfer::new_write( - dma, - req, - duty, - self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u16, - dma_transfer_option, - ) - .await - } - #[cfg(not(any(stm32l0)))] - TimerBits::Bits32 => { - #[cfg(not(any(bdma, gpdma)))] - panic!("unsupported timer bits"); - - #[cfg(any(bdma, gpdma))] - Transfer::new_write( - dma, - req, - duty, - self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u32, - dma_transfer_option, - ) - .await - } - }; - }; - - // restore output compare state - if !original_enable_state { - self.channel(cc_channel).disable(); - } - - self.channel(cc_channel).set_duty_cycle(original_duty_state); - - // Since DMA is closed before timer Capture Compare Event trigger DMA is turn off, - // this can almost always trigger a DMA FIFO error. - // - // optional TODO: - // clean FEIF after disable UDE - if !original_cc_dma_enabled { - self.inner.set_cc_dma_enable_state(cc_channel, false); - } - - if !original_cc_dma_on_update { - self.inner.set_cc_dma_selection(Ccds::ON_COMPARE) - } - } + // redirect CC DMA request onto Update Event + if !original_cc_dma_on_update { + self.inner.set_cc_dma_selection(Ccds::ON_UPDATE) } - }; -} -impl_waveform_chx!(waveform_ch1, Ch1Dma, Ch1); -impl_waveform_chx!(waveform_ch2, Ch2Dma, Ch2); -impl_waveform_chx!(waveform_ch3, Ch3Dma, Ch3); -impl_waveform_chx!(waveform_ch4, Ch4Dma, Ch4); + if !original_cc_dma_enabled { + self.inner.set_cc_dma_enable_state(cc_channel, true); + } + + if !original_enable_state { + self.channel(cc_channel).enable(); + } + + unsafe { + #[cfg(not(any(bdma, gpdma)))] + use crate::dma::{Burst, FifoThreshold}; + use crate::dma::{Transfer, TransferOptions}; + + let dma_transfer_option = TransferOptions { + #[cfg(not(any(bdma, gpdma)))] + fifo_threshold: Some(FifoThreshold::Full), + #[cfg(not(any(bdma, gpdma)))] + mburst: Burst::Incr8, + ..Default::default() + }; + + match self.inner.bits() { + TimerBits::Bits16 => { + Transfer::new_write( + dma, + req, + duty, + self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u16, + dma_transfer_option, + ) + .await + } + #[cfg(not(any(stm32l0)))] + TimerBits::Bits32 => { + #[cfg(not(any(bdma, gpdma)))] + panic!("unsupported timer bits"); + + #[cfg(any(bdma, gpdma))] + Transfer::new_write( + dma, + req, + duty, + self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u32, + dma_transfer_option, + ) + .await + } + }; + }; + + // restore output compare state + if !original_enable_state { + self.channel(cc_channel).disable(); + } + + self.channel(cc_channel).set_duty_cycle(original_duty_state); + + // Since DMA is closed before timer Capture Compare Event trigger DMA is turn off, + // this can almost always trigger a DMA FIFO error. + // + // optional TODO: + // clean FEIF after disable UDE + if !original_cc_dma_enabled { + self.inner.set_cc_dma_enable_state(cc_channel, false); + } + + if !original_cc_dma_on_update { + self.inner.set_cc_dma_selection(Ccds::ON_COMPARE) + } + } +} impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::ErrorType for SimplePwmChannel<'d, T> { type Error = core::convert::Infallible; diff --git a/examples/stm32f1/src/bin/input_capture.rs b/examples/stm32f1/src/bin/input_capture.rs index 6fe8e0b50..84811fb95 100644 --- a/examples/stm32f1/src/bin/input_capture.rs +++ b/examples/stm32f1/src/bin/input_capture.rs @@ -39,7 +39,7 @@ async fn main(spawner: Spawner) { unwrap!(spawner.spawn(blinky(p.PC13))); - let ch3 = CapturePin::new_ch3(p.PA2, Pull::None); + let ch3 = CapturePin::new(p.PA2, Pull::None); let mut ic = InputCapture::new(p.TIM2, None, None, Some(ch3), None, Irqs, khz(1000), Default::default()); loop { diff --git a/examples/stm32f4/src/bin/input_capture.rs b/examples/stm32f4/src/bin/input_capture.rs index fe5e2bdfc..e15b4d26e 100644 --- a/examples/stm32f4/src/bin/input_capture.rs +++ b/examples/stm32f4/src/bin/input_capture.rs @@ -39,7 +39,7 @@ async fn main(spawner: Spawner) { unwrap!(spawner.spawn(blinky(p.PB2))); - let ch3 = CapturePin::new_ch3(p.PB10, Pull::None); + let ch3 = CapturePin::new(p.PB10, Pull::None); let mut ic = InputCapture::new(p.TIM2, None, None, Some(ch3), None, Irqs, khz(1000), Default::default()); loop { diff --git a/examples/stm32f4/src/bin/pwm.rs b/examples/stm32f4/src/bin/pwm.rs index 04811162b..e385842f0 100644 --- a/examples/stm32f4/src/bin/pwm.rs +++ b/examples/stm32f4/src/bin/pwm.rs @@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let ch1_pin = PwmPin::new_ch1(p.PE9, OutputType::PushPull); + let ch1_pin = PwmPin::new(p.PE9, OutputType::PushPull); let mut pwm = SimplePwm::new(p.TIM1, Some(ch1_pin), None, None, None, khz(10), Default::default()); let mut ch1 = pwm.ch1(); ch1.enable(); diff --git a/examples/stm32f4/src/bin/pwm_complementary.rs b/examples/stm32f4/src/bin/pwm_complementary.rs index 161f43c48..c981f1a76 100644 --- a/examples/stm32f4/src/bin/pwm_complementary.rs +++ b/examples/stm32f4/src/bin/pwm_complementary.rs @@ -16,8 +16,8 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let ch1 = PwmPin::new_ch1(p.PE9, OutputType::PushPull); - let ch1n = ComplementaryPwmPin::new_ch1(p.PA7, OutputType::PushPull); + let ch1 = PwmPin::new(p.PE9, OutputType::PushPull); + let ch1n = ComplementaryPwmPin::new(p.PA7, OutputType::PushPull); let mut pwm = ComplementaryPwm::new( p.TIM1, Some(ch1), diff --git a/examples/stm32f4/src/bin/ws2812_pwm.rs b/examples/stm32f4/src/bin/ws2812_pwm.rs index ca924e181..5153e1cfd 100644 --- a/examples/stm32f4/src/bin/ws2812_pwm.rs +++ b/examples/stm32f4/src/bin/ws2812_pwm.rs @@ -50,7 +50,7 @@ async fn main(_spawner: Spawner) { let mut ws2812_pwm = SimplePwm::new( dp.TIM3, - Some(PwmPin::new_ch1(dp.PB4, OutputType::PushPull)), + Some(PwmPin::new(dp.PB4, OutputType::PushPull)), None, None, None, diff --git a/examples/stm32g0/src/bin/hf_timer.rs b/examples/stm32g0/src/bin/hf_timer.rs index dfb6e0edc..705905f01 100644 --- a/examples/stm32g0/src/bin/hf_timer.rs +++ b/examples/stm32g0/src/bin/hf_timer.rs @@ -37,8 +37,8 @@ async fn main(_spawner: Spawner) { } let p = embassy_stm32::init(config); - let ch1 = PwmPin::new_ch1(p.PA8, OutputType::PushPull); - let ch1n = ComplementaryPwmPin::new_ch1(p.PA7, OutputType::PushPull); + let ch1 = PwmPin::new(p.PA8, OutputType::PushPull); + let ch1n = ComplementaryPwmPin::new(p.PA7, OutputType::PushPull); let mut pwm = ComplementaryPwm::new( p.TIM1, diff --git a/examples/stm32g0/src/bin/input_capture.rs b/examples/stm32g0/src/bin/input_capture.rs index 08df4e043..df339d541 100644 --- a/examples/stm32g0/src/bin/input_capture.rs +++ b/examples/stm32g0/src/bin/input_capture.rs @@ -47,12 +47,12 @@ async fn main(spawner: Spawner) { unwrap!(spawner.spawn(blinky(p.PB1))); // Connect PB1 and PA8 with a 1k Ohm resistor - let ch1_pin = PwmPin::new_ch1(p.PA8, OutputType::PushPull); + let ch1_pin = PwmPin::new(p.PA8, OutputType::PushPull); let mut pwm = SimplePwm::new(p.TIM1, Some(ch1_pin), None, None, None, khz(1), Default::default()); pwm.ch1().enable(); pwm.ch1().set_duty_cycle(50); - let ch1 = CapturePin::new_ch1(p.PA0, Pull::None); + let ch1 = CapturePin::new(p.PA0, Pull::None); let mut ic = InputCapture::new(p.TIM2, Some(ch1), None, None, None, Irqs, khz(1000), Default::default()); let mut old_capture = 0; diff --git a/examples/stm32g0/src/bin/pwm_complementary.rs b/examples/stm32g0/src/bin/pwm_complementary.rs index 97b163c40..dbd9194c9 100644 --- a/examples/stm32g0/src/bin/pwm_complementary.rs +++ b/examples/stm32g0/src/bin/pwm_complementary.rs @@ -26,10 +26,10 @@ use {defmt_rtt as _, panic_probe as _}; async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); - let ch1 = PwmPin::new_ch1(p.PA8, OutputType::PushPull); - let ch1n = ComplementaryPwmPin::new_ch1(p.PA7, OutputType::PushPull); - let ch2 = PwmPin::new_ch2(p.PB3, OutputType::PushPull); - let ch2n = ComplementaryPwmPin::new_ch2(p.PB0, OutputType::PushPull); + let ch1 = PwmPin::new(p.PA8, OutputType::PushPull); + let ch1n = ComplementaryPwmPin::new(p.PA7, OutputType::PushPull); + let ch2 = PwmPin::new(p.PB3, OutputType::PushPull); + let ch2n = ComplementaryPwmPin::new(p.PB0, OutputType::PushPull); let mut pwm = ComplementaryPwm::new( p.TIM1, diff --git a/examples/stm32g0/src/bin/pwm_input.rs b/examples/stm32g0/src/bin/pwm_input.rs index 9d6b5fe97..dc2428607 100644 --- a/examples/stm32g0/src/bin/pwm_input.rs +++ b/examples/stm32g0/src/bin/pwm_input.rs @@ -42,7 +42,7 @@ async fn main(spawner: Spawner) { unwrap!(spawner.spawn(blinky(p.PB1))); // Connect PA8 and PA6 with a 1k Ohm resistor - let ch1_pin = PwmPin::new_ch1(p.PA8, OutputType::PushPull); + let ch1_pin = PwmPin::new(p.PA8, OutputType::PushPull); let mut pwm = SimplePwm::new(p.TIM1, Some(ch1_pin), None, None, None, khz(1), Default::default()); pwm.ch1().set_duty_cycle_fraction(1, 4); pwm.ch1().enable(); diff --git a/examples/stm32g4/src/bin/pwm.rs b/examples/stm32g4/src/bin/pwm.rs index 6c965012c..5b4194927 100644 --- a/examples/stm32g4/src/bin/pwm.rs +++ b/examples/stm32g4/src/bin/pwm.rs @@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let ch1_pin = PwmPin::new_ch1(p.PC0, OutputType::PushPull); + let ch1_pin = PwmPin::new(p.PC0, OutputType::PushPull); let mut pwm = SimplePwm::new(p.TIM1, Some(ch1_pin), None, None, None, khz(10), Default::default()); let mut ch1 = pwm.ch1(); ch1.enable(); diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs index 8de31ea5b..12abb8693 100644 --- a/examples/stm32h7/src/bin/low_level_timer_api.rs +++ b/examples/stm32h7/src/bin/low_level_timer_api.rs @@ -6,7 +6,7 @@ use embassy_executor::Spawner; use embassy_stm32::gpio::{AfType, Flex, OutputType, Speed}; use embassy_stm32::time::{khz, Hertz}; use embassy_stm32::timer::low_level::{OutputCompareMode, Timer as LLTimer}; -use embassy_stm32::timer::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance32bit4Channel}; +use embassy_stm32::timer::{Ch1, Ch2, Ch3, Ch4, Channel, GeneralInstance32bit4Channel, TimerPin}; use embassy_stm32::{Config, Peri}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -67,10 +67,10 @@ pub struct SimplePwm32<'d, T: GeneralInstance32bit4Channel> { impl<'d, T: GeneralInstance32bit4Channel> SimplePwm32<'d, T> { pub fn new( tim: Peri<'d, T>, - ch1: Peri<'d, impl Channel1Pin>, - ch2: Peri<'d, impl Channel2Pin>, - ch3: Peri<'d, impl Channel3Pin>, - ch4: Peri<'d, impl Channel4Pin>, + ch1: Peri<'d, impl TimerPin>, + ch2: Peri<'d, impl TimerPin>, + ch3: Peri<'d, impl TimerPin>, + ch4: Peri<'d, impl TimerPin>, freq: Hertz, ) -> Self { let af1 = ch1.af_num(); diff --git a/examples/stm32h7/src/bin/pwm.rs b/examples/stm32h7/src/bin/pwm.rs index a1c53fc3f..73b43be69 100644 --- a/examples/stm32h7/src/bin/pwm.rs +++ b/examples/stm32h7/src/bin/pwm.rs @@ -36,7 +36,7 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(config); info!("Hello World!"); - let ch1_pin = PwmPin::new_ch1(p.PA6, OutputType::PushPull); + let ch1_pin = PwmPin::new(p.PA6, OutputType::PushPull); let mut pwm = SimplePwm::new(p.TIM3, Some(ch1_pin), None, None, None, khz(10), Default::default()); let mut ch1 = pwm.ch1(); ch1.enable(); diff --git a/examples/stm32l0/src/bin/dds.rs b/examples/stm32l0/src/bin/dds.rs index a54b28a93..eaa7a61a8 100644 --- a/examples/stm32l0/src/bin/dds.rs +++ b/examples/stm32l0/src/bin/dds.rs @@ -11,7 +11,7 @@ use embassy_stm32::rcc::*; use embassy_stm32::time::hz; use embassy_stm32::timer::low_level::{Timer as LLTimer, *}; use embassy_stm32::timer::simple_pwm::PwmPin; -use embassy_stm32::timer::Channel; +use embassy_stm32::timer::{Ch3, Channel}; use embassy_stm32::{interrupt, pac, Config}; use panic_probe as _; @@ -70,7 +70,7 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(config); // setup PWM pin in AF mode - let _ch3 = PwmPin::new_ch3(p.PA2, OutputType::PushPull); + let _ch3 = PwmPin::<_, Ch3>::new(p.PA2, OutputType::PushPull); // initialize timer // we cannot use SimplePWM here because the Time is privately encapsulated