stm32/afio: use type inference for timer remaps as well.

This commit is contained in:
Dario Nieuwenhuis 2025-09-05 23:00:31 +02:00
parent a6562c4f03
commit 7419b398bf
12 changed files with 159 additions and 292 deletions

View File

@ -1391,58 +1391,51 @@ fn main() {
}) })
} }
let pin_trait_impl = p let pin_trait_impl = if let Some(afio) = &p.afio {
.afio let values = afio
.as_ref() .values
.and_then(|afio| { .iter()
if p.name.starts_with("TIM") { .filter(|v| v.pins.contains(&pin.pin))
// timers are handled by timer_afio_impl!() .map(|v| v.value)
return None; .collect::<Vec<_>>();
}
let values = afio if values.is_empty() {
.values None
.iter() } else {
.filter(|v| v.pins.contains(&pin.pin)) let reg = format_ident!("{}", afio.register.to_lowercase());
.map(|v| v.value) let setter = format_ident!("set_{}", afio.field.to_lowercase());
.collect::<Vec<_>>(); let type_and_values = if is_bool_field("AFIO", afio.register, afio.field) {
let values = values.iter().map(|&v| v > 0);
if values.is_empty() { quote!(AfioRemapBool, [#(#values),*])
None
} else { } else {
let setter = format_ident!("set_{}", afio.field.to_lowercase()); quote!(AfioRemap, [#(#values),*])
let type_and_values = if is_bool_field("AFIO", afio.register, afio.field) {
let values = values.iter().map(|&v| v > 0);
quote!(AfioRemapBool, [#(#values),*])
} else {
quote!(AfioRemap, [#(#values),*])
};
Some(quote! {
pin_trait_afio_impl!(#tr, #peri, #pin_name, {#setter, #type_and_values});
})
}
})
.unwrap_or_else(|| {
let peripherals_with_afio = [
"CAN",
"CEC",
"ETH",
"I2C",
"SPI",
"SUBGHZSPI",
"USART",
"UART",
"LPUART",
];
let af_or_not_applicable = if peripherals_with_afio.iter().any(|&x| p.name.starts_with(x)) {
quote!(0, crate::gpio::AfioRemapNotApplicable)
} else {
quote!(#af)
}; };
quote!(pin_trait_impl!(#tr, #peri, #pin_name, #af_or_not_applicable);) Some(quote! {
}); pin_trait_afio_impl!(#tr, #peri, #pin_name, {#reg, #setter, #type_and_values});
})
}
} else {
let peripherals_with_afio = [
"CAN",
"CEC",
"ETH",
"I2C",
"SPI",
"SUBGHZSPI",
"USART",
"UART",
"LPUART",
"TIM",
];
let af_or_not_applicable = if peripherals_with_afio.iter().any(|&x| p.name.starts_with(x)) {
quote!(0, crate::gpio::AfioRemapNotApplicable)
} else {
quote!(#af)
};
Some(quote!(pin_trait_impl!(#tr, #peri, #pin_name, #af_or_not_applicable);))
};
g.extend(pin_trait_impl); g.extend(pin_trait_impl);
} }
@ -1969,48 +1962,6 @@ fn main() {
pub(crate) const DMA_CHANNELS: &[crate::dma::ChannelInfo] = &[#dmas]; pub(crate) const DMA_CHANNELS: &[crate::dma::ChannelInfo] = &[#dmas];
}); });
// ========
// Generate timer AFIO impls
for p in METADATA.peripherals {
if p.name.starts_with("TIM") {
let pname = format_ident!("{}", p.name);
let afio = if let Some(afio) = &p.afio {
let register = format_ident!("{}", afio.register.to_lowercase());
let setter = format_ident!("set_{}", afio.field.to_lowercase());
let swj_cfg = if afio.register == "MAPR" {
quote!(w.set_swj_cfg(crate::pac::afio::vals::SwjCfg::NO_OP);)
} else {
quote!()
};
let bool_eval = if is_bool_field("AFIO", &afio.register, &afio.field) {
quote!(> 0)
} else {
quote!()
};
let values = afio.values.iter().map(|v| {
let mapr_value = v.value;
let pin = v.pins.iter().map(|p| {
let port_num = p.chars().nth(1).unwrap() as u8 - b'A';
let pin_num = p[2..].parse::<u8>().unwrap();
port_num * 16 + pin_num
});
quote!(#mapr_value, [#(#pin),*])
});
quote! {
, |v| crate::pac::AFIO.#register().modify(|w| { #swj_cfg w.#setter(v #bool_eval); }), #({#values}),*
}
} else {
quote!()
};
g.extend(quote!(timer_afio_impl!(#pname #afio);));
}
}
// ======== // ========
// Generate gpio_block() function // Generate gpio_block() function

View File

@ -71,7 +71,31 @@ macro_rules! pin_trait_impl {
#[cfg(afio)] #[cfg(afio)]
macro_rules! pin_trait_afio_impl { macro_rules! pin_trait_afio_impl {
(crate::$mod:ident::$trait:ident, $instance:ident, $pin:ident, {$setter:ident, $type:ident, [$($val:expr),+]}) => { (@set mapr, $setter:ident, $val:expr) => {
crate::pac::AFIO.mapr().modify(|w| {
w.set_swj_cfg(crate::pac::afio::vals::SwjCfg::NO_OP);
w.$setter($val);
});
};
(@set mapr2, $setter:ident, $val:expr) => {
crate::pac::AFIO.mapr2().modify(|w| {
w.$setter($val);
});
};
(crate::$mod:ident::$trait:ident<$mode:ident>, $instance:ident, $pin:ident, {$reg:ident, $setter:ident, $type:ident, [$($val:expr),+]}) => {
$(
impl crate::$mod::$trait<crate::peripherals::$instance, crate::$mod::$mode, crate::gpio::$type<$val>> for crate::peripherals::$pin {
fn af_num(&self) -> u8 {
0
}
fn afio_remap(&self) {
pin_trait_afio_impl!(@set $reg, $setter, $val);
}
}
)+
};
(crate::$mod:ident::$trait:ident, $instance:ident, $pin:ident, {$reg:ident, $setter:ident, $type:ident, [$($val:expr),+]}) => {
$( $(
impl crate::$mod::$trait<crate::peripherals::$instance, crate::gpio::$type<$val>> for crate::peripherals::$pin { impl crate::$mod::$trait<crate::peripherals::$instance, crate::gpio::$type<$val>> for crate::peripherals::$pin {
fn af_num(&self) -> u8 { fn af_num(&self) -> u8 {
@ -79,10 +103,7 @@ macro_rules! pin_trait_afio_impl {
} }
fn afio_remap(&self) { fn afio_remap(&self) {
crate::pac::AFIO.mapr().modify(|w| { pin_trait_afio_impl!(@set $reg, $setter, $val);
w.set_swj_cfg(crate::pac::afio::vals::SwjCfg::NO_OP);
w.$setter($val);
});
} }
} }
)+ )+
@ -102,30 +123,6 @@ macro_rules! sel_trait_impl {
// ==================== // ====================
macro_rules! timer_afio_impl {
($instance:ident $(, $set_afio:expr)? $(,{$mapr_value:literal, [$($pin:literal),*]})*) => {
impl crate::timer::Afio for crate::peripherals::$instance {
fn afio_mappings() -> &'static [crate::timer::AfioMapping] {
&[
$(
crate::timer::AfioMapping {
value: $mapr_value,
pins: &[$($pin),*],
}
),*
]
}
#[allow(unused)]
fn set_afio(value: u8) {
$($set_afio(value);)?
}
}
};
}
// ====================
macro_rules! dma_trait { macro_rules! dma_trait {
($signal:ident, $instance:path$(, $mode:path)?) => { ($signal:ident, $instance:path$(, $mode:path)?) => {
#[doc = concat!(stringify!($signal), " DMA request trait")] #[doc = concat!(stringify!($signal), " DMA request trait")]

View File

@ -16,21 +16,23 @@ use crate::Peri;
/// Complementary PWM pin wrapper. /// Complementary PWM pin wrapper.
/// ///
/// This wraps a pin to make it usable with PWM. /// This wraps a pin to make it usable with PWM.
pub struct ComplementaryPwmPin<'d, T, C> { pub struct ComplementaryPwmPin<'d, T, C, A> {
#[allow(unused)] #[allow(unused)]
pin: Peri<'d, AnyPin>, pin: Peri<'d, AnyPin>,
phantom: PhantomData<(T, C)>, phantom: PhantomData<(T, C, A)>,
} }
impl<'d, T: AdvancedInstance4Channel, C: TimerChannel> ComplementaryPwmPin<'d, T, C> { impl<'d, T: AdvancedInstance4Channel, C: TimerChannel, A> ComplementaryPwmPin<'d, T, C, A> {
/// Create a new complementary PWM pin instance. /// Create a new complementary PWM pin instance.
pub fn new(pin: Peri<'d, impl TimerComplementaryPin<T, C>>, output_type: OutputType) -> Self { pub fn new(pin: Peri<'d, impl TimerComplementaryPin<T, C, A>>, output_type: OutputType) -> Self {
critical_section::with(|_| { critical_section::with(|_| {
pin.set_low(); pin.set_low();
pin.set_as_af( pin.set_as_af(
pin.af_num(), pin.af_num(),
crate::gpio::AfType::output(output_type, crate::gpio::Speed::VeryHigh), crate::gpio::AfType::output(output_type, crate::gpio::Speed::VeryHigh),
); );
#[cfg(afio)]
pin.afio_remap();
}); });
ComplementaryPwmPin { ComplementaryPwmPin {
pin: pin.into(), pin: pin.into(),
@ -56,30 +58,19 @@ pub enum IdlePolarity {
impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
/// Create a new complementary PWM driver. /// Create a new complementary PWM driver.
#[allow(clippy::too_many_arguments, unused)] #[allow(clippy::too_many_arguments, unused)]
pub fn new( pub fn new<A>(
tim: Peri<'d, T>, tim: Peri<'d, T>,
ch1: Option<PwmPin<'d, T, Ch1>>, ch1: Option<PwmPin<'d, T, Ch1, A>>,
ch1n: Option<ComplementaryPwmPin<'d, T, Ch1>>, ch1n: Option<ComplementaryPwmPin<'d, T, Ch1, A>>,
ch2: Option<PwmPin<'d, T, Ch2>>, ch2: Option<PwmPin<'d, T, Ch2, A>>,
ch2n: Option<ComplementaryPwmPin<'d, T, Ch2>>, ch2n: Option<ComplementaryPwmPin<'d, T, Ch2, A>>,
ch3: Option<PwmPin<'d, T, Ch3>>, ch3: Option<PwmPin<'d, T, Ch3, A>>,
ch3n: Option<ComplementaryPwmPin<'d, T, Ch3>>, ch3n: Option<ComplementaryPwmPin<'d, T, Ch3, A>>,
ch4: Option<PwmPin<'d, T, Ch4>>, ch4: Option<PwmPin<'d, T, Ch4, A>>,
ch4n: Option<ComplementaryPwmPin<'d, T, Ch4>>, ch4n: Option<ComplementaryPwmPin<'d, T, Ch4, A>>,
freq: Hertz, freq: Hertz,
counting_mode: CountingMode, counting_mode: CountingMode,
) -> Self { ) -> Self {
#[cfg(afio)]
super::set_afio::<T>(&[
ch1.map(|p| p.pin),
ch1n.map(|p| p.pin),
ch2.map(|p| p.pin),
ch2n.map(|p| p.pin),
ch3.map(|p| p.pin),
ch3n.map(|p| p.pin),
ch4.map(|p| p.pin),
ch4n.map(|p| p.pin),
]);
Self::new_inner(tim, freq, counting_mode) Self::new_inner(tim, freq, counting_mode)
} }

View File

@ -17,14 +17,14 @@ use crate::Peri;
/// Capture pin wrapper. /// Capture pin wrapper.
/// ///
/// This wraps a pin to make it usable with capture. /// This wraps a pin to make it usable with capture.
pub struct CapturePin<'d, T, C> { pub struct CapturePin<'d, T, C, A> {
#[allow(unused)] #[allow(unused)]
pin: Peri<'d, AnyPin>, pin: Peri<'d, AnyPin>,
phantom: PhantomData<(T, C)>, phantom: PhantomData<(T, C, A)>,
} }
impl<'d, T: GeneralInstance4Channel, C: TimerChannel> CapturePin<'d, T, C> { impl<'d, T: GeneralInstance4Channel, C: TimerChannel, A> CapturePin<'d, T, C, A> {
/// Create a new capture pin instance. /// Create a new capture pin instance.
pub fn new(pin: Peri<'d, impl TimerPin<T, C>>, pull: Pull) -> Self { pub fn new(pin: Peri<'d, impl TimerPin<T, C, A>>, pull: Pull) -> Self {
pin.set_as_af(pin.af_num(), AfType::input(pull)); pin.set_as_af(pin.af_num(), AfType::input(pull));
CapturePin { CapturePin {
pin: pin.into(), pin: pin.into(),
@ -41,23 +41,16 @@ pub struct InputCapture<'d, T: GeneralInstance4Channel> {
impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> { impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> {
/// Create a new input capture driver. /// Create a new input capture driver.
#[allow(unused)] #[allow(unused)]
pub fn new( pub fn new<A>(
tim: Peri<'d, T>, tim: Peri<'d, T>,
ch1: Option<CapturePin<'d, T, Ch1>>, ch1: Option<CapturePin<'d, T, Ch1, A>>,
ch2: Option<CapturePin<'d, T, Ch2>>, ch2: Option<CapturePin<'d, T, Ch2, A>>,
ch3: Option<CapturePin<'d, T, Ch3>>, ch3: Option<CapturePin<'d, T, Ch3, A>>,
ch4: Option<CapturePin<'d, T, Ch4>>, ch4: Option<CapturePin<'d, T, Ch4, A>>,
_irq: impl Binding<T::CaptureCompareInterrupt, CaptureCompareInterruptHandler<T>> + 'd, _irq: impl Binding<T::CaptureCompareInterrupt, CaptureCompareInterruptHandler<T>> + 'd,
freq: Hertz, freq: Hertz,
counting_mode: CountingMode, counting_mode: CountingMode,
) -> Self { ) -> Self {
#[cfg(afio)]
super::set_afio::<T>(&[
ch1.map(|p| p.pin),
ch2.map(|p| p.pin),
ch3.map(|p| p.pin),
ch4.map(|p| p.pin),
]);
Self::new_inner(tim, freq, counting_mode) Self::new_inner(tim, freq, counting_mode)
} }

View File

@ -14,8 +14,6 @@ pub mod pwm_input;
pub mod qei; pub mod qei;
pub mod simple_pwm; pub mod simple_pwm;
#[cfg(afio)]
use crate::gpio::SealedPin;
use crate::interrupt; use crate::interrupt;
use crate::rcc::RccPeripheral; use crate::rcc::RccPeripheral;
@ -157,15 +155,9 @@ trait SealedInstance: RccPeripheral + PeripheralType {
fn state() -> &'static State; fn state() -> &'static State;
} }
#[allow(unused)]
pub(crate) trait Afio {
fn afio_mappings() -> &'static [AfioMapping];
fn set_afio(value: u8);
}
/// Core timer instance. /// Core timer instance.
#[allow(private_bounds)] #[allow(private_bounds)]
pub trait CoreInstance: SealedInstance + Afio + 'static { pub trait CoreInstance: SealedInstance + 'static {
/// Update Interrupt for this timer. /// Update Interrupt for this timer.
type UpdateInterrupt: interrupt::typelevel::Interrupt; type UpdateInterrupt: interrupt::typelevel::Interrupt;
@ -231,15 +223,15 @@ pub trait AdvancedInstance2Channel: BasicInstance + GeneralInstance2Channel + Ad
/// Advanced 16-bit timer with 4 channels instance. /// Advanced 16-bit timer with 4 channels instance.
pub trait AdvancedInstance4Channel: AdvancedInstance2Channel + GeneralInstance4Channel {} pub trait AdvancedInstance4Channel: AdvancedInstance2Channel + GeneralInstance4Channel {}
pin_trait!(TimerPin, GeneralInstance4Channel, TimerChannel); pin_trait!(TimerPin, GeneralInstance4Channel, TimerChannel, @A);
pin_trait!(ExternalTriggerPin, GeneralInstance4Channel); pin_trait!(ExternalTriggerPin, GeneralInstance4Channel, @A);
pin_trait!(TimerComplementaryPin, AdvancedInstance4Channel, TimerChannel); pin_trait!(TimerComplementaryPin, AdvancedInstance4Channel, TimerChannel, @A);
pin_trait!(BreakInputPin, AdvancedInstance4Channel, BreakInput); pin_trait!(BreakInputPin, AdvancedInstance4Channel, BreakInput, @A);
pin_trait!(BreakInputComparator1Pin, AdvancedInstance4Channel, BreakInput); pin_trait!(BreakInputComparator1Pin, AdvancedInstance4Channel, BreakInput, @A);
pin_trait!(BreakInputComparator2Pin, AdvancedInstance4Channel, BreakInput); pin_trait!(BreakInputComparator2Pin, AdvancedInstance4Channel, BreakInput, @A);
// Update Event trigger DMA for every timer // Update Event trigger DMA for every timer
dma_trait!(UpDma, BasicInstance); dma_trait!(UpDma, BasicInstance);
@ -458,24 +450,3 @@ impl<T: GeneralInstance1Channel> interrupt::typelevel::Handler<T::CaptureCompare
} }
} }
} }
#[allow(unused)]
pub(crate) struct AfioMapping {
pub(crate) value: u8,
pub(crate) pins: &'static [u8],
}
#[cfg(afio)]
fn set_afio<'d, T: Afio>(pins: &[Option<embassy_hal_internal::Peri<'d, crate::gpio::AnyPin>>]) {
let mapping = T::afio_mappings()
.iter()
.find(|m| {
pins.iter()
.flatten()
.map(|p| (*p).pin_port())
.all(|p| m.pins.contains(&p))
})
.expect("Should be called with a combination of timer pins supported by the hardware");
T::set_afio(mapping.value);
}

View File

@ -15,6 +15,7 @@ use crate::gpio::{AfType, AnyPin, Pull};
use crate::interrupt::typelevel::{Binding, Interrupt}; use crate::interrupt::typelevel::{Binding, Interrupt};
use crate::pac::timer::vals::Etp; use crate::pac::timer::vals::Etp;
use crate::time::Hertz; use crate::time::Hertz;
use crate::timer::TimerChannel;
use crate::Peri; use crate::Peri;
/// External input marker type. /// External input marker type.
@ -61,58 +62,25 @@ impl SealedTriggerSource for Ch1 {}
impl SealedTriggerSource for Ch2 {} impl SealedTriggerSource for Ch2 {}
impl SealedTriggerSource for Ext {} impl SealedTriggerSource for Ext {}
trait SealedTimerTriggerPin<T, S>: crate::gpio::Pin {} impl<'d, T: GeneralInstance4Channel, C: TriggerSource + TimerChannel> TriggerPin<'d, T, C> {
/// Create a new Channel trigger pin instance.
/// Marker trait for a trigger pin. pub fn new<A>(pin: Peri<'d, impl TimerPin<T, C, A>>, pull: Pull) -> Self {
#[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<T, S>: SealedTimerTriggerPin<T, S> {
/// Get the AF number needed to use this pin as a trigger source.
fn af_num(&self) -> u8;
}
impl<T, P, C> TimerTriggerPin<T, C> for P
where
T: GeneralInstance4Channel,
P: TimerPin<T, C>,
C: super::TimerChannel + TriggerSource,
{
fn af_num(&self) -> u8 {
TimerPin::af_num(self)
}
}
impl<T, P> TimerTriggerPin<T, Ext> for P
where
T: GeneralInstance4Channel,
P: ExternalTriggerPin<T>,
{
fn af_num(&self) -> u8 {
ExternalTriggerPin::af_num(self)
}
}
impl<T, P, C> SealedTimerTriggerPin<T, C> for P
where
T: GeneralInstance4Channel,
P: TimerPin<T, C>,
C: super::TimerChannel + TriggerSource,
{
}
impl<T, P> SealedTimerTriggerPin<T, Ext> for P
where
T: GeneralInstance4Channel,
P: ExternalTriggerPin<T>,
{
}
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<T, C>>, pull: Pull) -> Self {
pin.set_as_af(pin.af_num(), AfType::input(pull)); pin.set_as_af(pin.af_num(), AfType::input(pull));
#[cfg(afio)]
pin.afio_remap();
TriggerPin {
pin: pin.into(),
phantom: PhantomData,
}
}
}
impl<'d, T: GeneralInstance4Channel> TriggerPin<'d, T, Ext> {
/// Create a new external trigger pin instance.
pub fn new_external<A>(pin: Peri<'d, impl ExternalTriggerPin<T, A>>, pull: Pull) -> Self {
pin.set_as_af(pin.af_num(), AfType::input(pull));
#[cfg(afio)]
pin.afio_remap();
TriggerPin { TriggerPin {
pin: pin.into(), pin: pin.into(),
phantom: PhantomData, phantom: PhantomData,
@ -141,8 +109,6 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> {
pulse_end: u32, pulse_end: u32,
counting_mode: CountingMode, counting_mode: CountingMode,
) -> Self { ) -> Self {
#[cfg(afio)]
super::set_afio::<T>(&[Some(pin.pin)]);
let mut this = Self { inner: Timer::new(tim) }; let mut this = Self { inner: Timer::new(tim) };
this.inner.set_trigger_source(Ts::TI1F_ED); this.inner.set_trigger_source(Ts::TI1F_ED);

View File

@ -18,19 +18,19 @@ pub struct PwmInput<'d, T: GeneralInstance4Channel> {
impl<'d, T: GeneralInstance4Channel> PwmInput<'d, T> { impl<'d, T: GeneralInstance4Channel> PwmInput<'d, T> {
/// Create a new PWM input driver. /// Create a new PWM input driver.
pub fn new_ch1(tim: Peri<'d, T>, pin: Peri<'d, impl TimerPin<T, Ch1>>, pull: Pull, freq: Hertz) -> Self { pub fn new_ch1<A>(tim: Peri<'d, T>, pin: Peri<'d, impl TimerPin<T, Ch1, A>>, pull: Pull, freq: Hertz) -> Self {
pin.set_as_af(pin.af_num(), AfType::input(pull)); pin.set_as_af(pin.af_num(), AfType::input(pull));
#[cfg(afio)] #[cfg(afio)]
super::set_afio::<T>(&[Some(pin.into())]); pin.afio_remap();
Self::new_inner(tim, freq, Channel::Ch1, Channel::Ch2) Self::new_inner(tim, freq, Channel::Ch1, Channel::Ch2)
} }
/// Create a new PWM input driver. /// Create a new PWM input driver.
pub fn new_ch2(tim: Peri<'d, T>, pin: Peri<'d, impl TimerPin<T, Ch2>>, pull: Pull, freq: Hertz) -> Self { pub fn new_ch2<A>(tim: Peri<'d, T>, pin: Peri<'d, impl TimerPin<T, Ch2, A>>, pull: Pull, freq: Hertz) -> Self {
pin.set_as_af(pin.af_num(), AfType::input(pull)); pin.set_as_af(pin.af_num(), AfType::input(pull));
#[cfg(afio)] #[cfg(afio)]
super::set_afio::<T>(&[Some(pin.into())]); pin.afio_remap();
Self::new_inner(tim, freq, Channel::Ch2, Channel::Ch1) Self::new_inner(tim, freq, Channel::Ch2, Channel::Ch1)
} }

View File

@ -20,18 +20,20 @@ pub enum Direction {
} }
/// Wrapper for using a pin with QEI. /// Wrapper for using a pin with QEI.
pub struct QeiPin<'d, T, Channel> { pub struct QeiPin<'d, T, Channel, A> {
#[allow(unused)] #[allow(unused)]
pin: Peri<'d, AnyPin>, pin: Peri<'d, AnyPin>,
phantom: PhantomData<(T, Channel)>, phantom: PhantomData<(T, Channel, A)>,
} }
impl<'d, T: GeneralInstance4Channel, C: QeiChannel> QeiPin<'d, T, C> { impl<'d, T: GeneralInstance4Channel, C: QeiChannel, A> QeiPin<'d, T, C, A> {
/// Create a new QEI pin instance. /// Create a new QEI pin instance.
pub fn new(pin: Peri<'d, impl TimerPin<T, C>>) -> Self { pub fn new(pin: Peri<'d, impl TimerPin<T, C, A>>) -> Self {
critical_section::with(|_| { critical_section::with(|_| {
pin.set_low(); pin.set_low();
pin.set_as_af(pin.af_num(), AfType::input(Pull::None)); pin.set_as_af(pin.af_num(), AfType::input(Pull::None));
#[cfg(afio)]
pin.afio_remap();
}); });
QeiPin { QeiPin {
pin: pin.into(), pin: pin.into(),
@ -60,9 +62,7 @@ pub struct Qei<'d, T: GeneralInstance4Channel> {
impl<'d, T: GeneralInstance4Channel> Qei<'d, T> { impl<'d, T: GeneralInstance4Channel> Qei<'d, T> {
/// Create a new quadrature decoder driver. /// Create a new quadrature decoder driver.
#[allow(unused)] #[allow(unused)]
pub fn new(tim: Peri<'d, T>, ch1: QeiPin<'d, T, Ch1>, ch2: QeiPin<'d, T, Ch2>) -> Self { pub fn new<A>(tim: Peri<'d, T>, ch1: QeiPin<'d, T, Ch1, A>, ch2: QeiPin<'d, T, Ch2, A>) -> Self {
#[cfg(afio)]
super::set_afio::<T>(&[Some(ch1.pin), Some(ch2.pin)]);
Self::new_inner(tim) Self::new_inner(tim)
} }

View File

@ -14,10 +14,10 @@ use crate::Peri;
/// PWM pin wrapper. /// PWM pin wrapper.
/// ///
/// This wraps a pin to make it usable with PWM. /// This wraps a pin to make it usable with PWM.
pub struct PwmPin<'d, T, C> { pub struct PwmPin<'d, T, C, A> {
#[allow(unused)] #[allow(unused)]
pub(crate) pin: Peri<'d, AnyPin>, pub(crate) pin: Peri<'d, AnyPin>,
phantom: PhantomData<(T, C)>, phantom: PhantomData<(T, C, A)>,
} }
/// PWM pin config /// PWM pin config
@ -35,12 +35,14 @@ pub struct PwmPinConfig {
pub pull: Pull, pub pull: Pull,
} }
impl<'d, T: GeneralInstance4Channel, C: TimerChannel> PwmPin<'d, T, C> { impl<'d, T: GeneralInstance4Channel, C: TimerChannel, A> PwmPin<'d, T, C, A> {
/// Create a new PWM pin instance. /// Create a new PWM pin instance.
pub fn new(pin: Peri<'d, impl TimerPin<T, C>>, output_type: OutputType) -> Self { pub fn new(pin: Peri<'d, impl TimerPin<T, C, A>>, output_type: OutputType) -> Self {
critical_section::with(|_| { critical_section::with(|_| {
pin.set_low(); pin.set_low();
pin.set_as_af(pin.af_num(), AfType::output(output_type, Speed::VeryHigh)); pin.set_as_af(pin.af_num(), AfType::output(output_type, Speed::VeryHigh));
#[cfg(afio)]
pin.afio_remap();
}); });
PwmPin { PwmPin {
pin: pin.into(), pin: pin.into(),
@ -49,7 +51,7 @@ impl<'d, T: GeneralInstance4Channel, C: TimerChannel> PwmPin<'d, T, C> {
} }
/// Create a new PWM pin instance with config. /// Create a new PWM pin instance with config.
pub fn new_with_config(pin: Peri<'d, impl TimerPin<T, C>>, pin_config: PwmPinConfig) -> Self { pub fn new_with_config(pin: Peri<'d, impl TimerPin<T, C, A>>, pin_config: PwmPinConfig) -> Self {
critical_section::with(|_| { critical_section::with(|_| {
pin.set_low(); pin.set_low();
pin.set_as_af( pin.set_as_af(
@ -59,6 +61,8 @@ impl<'d, T: GeneralInstance4Channel, C: TimerChannel> PwmPin<'d, T, C> {
#[cfg(gpio_v2)] #[cfg(gpio_v2)]
AfType::output_pull(pin_config.output_type, pin_config.speed, pin_config.pull), AfType::output_pull(pin_config.output_type, pin_config.speed, pin_config.pull),
); );
#[cfg(afio)]
pin.afio_remap();
}); });
PwmPin { PwmPin {
pin: pin.into(), pin: pin.into(),
@ -180,22 +184,15 @@ pub struct SimplePwm<'d, T: GeneralInstance4Channel> {
impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
/// Create a new simple PWM driver. /// Create a new simple PWM driver.
#[allow(unused)] #[allow(unused)]
pub fn new( pub fn new<A>(
tim: Peri<'d, T>, tim: Peri<'d, T>,
ch1: Option<PwmPin<'d, T, Ch1>>, ch1: Option<PwmPin<'d, T, Ch1, A>>,
ch2: Option<PwmPin<'d, T, Ch2>>, ch2: Option<PwmPin<'d, T, Ch2, A>>,
ch3: Option<PwmPin<'d, T, Ch3>>, ch3: Option<PwmPin<'d, T, Ch3, A>>,
ch4: Option<PwmPin<'d, T, Ch4>>, ch4: Option<PwmPin<'d, T, Ch4, A>>,
freq: Hertz, freq: Hertz,
counting_mode: CountingMode, counting_mode: CountingMode,
) -> Self { ) -> Self {
#[cfg(afio)]
super::set_afio::<T>(&[
ch1.map(|p| p.pin),
ch2.map(|p| p.pin),
ch3.map(|p| p.pin),
ch4.map(|p| p.pin),
]);
Self::new_inner(tim, freq, counting_mode) Self::new_inner(tim, freq, counting_mode)
} }

View File

@ -3,7 +3,7 @@
use defmt::*; use defmt::*;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::gpio::{Level, Output, Pull, Speed}; use embassy_stm32::gpio::{AfioRemap, Level, Output, Pull, Speed};
use embassy_stm32::time::khz; use embassy_stm32::time::khz;
use embassy_stm32::timer::input_capture::{CapturePin, InputCapture}; use embassy_stm32::timer::input_capture::{CapturePin, InputCapture};
use embassy_stm32::timer::{self, Channel}; use embassy_stm32::timer::{self, Channel};
@ -40,7 +40,8 @@ async fn main(spawner: Spawner) {
spawner.spawn(unwrap!(blinky(p.PC13))); spawner.spawn(unwrap!(blinky(p.PC13)));
let ch3 = CapturePin::new(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()); let mut ic =
InputCapture::new::<AfioRemap<0>>(p.TIM2, None, None, Some(ch3), None, Irqs, khz(1000), Default::default());
loop { loop {
info!("wait for rising edge"); info!("wait for rising edge");

View File

@ -3,7 +3,7 @@
use defmt::*; use defmt::*;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::gpio::{Level, Output, Pull, Speed}; use embassy_stm32::gpio::{AfioRemap, Level, Output, Pull, Speed};
use embassy_stm32::time::khz; use embassy_stm32::time::khz;
use embassy_stm32::timer::pwm_input::PwmInput; use embassy_stm32::timer::pwm_input::PwmInput;
use embassy_stm32::{bind_interrupts, peripherals, timer, Peri}; use embassy_stm32::{bind_interrupts, peripherals, timer, Peri};
@ -38,7 +38,7 @@ async fn main(spawner: Spawner) {
spawner.spawn(unwrap!(blinky(p.PC13))); spawner.spawn(unwrap!(blinky(p.PC13)));
let mut pwm_input = PwmInput::new_ch1(p.TIM2, p.PA0, Pull::None, khz(10)); let mut pwm_input = PwmInput::new_ch1::<AfioRemap<0>>(p.TIM2, p.PA0, Pull::None, khz(10));
pwm_input.enable(); pwm_input.enable();
loop { loop {

View File

@ -6,7 +6,7 @@ mod common;
use common::*; use common::*;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::gpio::{OutputType, Pull}; use embassy_stm32::gpio::{AfioRemap, OutputType, Pull};
use embassy_stm32::pac::AFIO; use embassy_stm32::pac::AFIO;
use embassy_stm32::time::khz; use embassy_stm32::time::khz;
use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin}; use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin};
@ -173,7 +173,7 @@ async fn main(_spawner: Spawner) {
{ {
// no remap // no remap
afio_registers_set_remap(); afio_registers_set_remap();
SimplePwm::new( SimplePwm::new::<AfioRemap<0>>(
p.TIM1.reborrow(), p.TIM1.reborrow(),
Some(PwmPin::new(p.PA8.reborrow(), OutputType::PushPull)), Some(PwmPin::new(p.PA8.reborrow(), OutputType::PushPull)),
Some(PwmPin::new(p.PA9.reborrow(), OutputType::PushPull)), Some(PwmPin::new(p.PA9.reborrow(), OutputType::PushPull)),
@ -187,7 +187,7 @@ async fn main(_spawner: Spawner) {
{ {
// no remap // no remap
afio_registers_set_remap(); afio_registers_set_remap();
SimplePwm::new( SimplePwm::new::<AfioRemap<0>>(
p.TIM1.reborrow(), p.TIM1.reborrow(),
Some(PwmPin::new(p.PA8.reborrow(), OutputType::PushPull)), Some(PwmPin::new(p.PA8.reborrow(), OutputType::PushPull)),
None, None,
@ -201,7 +201,7 @@ async fn main(_spawner: Spawner) {
{ {
// partial remap // partial remap
reset_afio_registers(); reset_afio_registers();
ComplementaryPwm::new( ComplementaryPwm::new::<AfioRemap<1>>(
p.TIM1.reborrow(), p.TIM1.reborrow(),
Some(PwmPin::new(p.PA8.reborrow(), OutputType::PushPull)), Some(PwmPin::new(p.PA8.reborrow(), OutputType::PushPull)),
None, None,
@ -219,7 +219,7 @@ async fn main(_spawner: Spawner) {
{ {
// partial remap // partial remap
reset_afio_registers(); reset_afio_registers();
ComplementaryPwm::new( ComplementaryPwm::new::<AfioRemap<1>>(
p.TIM1.reborrow(), p.TIM1.reborrow(),
Some(PwmPin::new(p.PA8.reborrow(), OutputType::PushPull)), Some(PwmPin::new(p.PA8.reborrow(), OutputType::PushPull)),
Some(ComplementaryPwmPin::new(p.PA7.reborrow(), OutputType::PushPull)), Some(ComplementaryPwmPin::new(p.PA7.reborrow(), OutputType::PushPull)),
@ -237,7 +237,7 @@ async fn main(_spawner: Spawner) {
{ {
// partial remap // partial remap
reset_afio_registers(); reset_afio_registers();
InputCapture::new( InputCapture::new::<AfioRemap<1>>(
p.TIM1.reborrow(), p.TIM1.reborrow(),
Some(CapturePin::new(p.PA8.reborrow(), Pull::Down)), Some(CapturePin::new(p.PA8.reborrow(), Pull::Down)),
None, None,
@ -252,13 +252,13 @@ async fn main(_spawner: Spawner) {
{ {
// partial remap // partial remap
reset_afio_registers(); reset_afio_registers();
PwmInput::new_ch1(p.TIM1.reborrow(), p.PA8.reborrow(), Pull::Down, khz(10)); PwmInput::new_ch1::<AfioRemap<1>>(p.TIM1.reborrow(), p.PA8.reborrow(), Pull::Down, khz(10));
defmt::assert_eq!(AFIO.mapr().read().tim1_remap(), 1); defmt::assert_eq!(AFIO.mapr().read().tim1_remap(), 1);
} }
{ {
// partial remap // partial remap
reset_afio_registers(); reset_afio_registers();
Qei::new( Qei::new::<AfioRemap<1>>(
p.TIM1.reborrow(), p.TIM1.reborrow(),
QeiPin::new(p.PA8.reborrow()), QeiPin::new(p.PA8.reborrow()),
QeiPin::new(p.PA9.reborrow()), QeiPin::new(p.PA9.reborrow()),
@ -270,7 +270,7 @@ async fn main(_spawner: Spawner) {
{ {
// no remap // no remap
afio_registers_set_remap(); afio_registers_set_remap();
SimplePwm::new( SimplePwm::new::<AfioRemap<0>>(
p.TIM2.reborrow(), p.TIM2.reborrow(),
Some(PwmPin::new(p.PA0.reborrow(), OutputType::PushPull)), Some(PwmPin::new(p.PA0.reborrow(), OutputType::PushPull)),
Some(PwmPin::new(p.PA1.reborrow(), OutputType::PushPull)), Some(PwmPin::new(p.PA1.reborrow(), OutputType::PushPull)),
@ -284,7 +284,7 @@ async fn main(_spawner: Spawner) {
{ {
// partial remap 1 // partial remap 1
reset_afio_registers(); reset_afio_registers();
SimplePwm::new( SimplePwm::new::<AfioRemap<1>>(
p.TIM2.reborrow(), p.TIM2.reborrow(),
Some(PwmPin::new(p.PA15.reborrow(), OutputType::PushPull)), Some(PwmPin::new(p.PA15.reborrow(), OutputType::PushPull)),
Some(PwmPin::new(p.PB3.reborrow(), OutputType::PushPull)), Some(PwmPin::new(p.PB3.reborrow(), OutputType::PushPull)),
@ -298,7 +298,7 @@ async fn main(_spawner: Spawner) {
{ {
// partial remap 2 // partial remap 2
reset_afio_registers(); reset_afio_registers();
SimplePwm::new( SimplePwm::new::<AfioRemap<2>>(
p.TIM2.reborrow(), p.TIM2.reborrow(),
Some(PwmPin::new(p.PA0.reborrow(), OutputType::PushPull)), Some(PwmPin::new(p.PA0.reborrow(), OutputType::PushPull)),
Some(PwmPin::new(p.PA1.reborrow(), OutputType::PushPull)), Some(PwmPin::new(p.PA1.reborrow(), OutputType::PushPull)),
@ -312,7 +312,7 @@ async fn main(_spawner: Spawner) {
{ {
// full remap // full remap
reset_afio_registers(); reset_afio_registers();
SimplePwm::new( SimplePwm::new::<AfioRemap<3>>(
p.TIM2.reborrow(), p.TIM2.reborrow(),
Some(PwmPin::new(p.PA15.reborrow(), OutputType::PushPull)), Some(PwmPin::new(p.PA15.reborrow(), OutputType::PushPull)),
Some(PwmPin::new(p.PB3.reborrow(), OutputType::PushPull)), Some(PwmPin::new(p.PB3.reborrow(), OutputType::PushPull)),