Merge pull request #4430 from fwolter/add-f1-remap

Add STM32F1 AFIO remap
This commit is contained in:
Dario Nieuwenhuis 2025-09-05 22:45:57 +00:00 committed by GitHub
commit 25e0ebf520
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
40 changed files with 1765 additions and 434 deletions

View File

@ -17,7 +17,7 @@
//"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf",
"rust-analyzer.cargo.features": [
// Comment out these features when working on the examples. Most example crates do not have any cargo features.
"stm32f446re",
"stm32f107rb",
"time-driver-any",
"unstable-pac",
"exti",

6
ci.sh
View File

@ -311,7 +311,9 @@ cargo batch \
--- build --release --manifest-path examples/boot/bootloader/stm32wba-dfu/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-stm32/stm32wba65ri,verify \
--- build --release --manifest-path examples/boot/bootloader/stm32-dual-bank/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32h743zi \
--- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --artifact-dir out/examples/wasm \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f100rd --artifact-dir out/tests/stm32f100rd \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103c8 --artifact-dir out/tests/stm32f103c8 \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f107vc --artifact-dir out/tests/stm32f107vc \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi --artifact-dir out/tests/stm32f429zi \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f446re --artifact-dir out/tests/stm32f446re \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g491re --artifact-dir out/tests/stm32g491re \
@ -398,8 +400,10 @@ rm out/tests/pimoroni-pico-plus-2/pwm
rm out/tests/rpi-pico/pwm
rm out/tests/rpi-pico/cyw43-perf
# tests are implemented but the HIL test farm doesn't actually have this board yet
# tests are implemented but the HIL test farm doesn't actually have these boards, yet
rm -rf out/tests/stm32c071rb
rm -rf out/tests/stm32f100rd
rm -rf out/tests/stm32f107vc
if [[ -z "${TELEPROBE_TOKEN-}" ]]; then
echo No teleprobe token found, skipping running HIL tests

View File

@ -30,6 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- fix: Fix stm32h7rs init when using external flash via XSPI
- feat: Add Adc::new_with_clock() to configure analog clock
- feat: Add GPDMA linked-list + ringbuffer support ([#3923](https://github.com/embassy-rs/embassy/pull/3923))
- feat: Added support for STM32F1 peripheral pin remapping (AFIO) ([#4430](https://github.com/embassy-rs/embassy/pull/4430))
## 0.3.0 - 2025-08-12

View File

@ -1391,9 +1391,53 @@ fn main() {
})
}
g.extend(quote! {
pin_trait_impl!(#tr, #peri, #pin_name, #af);
})
let pin_trait_impl = if let Some(afio) = &p.afio {
let values = afio
.values
.iter()
.filter(|v| v.pins.contains(&pin.pin))
.map(|v| v.value)
.collect::<Vec<_>>();
if values.is_empty() {
None
} else {
let reg = format_ident!("{}", afio.register.to_lowercase());
let setter = format_ident!("set_{}", afio.field.to_lowercase());
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, {#reg, #setter, #type_and_values});
})
}
} else {
let peripherals_with_afio = [
"CAN",
"CEC",
"ETH",
"I2C",
"SPI",
"SUBGHZSPI",
"USART",
"UART",
"LPUART",
"TIM",
];
let not_applicable = if peripherals_with_afio.iter().any(|&x| p.name.starts_with(x)) {
quote!(, crate::gpio::AfioRemapNotApplicable)
} else {
quote!()
};
Some(quote!(pin_trait_impl!(#tr, #peri, #pin_name, #af #not_applicable);))
};
g.extend(pin_trait_impl);
}
// ADC is special
@ -1588,17 +1632,7 @@ fn main() {
let register = format_ident!("{}", remap_info.register.to_lowercase());
let setter = format_ident!("set_{}", remap_info.field.to_lowercase());
let field_metadata = METADATA
.peripherals
.iter()
.filter(|p| p.name == "SYSCFG")
.flat_map(|p| p.registers.as_ref().unwrap().ir.fieldsets.iter())
.filter(|f| f.name.eq_ignore_ascii_case(remap_info.register))
.flat_map(|f| f.fields.iter())
.find(|f| f.name.eq_ignore_ascii_case(remap_info.field))
.unwrap();
let value = if field_metadata.bit_size == 1 {
let value = if is_bool_field("SYSCFG", &remap_info.register, &remap_info.field) {
let bool_value = format_ident!("{}", remap_info.value > 0);
quote!(#bool_value)
} else {
@ -2300,3 +2334,17 @@ fn gcd(a: u32, b: u32) -> u32 {
}
gcd(b, a % b)
}
fn is_bool_field(peripheral: &str, register: &str, field: &str) -> bool {
let field_metadata = METADATA
.peripherals
.iter()
.filter(|p| p.name == peripheral)
.flat_map(|p| p.registers.as_ref().unwrap().ir.fieldsets.iter())
.filter(|f| f.name.eq_ignore_ascii_case(register))
.flat_map(|f| f.fields.iter())
.find(|f| f.name.eq_ignore_ascii_case(field))
.unwrap();
field_metadata.bit_size == 1
}

View File

@ -181,10 +181,10 @@ pub enum TryWriteError {
impl<'d> Can<'d> {
/// Creates a new Bxcan instance, keeping the peripheral in sleep mode.
/// You must call [Can::enable_non_blocking] to use the peripheral.
pub fn new<T: Instance>(
pub fn new<T: Instance, #[cfg(afio)] A>(
_peri: Peri<'d, T>,
rx: Peri<'d, impl RxPin<T>>,
tx: Peri<'d, impl TxPin<T>>,
rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
_irqs: impl interrupt::typelevel::Binding<T::TXInterrupt, TxInterruptHandler<T>>
+ interrupt::typelevel::Binding<T::RX0Interrupt, Rx0InterruptHandler<T>>
+ interrupt::typelevel::Binding<T::RX1Interrupt, Rx1InterruptHandler<T>>
@ -194,8 +194,8 @@ impl<'d> Can<'d> {
let info = T::info();
let regs = &T::info().regs;
rx.set_as_af(rx.af_num(), AfType::input(Pull::None));
tx.set_as_af(tx.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
set_as_af!(rx, AfType::input(Pull::None));
set_as_af!(tx, AfType::output(OutputType::PushPull, Speed::VeryHigh));
rcc::enable_and_reset::<T>();
@ -229,8 +229,8 @@ impl<'d> Can<'d> {
info.sce_interrupt.enable();
}
rx.set_as_af(rx.af_num(), AfType::input(Pull::None));
tx.set_as_af(tx.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
set_as_af!(rx, AfType::input(Pull::None));
set_as_af!(tx, AfType::output(OutputType::PushPull, Speed::VeryHigh));
Registers(T::regs()).leave_init_mode();
@ -1218,8 +1218,8 @@ foreach_peripheral!(
};
);
pin_trait!(RxPin, Instance);
pin_trait!(TxPin, Instance);
pin_trait!(RxPin, Instance, @A);
pin_trait!(TxPin, Instance, @A);
trait Index {
fn index(&self) -> usize;

View File

@ -185,8 +185,8 @@ impl<'d> CanConfigurator<'d> {
+ interrupt::typelevel::Binding<T::IT1Interrupt, IT1InterruptHandler<T>>
+ 'd,
) -> CanConfigurator<'d> {
rx.set_as_af(rx.af_num(), AfType::input(Pull::None));
tx.set_as_af(tx.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
set_as_af!(rx, AfType::input(Pull::None));
set_as_af!(tx, AfType::output(OutputType::PushPull, Speed::VeryHigh));
rcc::enable_and_reset::<T>();

View File

@ -108,7 +108,7 @@ macro_rules! config_pins {
($($pin:ident),*) => {
critical_section::with(|_| {
$(
$pin.set_as_af($pin.af_num(), AfType::input(Pull::None));
set_as_af!($pin, AfType::input(Pull::None));
)*
})
};

View File

@ -78,7 +78,7 @@ impl<'d, T: Instance> DsiHost<'d, T> {
rcc::enable_and_reset::<T>();
// Set Tearing Enable pin according to CubeMx example
te.set_as_af(te.af_num(), AfType::output(OutputType::PushPull, Speed::Low));
set_as_af!(te, AfType::output(OutputType::PushPull, Speed::Low));
/*
T::regs().wcr().modify(|w| {
w.set_dsien(true);

View File

@ -209,19 +209,19 @@ impl SealedInstance for crate::peripherals::ETH {
}
impl Instance for crate::peripherals::ETH {}
pin_trait!(RXClkPin, Instance);
pin_trait!(TXClkPin, Instance);
pin_trait!(RefClkPin, Instance);
pin_trait!(MDIOPin, Instance);
pin_trait!(MDCPin, Instance);
pin_trait!(RXDVPin, Instance);
pin_trait!(CRSPin, Instance);
pin_trait!(RXD0Pin, Instance);
pin_trait!(RXD1Pin, Instance);
pin_trait!(RXD2Pin, Instance);
pin_trait!(RXD3Pin, Instance);
pin_trait!(TXD0Pin, Instance);
pin_trait!(TXD1Pin, Instance);
pin_trait!(TXD2Pin, Instance);
pin_trait!(TXD3Pin, Instance);
pin_trait!(TXEnPin, Instance);
pin_trait!(RXClkPin, Instance, @A);
pin_trait!(TXClkPin, Instance, @A);
pin_trait!(RefClkPin, Instance, @A);
pin_trait!(MDIOPin, Instance, @A);
pin_trait!(MDCPin, Instance, @A);
pin_trait!(RXDVPin, Instance, @A);
pin_trait!(CRSPin, Instance, @A);
pin_trait!(RXD0Pin, Instance, @A);
pin_trait!(RXD1Pin, Instance, @A);
pin_trait!(RXD2Pin, Instance, @A);
pin_trait!(RXD3Pin, Instance, @A);
pin_trait!(TXD0Pin, Instance, @A);
pin_trait!(TXD1Pin, Instance, @A);
pin_trait!(TXD2Pin, Instance, @A);
pin_trait!(TXD3Pin, Instance, @A);
pin_trait!(TXEnPin, Instance, @A);

View File

@ -69,7 +69,7 @@ macro_rules! config_in_pins {
critical_section::with(|_| {
$(
// TODO properly create a set_as_input function
$pin.set_as_af($pin.af_num(), AfType::input(Pull::None));
set_as_af!($pin, AfType::input(Pull::None));
)*
})
}
@ -80,7 +80,7 @@ macro_rules! config_af_pins {
($($pin:ident),*) => {
critical_section::with(|_| {
$(
$pin.set_as_af($pin.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
set_as_af!($pin, AfType::output(OutputType::PushPull, Speed::VeryHigh));
)*
})
};
@ -91,7 +91,7 @@ macro_rules! config_pins {
($($pin:ident),*) => {
critical_section::with(|_| {
$(
$pin.set_as_af($pin.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
set_as_af!($pin, AfType::output(OutputType::PushPull, Speed::VeryHigh));
)*
})
};
@ -99,19 +99,19 @@ macro_rules! config_pins {
impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
/// safety: the returned instance is not leak-safe
pub fn new<const TX: usize, const RX: usize>(
pub fn new<const TX: usize, const RX: usize, #[cfg(afio)] A>(
queue: &'d mut PacketQueue<TX, RX>,
peri: Peri<'d, T>,
irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
ref_clk: Peri<'d, impl RefClkPin<T>>,
mdio: Peri<'d, impl MDIOPin<T>>,
mdc: Peri<'d, impl MDCPin<T>>,
crs: Peri<'d, impl CRSPin<T>>,
rx_d0: Peri<'d, impl RXD0Pin<T>>,
rx_d1: Peri<'d, impl RXD1Pin<T>>,
tx_d0: Peri<'d, impl TXD0Pin<T>>,
tx_d1: Peri<'d, impl TXD1Pin<T>>,
tx_en: Peri<'d, impl TXEnPin<T>>,
ref_clk: Peri<'d, if_afio!(impl RefClkPin<T, A>)>,
mdio: Peri<'d, if_afio!(impl MDIOPin<T, A>)>,
mdc: Peri<'d, if_afio!(impl MDCPin<T, A>)>,
crs: Peri<'d, if_afio!(impl CRSPin<T, A>)>,
rx_d0: Peri<'d, if_afio!(impl RXD0Pin<T, A>)>,
rx_d1: Peri<'d, if_afio!(impl RXD1Pin<T, A>)>,
tx_d0: Peri<'d, if_afio!(impl TXD0Pin<T, A>)>,
tx_d1: Peri<'d, if_afio!(impl TXD1Pin<T, A>)>,
tx_en: Peri<'d, if_afio!(impl TXEnPin<T, A>)>,
phy: P,
mac_addr: [u8; 6],
) -> Self {
@ -289,24 +289,24 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
}
/// Create a new MII ethernet driver using 14 pins.
pub fn new_mii<const TX: usize, const RX: usize>(
pub fn new_mii<const TX: usize, const RX: usize, #[cfg(afio)] A>(
queue: &'d mut PacketQueue<TX, RX>,
peri: Peri<'d, T>,
irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
rx_clk: Peri<'d, impl RXClkPin<T>>,
tx_clk: Peri<'d, impl TXClkPin<T>>,
mdio: Peri<'d, impl MDIOPin<T>>,
mdc: Peri<'d, impl MDCPin<T>>,
rxdv: Peri<'d, impl RXDVPin<T>>,
rx_d0: Peri<'d, impl RXD0Pin<T>>,
rx_d1: Peri<'d, impl RXD1Pin<T>>,
rx_d2: Peri<'d, impl RXD2Pin<T>>,
rx_d3: Peri<'d, impl RXD3Pin<T>>,
tx_d0: Peri<'d, impl TXD0Pin<T>>,
tx_d1: Peri<'d, impl TXD1Pin<T>>,
tx_d2: Peri<'d, impl TXD2Pin<T>>,
tx_d3: Peri<'d, impl TXD3Pin<T>>,
tx_en: Peri<'d, impl TXEnPin<T>>,
rx_clk: Peri<'d, if_afio!(impl RXClkPin<T, A>)>,
tx_clk: Peri<'d, if_afio!(impl TXClkPin<T, A>)>,
mdio: Peri<'d, if_afio!(impl MDIOPin<T, A>)>,
mdc: Peri<'d, if_afio!(impl MDCPin<T, A>)>,
rxdv: Peri<'d, if_afio!(impl RXDVPin<T, A>)>,
rx_d0: Peri<'d, if_afio!(impl RXD0Pin<T, A>)>,
rx_d1: Peri<'d, if_afio!(impl RXD1Pin<T, A>)>,
rx_d2: Peri<'d, if_afio!(impl RXD2Pin<T, A>)>,
rx_d3: Peri<'d, if_afio!(impl RXD3Pin<T, A>)>,
tx_d0: Peri<'d, if_afio!(impl TXD0Pin<T, A>)>,
tx_d1: Peri<'d, if_afio!(impl TXD1Pin<T, A>)>,
tx_d2: Peri<'d, if_afio!(impl TXD2Pin<T, A>)>,
tx_d3: Peri<'d, if_afio!(impl TXD3Pin<T, A>)>,
tx_en: Peri<'d, if_afio!(impl TXEnPin<T, A>)>,
phy: P,
mac_addr: [u8; 6],
) -> Self {

View File

@ -57,7 +57,7 @@ macro_rules! config_pins {
critical_section::with(|_| {
$(
// TODO: shouldn't some pins be configured as inputs?
$pin.set_as_af($pin.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
set_as_af!($pin, AfType::output(OutputType::PushPull, Speed::VeryHigh));
)*
})
};

View File

@ -75,7 +75,7 @@ where
macro_rules! config_pins {
($($pin:ident),*) => {
$(
$pin.set_as_af($pin.af_num(), AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up));
set_as_af!($pin, AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up));
)*
};
}

View File

@ -150,9 +150,13 @@ impl<'d> Flex<'d> {
/// This puts the pin into the AF mode, with the requested number and AF type. This is
/// completely unchecked, it can attach the pin to literally any peripheral, so use with care.
#[inline]
pub fn set_as_af_unchecked(&mut self, af_num: u8, af_type: AfType) {
pub fn set_as_af_unchecked(&mut self, #[cfg(not(afio))] af_num: u8, af_type: AfType) {
critical_section::with(|_| {
self.pin.set_as_af(af_num, af_type);
self.pin.set_as_af(
#[cfg(not(afio))]
af_num,
af_type,
);
});
}
@ -588,7 +592,7 @@ impl AfType {
#[inline(never)]
#[cfg(gpio_v1)]
fn set_as_af(pin_port: u8, _af_num: u8, af_type: AfType) {
fn set_as_af(pin_port: u8, af_type: AfType) {
let pin = unsafe { AnyPin::steal(pin_port) };
let r = pin.block();
let n = pin._pin() as usize;
@ -710,6 +714,18 @@ fn get_pull(pin_port: u8) -> Pull {
};
}
#[cfg(afio)]
/// Holds the AFIO remap value for a peripheral's pin
pub struct AfioRemap<const V: u8>;
#[cfg(afio)]
/// Holds the AFIO remap value for a peripheral's pin
pub struct AfioRemapBool<const V: bool>;
#[cfg(afio)]
/// Placeholder for a peripheral's pin which cannot be remapped via AFIO.
pub struct AfioRemapNotApplicable;
pub(crate) trait SealedPin {
fn pin_port(&self) -> u8;
@ -743,8 +759,13 @@ pub(crate) trait SealedPin {
}
#[inline]
fn set_as_af(&self, af_num: u8, af_type: AfType) {
set_as_af(self.pin_port(), af_num, af_type)
fn set_as_af(&self, #[cfg(not(afio))] af_num: u8, af_type: AfType) {
set_as_af(
self.pin_port(),
#[cfg(not(afio))]
af_num,
af_type,
)
}
#[inline]

View File

@ -79,10 +79,7 @@ macro_rules! advanced_channel_impl {
pub fn $new_chx(pin: Peri<'d, impl $pin_trait<T>>) -> Self {
critical_section::with(|_| {
pin.set_low();
pin.set_as_af(
pin.af_num(),
AfType::output(OutputType::PushPull, Speed::VeryHigh),
);
set_as_af!(pin, AfType::output(OutputType::PushPull, Speed::VeryHigh));
});
PwmPin {
_pin: pin.into(),
@ -96,10 +93,7 @@ macro_rules! advanced_channel_impl {
pub fn $new_chx(pin: Peri<'d, impl $complementary_pin_trait<T>>) -> Self {
critical_section::with(|_| {
pin.set_low();
pin.set_as_af(
pin.af_num(),
AfType::output(OutputType::PushPull, Speed::VeryHigh),
);
set_as_af!(pin, AfType::output(OutputType::PushPull, Speed::VeryHigh));
});
ComplementaryPwmPin {
_pin: pin.into(),

View File

@ -149,10 +149,10 @@ pub struct I2c<'d, M: Mode, IM: MasterMode> {
impl<'d> I2c<'d, Async, Master> {
/// Create a new I2C driver.
pub fn new<T: Instance>(
pub fn new<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
scl: Peri<'d, impl SclPin<T>>,
sda: Peri<'d, impl SdaPin<T>>,
scl: Peri<'d, if_afio!(impl SclPin<T, A>)>,
sda: Peri<'d, if_afio!(impl SdaPin<T, A>)>,
_irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>>
+ interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>>
+ 'd,
@ -173,10 +173,10 @@ impl<'d> I2c<'d, Async, Master> {
impl<'d> I2c<'d, Blocking, Master> {
/// Create a new blocking I2C driver.
pub fn new_blocking<T: Instance>(
pub fn new_blocking<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
scl: Peri<'d, impl SclPin<T>>,
sda: Peri<'d, impl SdaPin<T>>,
scl: Peri<'d, if_afio!(impl SclPin<T, A>)>,
sda: Peri<'d, if_afio!(impl SdaPin<T, A>)>,
config: Config,
) -> Self {
Self::new_inner(
@ -296,8 +296,8 @@ peri_trait!(
irqs: [EventInterrupt, ErrorInterrupt],
);
pin_trait!(SclPin, Instance);
pin_trait!(SdaPin, Instance);
pin_trait!(SclPin, Instance, @A);
pin_trait!(SdaPin, Instance, @A);
dma_trait!(RxDma, Instance);
dma_trait!(TxDma, Instance);

View File

@ -237,12 +237,12 @@ pub struct I2S<'d, W: Word> {
impl<'d, W: Word> I2S<'d, W> {
/// Create a transmitter driver.
pub fn new_txonly<T: Instance>(
pub fn new_txonly<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
sd: Peri<'d, impl MosiPin<T>>,
ws: Peri<'d, impl WsPin<T>>,
ck: Peri<'d, impl CkPin<T>>,
mck: Peri<'d, impl MckPin<T>>,
sd: Peri<'d, if_afio!(impl MosiPin<T, A>)>,
ws: Peri<'d, if_afio!(impl WsPin<T, A>)>,
ck: Peri<'d, if_afio!(impl CkPin<T, A>)>,
mck: Peri<'d, if_afio!(impl MckPin<T, A>)>,
txdma: Peri<'d, impl TxDma<T>>,
txdma_buf: &'d mut [W],
config: Config,
@ -262,11 +262,11 @@ impl<'d, W: Word> I2S<'d, W> {
}
/// Create a transmitter driver without a master clock pin.
pub fn new_txonly_nomck<T: Instance>(
pub fn new_txonly_nomck<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
sd: Peri<'d, impl MosiPin<T>>,
ws: Peri<'d, impl WsPin<T>>,
ck: Peri<'d, impl CkPin<T>>,
sd: Peri<'d, if_afio!(impl MosiPin<T, A>)>,
ws: Peri<'d, if_afio!(impl WsPin<T, A>)>,
ck: Peri<'d, if_afio!(impl CkPin<T, A>)>,
txdma: Peri<'d, impl TxDma<T>>,
txdma_buf: &'d mut [W],
config: Config,
@ -286,12 +286,12 @@ impl<'d, W: Word> I2S<'d, W> {
}
/// Create a receiver driver.
pub fn new_rxonly<T: Instance>(
pub fn new_rxonly<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
sd: Peri<'d, impl MisoPin<T>>,
ws: Peri<'d, impl WsPin<T>>,
ck: Peri<'d, impl CkPin<T>>,
mck: Peri<'d, impl MckPin<T>>,
sd: Peri<'d, if_afio!(impl MisoPin<T, A>)>,
ws: Peri<'d, if_afio!(impl WsPin<T, A>)>,
ck: Peri<'d, if_afio!(impl CkPin<T, A>)>,
mck: Peri<'d, if_afio!(impl MckPin<T, A>)>,
rxdma: Peri<'d, impl RxDma<T>>,
rxdma_buf: &'d mut [W],
config: Config,
@ -313,13 +313,13 @@ impl<'d, W: Word> I2S<'d, W> {
#[cfg(any(spi_v4, spi_v5))]
/// Create a full duplex driver.
pub fn new_full_duplex<T: Instance>(
pub fn new_full_duplex<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
txsd: Peri<'d, impl MosiPin<T>>,
rxsd: Peri<'d, impl MisoPin<T>>,
ws: Peri<'d, impl WsPin<T>>,
ck: Peri<'d, impl CkPin<T>>,
mck: Peri<'d, impl MckPin<T>>,
txsd: Peri<'d, if_afio!(impl MosiPin<T, A>)>,
rxsd: Peri<'d, if_afio!(impl MisoPin<T, A>)>,
ws: Peri<'d, if_afio!(impl WsPin<T, A>)>,
ck: Peri<'d, if_afio!(impl CkPin<T, A>)>,
mck: Peri<'d, if_afio!(impl MckPin<T, A>)>,
txdma: Peri<'d, impl TxDma<T>>,
txdma_buf: &'d mut [W],
rxdma: Peri<'d, impl RxDma<T>>,
@ -459,20 +459,20 @@ impl<'d, W: Word> I2S<'d, W> {
}
}
fn new_inner<T: Instance>(
fn new_inner<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
txsd: Option<Peri<'d, AnyPin>>,
rxsd: Option<Peri<'d, AnyPin>>,
ws: Peri<'d, impl WsPin<T>>,
ck: Peri<'d, impl CkPin<T>>,
ws: Peri<'d, if_afio!(impl WsPin<T, A>)>,
ck: Peri<'d, if_afio!(impl CkPin<T, A>)>,
mck: Option<Peri<'d, AnyPin>>,
txdma: Option<(ChannelAndRequest<'d>, &'d mut [W])>,
rxdma: Option<(ChannelAndRequest<'d>, &'d mut [W])>,
config: Config,
function: Function,
) -> Self {
ws.set_as_af(ws.af_num(), AfType::output(OutputType::PushPull, config.gpio_speed));
ck.set_as_af(ck.af_num(), AfType::output(OutputType::PushPull, config.gpio_speed));
set_as_af!(ws, AfType::output(OutputType::PushPull, config.gpio_speed));
set_as_af!(ck, AfType::output(OutputType::PushPull, config.gpio_speed));
let spi = Spi::new_internal(peri, None, None, {
let mut spi_config = SpiConfig::default();

View File

@ -50,10 +50,7 @@ macro_rules! channel_impl {
pub fn $new_chx(pin: Peri<'d, impl $pin_trait<T>>) -> Self {
critical_section::with(|_| {
pin.set_low();
pin.set_as_af(
pin.af_num(),
AfType::output(OutputType::PushPull, Speed::VeryHigh),
);
set_as_af!(pin, AfType::output(OutputType::PushPull, Speed::VeryHigh));
});
PwmPin {
_pin: pin.into(),
@ -64,12 +61,12 @@ macro_rules! channel_impl {
pub fn $new_chx_with_config(pin: Peri<'d, impl $pin_trait<T>>, 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),
#[cfg(gpio_v1)]
set_as_af!(pin, AfType::output(pin_config.output_type, pin_config.speed));
#[cfg(gpio_v2)]
set_as_af!(
pin,
AfType::output_pull(pin_config.output_type, pin_config.speed, pin_config.pull)
);
});
PwmPin {

View File

@ -41,17 +41,30 @@ macro_rules! peri_trait_impl {
}
macro_rules! pin_trait {
($signal:ident, $instance:path $(, $mode:path)?) => {
($signal:ident, $instance:path $(, $mode:path)? $(, @$afio:ident)?) => {
#[doc = concat!(stringify!($signal), " pin trait")]
pub trait $signal<T: $instance $(, M: $mode)?>: crate::gpio::Pin {
pub trait $signal<T: $instance $(, M: $mode)? $(, #[cfg(afio)] $afio)?>: crate::gpio::Pin {
#[cfg(not(afio))]
#[doc = concat!("Get the AF number needed to use this pin as ", stringify!($signal))]
fn af_num(&self) -> u8;
#[cfg(afio)]
#[doc = concat!("Configures AFIO_MAPR to use this pin as ", stringify!($signal))]
fn afio_remap(&self);
}
};
}
macro_rules! pin_trait_impl {
(crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, $pin:ident, $af:expr) => {
(crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, $pin:ident, $af:expr $(, $afio:path)?) => {
#[cfg(afio)]
impl crate::$mod::$trait<crate::peripherals::$instance $(, crate::$mod::$mode)? $(, $afio)?> for crate::peripherals::$pin {
fn afio_remap(&self) {
// nothing
}
}
#[cfg(not(afio))]
impl crate::$mod::$trait<crate::peripherals::$instance $(, crate::$mod::$mode)?> for crate::peripherals::$pin {
fn af_num(&self) -> u8 {
$af
@ -60,6 +73,39 @@ macro_rules! pin_trait_impl {
};
}
#[cfg(afio)]
macro_rules! pin_trait_afio_impl {
(@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 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 {
fn afio_remap(&self) {
pin_trait_afio_impl!(@set $reg, $setter, $val);
}
}
)+
};
}
#[allow(unused_macros)]
macro_rules! sel_trait_impl {
(crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, $pin:ident, $sel:expr) => {
@ -134,7 +180,73 @@ macro_rules! new_dma {
macro_rules! new_pin {
($name:ident, $af_type:expr) => {{
let pin = $name;
pin.set_as_af(pin.af_num(), $af_type);
#[cfg(afio)]
pin.afio_remap();
pin.set_as_af(
#[cfg(not(afio))]
pin.af_num(),
$af_type,
);
Some(pin.into())
}};
}
/// Macro to configure a pin for alternate function use.
/// For AFIO chips (STM32F1), it calls afio_remap().
/// For non-AFIO chips, it calls set_as_af() with the pin's af_num().
macro_rules! set_as_af {
($pin:expr, $af_type:expr) => {
#[cfg(afio)]
{
$pin.set_as_af($af_type);
$pin.afio_remap();
}
#[cfg(not(afio))]
{
$pin.set_as_af($pin.af_num(), $af_type);
}
};
}
#[cfg(afio)]
macro_rules! if_afio {
($($t:tt)*) => {
$($t)*
}
}
#[cfg(not(afio))]
macro_rules! if_afio {
(($a:ty, A)) => {
($a,)
};
(($a:ty, $b:ty, A)) => {
($a,$b)
};
(($a:ty, $b:ty, $c:ty, A)) => {
($a,$b, $c)
};
($type:ident<$lt:lifetime, $a:ty, $b:ty, A>) => {
$type<$lt, $a, $b>
};
($type:ident<$lt:lifetime, $a:ty, $b:ty, $c:ty, A>) => {
$type<$lt, $a, $b, $c>
};
($type:ident<$a:ty, A>) => {
$type<$a>
};
($type:ident<$a:ty, $b:ty, A>) => {
$type<$a, $b>
};
($type:ident<$a:ty, $b:ty, $c:ty, A>) => {
$type<$a, $b, $c>
};
(impl $trait:ident<$a:ty, A>) => {
impl $trait<$a>
};
(impl $trait:ident<$a:ty, $b:ty, A>) => {
impl $trait<$a, $b>
};
(impl $trait:ident<$a:ty, $b:ty, $c:ty, A>) => {
impl $trait<$a, $b, $c>
};
}

View File

@ -94,7 +94,7 @@ impl<'d, T: McoInstance> Mco<'d, T> {
pub fn new(_peri: Peri<'d, T>, pin: Peri<'d, impl McoPin<T>>, source: T::Source, prescaler: McoPrescaler) -> Self {
critical_section::with(|_| unsafe {
T::_apply_clock_settings(source, prescaler);
pin.set_as_af(pin.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
set_as_af!(pin, AfType::output(OutputType::PushPull, Speed::VeryHigh));
});
Self { phantom: PhantomData }

View File

@ -558,7 +558,7 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> {
config: Config,
) -> Self {
let (_sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx);
mclk.set_as_af(mclk.af_num(), ck_af_type);
set_as_af!(mclk, ck_af_type);
Self::new_asynchronous(peri, sck, sd, fs, dma, dma_buf, config)
}
@ -578,9 +578,9 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> {
let peri = peri.peri;
let (sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx);
sd.set_as_af(sd.af_num(), sd_af_type);
sck.set_as_af(sck.af_num(), ck_af_type);
fs.set_as_af(fs.af_num(), ck_af_type);
set_as_af!(sd, sd_af_type);
set_as_af!(sck, ck_af_type);
set_as_af!(fs, ck_af_type);
let sub_block = S::WHICH;
let request = dma.request();
@ -612,7 +612,7 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> {
let peri = peri.peri;
let (sd_af_type, _ck_af_type) = get_af_types(config.mode, config.tx_rx);
sd.set_as_af(sd.af_num(), sd_af_type);
set_as_af!(sd, sd_af_type);
let sub_block = S::WHICH;
let request = dma.request();

View File

@ -428,9 +428,9 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
config: Config,
) -> Self {
critical_section::with(|_| {
clk.set_as_af(clk.af_num(), CLK_AF);
cmd.set_as_af(cmd.af_num(), CMD_AF);
d0.set_as_af(d0.af_num(), DATA_AF);
set_as_af!(clk, CLK_AF);
set_as_af!(cmd, CMD_AF);
set_as_af!(d0, DATA_AF);
});
Self::new_inner(
@ -464,12 +464,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
config: Config,
) -> Self {
critical_section::with(|_| {
clk.set_as_af(clk.af_num(), CLK_AF);
cmd.set_as_af(cmd.af_num(), CMD_AF);
d0.set_as_af(d0.af_num(), DATA_AF);
d1.set_as_af(d1.af_num(), DATA_AF);
d2.set_as_af(d2.af_num(), DATA_AF);
d3.set_as_af(d3.af_num(), DATA_AF);
set_as_af!(clk, CLK_AF);
set_as_af!(cmd, CMD_AF);
set_as_af!(d0, DATA_AF);
set_as_af!(d1, DATA_AF);
set_as_af!(d2, DATA_AF);
set_as_af!(d3, DATA_AF);
});
Self::new_inner(
@ -510,16 +510,16 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
config: Config,
) -> Self {
critical_section::with(|_| {
clk.set_as_af(clk.af_num(), CLK_AF);
cmd.set_as_af(cmd.af_num(), CMD_AF);
d0.set_as_af(d0.af_num(), DATA_AF);
d1.set_as_af(d1.af_num(), DATA_AF);
d2.set_as_af(d2.af_num(), DATA_AF);
d3.set_as_af(d3.af_num(), DATA_AF);
d4.set_as_af(d4.af_num(), DATA_AF);
d5.set_as_af(d5.af_num(), DATA_AF);
d6.set_as_af(d6.af_num(), DATA_AF);
d7.set_as_af(d7.af_num(), DATA_AF);
set_as_af!(clk, CLK_AF);
set_as_af!(cmd, CMD_AF);
set_as_af!(d0, DATA_AF);
set_as_af!(d1, DATA_AF);
set_as_af!(d2, DATA_AF);
set_as_af!(d3, DATA_AF);
set_as_af!(d4, DATA_AF);
set_as_af!(d5, DATA_AF);
set_as_af!(d6, DATA_AF);
set_as_af!(d7, DATA_AF);
});
Self::new_inner(
@ -552,9 +552,9 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
config: Config,
) -> Self {
critical_section::with(|_| {
clk.set_as_af(clk.af_num(), CLK_AF);
cmd.set_as_af(cmd.af_num(), CMD_AF);
d0.set_as_af(d0.af_num(), DATA_AF);
set_as_af!(clk, CLK_AF);
set_as_af!(cmd, CMD_AF);
set_as_af!(d0, DATA_AF);
});
Self::new_inner(
@ -586,12 +586,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
config: Config,
) -> Self {
critical_section::with(|_| {
clk.set_as_af(clk.af_num(), CLK_AF);
cmd.set_as_af(cmd.af_num(), CMD_AF);
d0.set_as_af(d0.af_num(), DATA_AF);
d1.set_as_af(d1.af_num(), DATA_AF);
d2.set_as_af(d2.af_num(), DATA_AF);
d3.set_as_af(d3.af_num(), DATA_AF);
set_as_af!(clk, CLK_AF);
set_as_af!(cmd, CMD_AF);
set_as_af!(d0, DATA_AF);
set_as_af!(d1, DATA_AF);
set_as_af!(d2, DATA_AF);
set_as_af!(d3, DATA_AF);
});
Self::new_inner(
@ -630,16 +630,16 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
config: Config,
) -> Self {
critical_section::with(|_| {
clk.set_as_af(clk.af_num(), CLK_AF);
cmd.set_as_af(cmd.af_num(), CMD_AF);
d0.set_as_af(d0.af_num(), DATA_AF);
d1.set_as_af(d1.af_num(), DATA_AF);
d2.set_as_af(d2.af_num(), DATA_AF);
d3.set_as_af(d3.af_num(), DATA_AF);
d4.set_as_af(d4.af_num(), DATA_AF);
d5.set_as_af(d5.af_num(), DATA_AF);
d6.set_as_af(d6.af_num(), DATA_AF);
d7.set_as_af(d7.af_num(), DATA_AF);
set_as_af!(clk, CLK_AF);
set_as_af!(cmd, CMD_AF);
set_as_af!(d0, DATA_AF);
set_as_af!(d1, DATA_AF);
set_as_af!(d2, DATA_AF);
set_as_af!(d3, DATA_AF);
set_as_af!(d4, DATA_AF);
set_as_af!(d5, DATA_AF);
set_as_af!(d6, DATA_AF);
set_as_af!(d7, DATA_AF);
});
Self::new_inner(

View File

@ -35,7 +35,7 @@ macro_rules! new_spdifrx_pin {
($name:ident, $af_type:expr) => {{
let pin = $name;
let input_sel = pin.input_sel();
pin.set_as_af(pin.af_num(), $af_type);
set_as_af!(pin, $af_type);
(Some(pin.into()), input_sel)
}};
}

View File

@ -471,11 +471,11 @@ impl<'d, M: PeriMode> Spi<'d, M> {
impl<'d> Spi<'d, Blocking> {
/// Create a new blocking SPI driver.
pub fn new_blocking<T: Instance>(
pub fn new_blocking<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
sck: Peri<'d, impl SckPin<T>>,
mosi: Peri<'d, impl MosiPin<T>>,
miso: Peri<'d, impl MisoPin<T>>,
sck: Peri<'d, if_afio!(impl SckPin<T, A>)>,
mosi: Peri<'d, if_afio!(impl MosiPin<T, A>)>,
miso: Peri<'d, if_afio!(impl MisoPin<T, A>)>,
config: Config,
) -> Self {
Self::new_inner(
@ -490,10 +490,10 @@ impl<'d> Spi<'d, Blocking> {
}
/// Create a new blocking SPI driver, in RX-only mode (only MISO pin, no MOSI).
pub fn new_blocking_rxonly<T: Instance>(
pub fn new_blocking_rxonly<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
sck: Peri<'d, impl SckPin<T>>,
miso: Peri<'d, impl MisoPin<T>>,
sck: Peri<'d, if_afio!(impl SckPin<T, A>)>,
miso: Peri<'d, if_afio!(impl MisoPin<T, A>)>,
config: Config,
) -> Self {
Self::new_inner(
@ -508,10 +508,10 @@ impl<'d> Spi<'d, Blocking> {
}
/// Create a new blocking SPI driver, in TX-only mode (only MOSI pin, no MISO).
pub fn new_blocking_txonly<T: Instance>(
pub fn new_blocking_txonly<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
sck: Peri<'d, impl SckPin<T>>,
mosi: Peri<'d, impl MosiPin<T>>,
sck: Peri<'d, if_afio!(impl SckPin<T, A>)>,
mosi: Peri<'d, if_afio!(impl MosiPin<T, A>)>,
config: Config,
) -> Self {
Self::new_inner(
@ -528,9 +528,9 @@ impl<'d> Spi<'d, Blocking> {
/// Create a new SPI driver, in TX-only mode, without SCK pin.
///
/// This can be useful for bit-banging non-SPI protocols.
pub fn new_blocking_txonly_nosck<T: Instance>(
pub fn new_blocking_txonly_nosck<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
mosi: Peri<'d, impl MosiPin<T>>,
mosi: Peri<'d, if_afio!(impl MosiPin<T, A>)>,
config: Config,
) -> Self {
Self::new_inner(
@ -547,11 +547,11 @@ impl<'d> Spi<'d, Blocking> {
impl<'d> Spi<'d, Async> {
/// Create a new SPI driver.
pub fn new<T: Instance>(
pub fn new<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
sck: Peri<'d, impl SckPin<T>>,
mosi: Peri<'d, impl MosiPin<T>>,
miso: Peri<'d, impl MisoPin<T>>,
sck: Peri<'d, if_afio!(impl SckPin<T, A>)>,
mosi: Peri<'d, if_afio!(impl MosiPin<T, A>)>,
miso: Peri<'d, if_afio!(impl MisoPin<T, A>)>,
tx_dma: Peri<'d, impl TxDma<T>>,
rx_dma: Peri<'d, impl RxDma<T>>,
config: Config,
@ -568,10 +568,10 @@ impl<'d> Spi<'d, Async> {
}
/// Create a new SPI driver, in RX-only mode (only MISO pin, no MOSI).
pub fn new_rxonly<T: Instance>(
pub fn new_rxonly<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
sck: Peri<'d, impl SckPin<T>>,
miso: Peri<'d, impl MisoPin<T>>,
sck: Peri<'d, if_afio!(impl SckPin<T, A>)>,
miso: Peri<'d, if_afio!(impl MisoPin<T, A>)>,
#[cfg(any(spi_v1, spi_v2, spi_v3))] tx_dma: Peri<'d, impl TxDma<T>>,
rx_dma: Peri<'d, impl RxDma<T>>,
config: Config,
@ -591,10 +591,10 @@ impl<'d> Spi<'d, Async> {
}
/// Create a new SPI driver, in TX-only mode (only MOSI pin, no MISO).
pub fn new_txonly<T: Instance>(
pub fn new_txonly<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
sck: Peri<'d, impl SckPin<T>>,
mosi: Peri<'d, impl MosiPin<T>>,
sck: Peri<'d, if_afio!(impl SckPin<T, A>)>,
mosi: Peri<'d, if_afio!(impl MosiPin<T, A>)>,
tx_dma: Peri<'d, impl TxDma<T>>,
config: Config,
) -> Self {
@ -612,9 +612,9 @@ impl<'d> Spi<'d, Async> {
/// Create a new SPI driver, in TX-only mode, without SCK pin.
///
/// This can be useful for bit-banging non-SPI protocols.
pub fn new_txonly_nosck<T: Instance>(
pub fn new_txonly_nosck<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
mosi: Peri<'d, impl MosiPin<T>>,
mosi: Peri<'d, if_afio!(impl MosiPin<T, A>)>,
tx_dma: Peri<'d, impl TxDma<T>>,
config: Config,
) -> Self {
@ -1309,13 +1309,13 @@ impl State {
peri_trait!();
pin_trait!(SckPin, Instance);
pin_trait!(MosiPin, Instance);
pin_trait!(MisoPin, Instance);
pin_trait!(CsPin, Instance);
pin_trait!(MckPin, Instance);
pin_trait!(CkPin, Instance);
pin_trait!(WsPin, Instance);
pin_trait!(SckPin, Instance, @A);
pin_trait!(MosiPin, Instance, @A);
pin_trait!(MisoPin, Instance, @A);
pin_trait!(CsPin, Instance, @A);
pin_trait!(MckPin, Instance, @A);
pin_trait!(CkPin, Instance, @A);
pin_trait!(WsPin, Instance, @A);
dma_trait!(RxDma, Instance);
dma_trait!(TxDma, Instance);

View File

@ -16,23 +16,24 @@ use crate::Peri;
/// Complementary PWM pin wrapper.
///
/// This wraps a pin to make it usable with PWM.
pub struct ComplementaryPwmPin<'d, T, C> {
_pin: Peri<'d, AnyPin>,
phantom: PhantomData<(T, C)>,
pub struct ComplementaryPwmPin<'d, T, C, #[cfg(afio)] A> {
#[allow(unused)]
pin: Peri<'d, AnyPin>,
phantom: PhantomData<if_afio!((T, C, A))>,
}
impl<'d, T: AdvancedInstance4Channel, C: TimerChannel> ComplementaryPwmPin<'d, T, C> {
impl<'d, T: AdvancedInstance4Channel, C: TimerChannel, #[cfg(afio)] A> if_afio!(ComplementaryPwmPin<'d, T, C, A>) {
/// 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, if_afio!(impl TimerComplementaryPin<T, C, A>)>, 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),
set_as_af!(
pin,
crate::gpio::AfType::output(output_type, crate::gpio::Speed::VeryHigh)
);
});
ComplementaryPwmPin {
_pin: pin.into(),
pin: pin.into(),
phantom: PhantomData,
}
}
@ -54,17 +55,17 @@ pub enum IdlePolarity {
impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
/// Create a new complementary PWM driver.
#[allow(clippy::too_many_arguments)]
pub fn new(
#[allow(clippy::too_many_arguments, unused)]
pub fn new<#[cfg(afio)] A>(
tim: Peri<'d, T>,
_ch1: Option<PwmPin<'d, T, Ch1>>,
_ch1n: Option<ComplementaryPwmPin<'d, T, Ch1>>,
_ch2: Option<PwmPin<'d, T, Ch2>>,
_ch2n: Option<ComplementaryPwmPin<'d, T, Ch2>>,
_ch3: Option<PwmPin<'d, T, Ch3>>,
_ch3n: Option<ComplementaryPwmPin<'d, T, Ch3>>,
_ch4: Option<PwmPin<'d, T, Ch4>>,
_ch4n: Option<ComplementaryPwmPin<'d, T, Ch4>>,
ch1: Option<if_afio!(PwmPin<'d, T, Ch1, A>)>,
ch1n: Option<if_afio!(ComplementaryPwmPin<'d, T, Ch1, A>)>,
ch2: Option<if_afio!(PwmPin<'d, T, Ch2, A>)>,
ch2n: Option<if_afio!(ComplementaryPwmPin<'d, T, Ch2, A>)>,
ch3: Option<if_afio!(PwmPin<'d, T, Ch3, A>)>,
ch3n: Option<if_afio!(ComplementaryPwmPin<'d, T, Ch3, A>)>,
ch4: Option<if_afio!(PwmPin<'d, T, Ch4, A>)>,
ch4n: Option<if_afio!(ComplementaryPwmPin<'d, T, Ch4, A>)>,
freq: Hertz,
counting_mode: CountingMode,
) -> Self {

View File

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

View File

@ -223,15 +223,15 @@ pub trait AdvancedInstance2Channel: BasicInstance + GeneralInstance2Channel + Ad
/// Advanced 16-bit timer with 4 channels instance.
pub trait AdvancedInstance4Channel: AdvancedInstance2Channel + GeneralInstance4Channel {}
pin_trait!(TimerPin, GeneralInstance4Channel, TimerChannel);
pin_trait!(ExternalTriggerPin, GeneralInstance4Channel);
pin_trait!(TimerPin, GeneralInstance4Channel, TimerChannel, @A);
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!(BreakInputComparator2Pin, AdvancedInstance4Channel, BreakInput);
pin_trait!(BreakInputComparator1Pin, AdvancedInstance4Channel, BreakInput, @A);
pin_trait!(BreakInputComparator2Pin, AdvancedInstance4Channel, BreakInput, @A);
// Update Event trigger DMA for every timer
dma_trait!(UpDma, BasicInstance);

View File

@ -15,6 +15,7 @@ use crate::gpio::{AfType, AnyPin, Pull};
use crate::interrupt::typelevel::{Binding, Interrupt};
use crate::pac::timer::vals::Etp;
use crate::time::Hertz;
use crate::timer::TimerChannel;
use crate::Peri;
/// External input marker type.
@ -42,7 +43,8 @@ impl From<ExternalTriggerPolarity> for Etp {
///
/// This wraps a pin to make it usable as a timer trigger.
pub struct TriggerPin<'d, T, C> {
_pin: Peri<'d, AnyPin>,
#[allow(unused)]
pin: Peri<'d, AnyPin>,
phantom: PhantomData<(T, C)>,
}
@ -60,60 +62,23 @@ impl SealedTriggerSource for Ch1 {}
impl SealedTriggerSource for Ch2 {}
impl SealedTriggerSource for Ext {}
trait SealedTimerTriggerPin<T, S>: 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<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));
impl<'d, T: GeneralInstance4Channel, C: TriggerSource + TimerChannel> TriggerPin<'d, T, C> {
/// Create a new Channel trigger pin instance.
pub fn new<#[cfg(afio)] A>(pin: Peri<'d, if_afio!(impl TimerPin<T, C, A>)>, pull: Pull) -> Self {
set_as_af!(pin, AfType::input(pull));
TriggerPin {
_pin: pin.into(),
pin: pin.into(),
phantom: PhantomData,
}
}
}
impl<'d, T: GeneralInstance4Channel> TriggerPin<'d, T, Ext> {
/// Create a new external trigger pin instance.
pub fn new_external<#[cfg(afio)] A>(pin: Peri<'d, if_afio!(impl ExternalTriggerPin<T, A>)>, pull: Pull) -> Self {
set_as_af!(pin, AfType::input(pull));
TriggerPin {
pin: pin.into(),
phantom: PhantomData,
}
}
@ -131,9 +96,10 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> {
///
/// The pulse is triggered by a channel 1 input pin on both rising and
/// falling edges. Channel 1 will unusable as an output.
#[allow(unused)]
pub fn new_ch1_edge_detect(
tim: Peri<'d, T>,
_pin: TriggerPin<'d, T, Ch1>,
pin: TriggerPin<'d, T, Ch1>,
_irq: impl Binding<T::CaptureCompareInterrupt, CaptureCompareInterruptHandler<T>> + 'd,
freq: Hertz,
pulse_end: u32,

View File

@ -18,15 +18,25 @@ pub struct PwmInput<'d, T: GeneralInstance4Channel> {
impl<'d, T: GeneralInstance4Channel> PwmInput<'d, T> {
/// 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 {
pin.set_as_af(pin.af_num(), AfType::input(pull));
pub fn new_ch1<#[cfg(afio)] A>(
tim: Peri<'d, T>,
pin: Peri<'d, if_afio!(impl TimerPin<T, Ch1, A>)>,
pull: Pull,
freq: Hertz,
) -> Self {
set_as_af!(pin, AfType::input(pull));
Self::new_inner(tim, freq, Channel::Ch1, Channel::Ch2)
}
/// 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 {
pin.set_as_af(pin.af_num(), AfType::input(pull));
pub fn new_ch2<#[cfg(afio)] A>(
tim: Peri<'d, T>,
pin: Peri<'d, if_afio!(impl TimerPin<T, Ch2, A>)>,
pull: Pull,
freq: Hertz,
) -> Self {
set_as_af!(pin, AfType::input(pull));
Self::new_inner(tim, freq, Channel::Ch2, Channel::Ch1)
}

View File

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

View File

@ -14,9 +14,10 @@ use crate::Peri;
/// PWM pin wrapper.
///
/// This wraps a pin to make it usable with PWM.
pub struct PwmPin<'d, T, C> {
_pin: Peri<'d, AnyPin>,
phantom: PhantomData<(T, C)>,
pub struct PwmPin<'d, T, C, #[cfg(afio)] A> {
#[allow(unused)]
pub(crate) pin: Peri<'d, AnyPin>,
phantom: PhantomData<if_afio!((T, C, A))>,
}
/// PWM pin config
@ -34,33 +35,33 @@ pub struct PwmPinConfig {
pub pull: Pull,
}
impl<'d, T: GeneralInstance4Channel, C: TimerChannel> PwmPin<'d, T, C> {
impl<'d, T: GeneralInstance4Channel, C: TimerChannel, #[cfg(afio)] A> if_afio!(PwmPin<'d, T, C, A>) {
/// 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, if_afio!(impl TimerPin<T, C, A>)>, output_type: OutputType) -> Self {
critical_section::with(|_| {
pin.set_low();
pin.set_as_af(pin.af_num(), AfType::output(output_type, Speed::VeryHigh));
set_as_af!(pin, AfType::output(output_type, Speed::VeryHigh));
});
PwmPin {
_pin: pin.into(),
pin: pin.into(),
phantom: PhantomData,
}
}
/// Create a new PWM pin instance with config.
pub fn new_with_config(pin: Peri<'d, impl TimerPin<T, C>>, pin_config: PwmPinConfig) -> Self {
/// Create a new PWM pin instance with a specific configuration.
pub fn new_with_config(pin: Peri<'d, if_afio!(impl TimerPin<T, C, A>)>, 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),
#[cfg(gpio_v1)]
set_as_af!(pin, AfType::output(pin_config.output_type, pin_config.speed));
#[cfg(gpio_v2)]
set_as_af!(
pin,
AfType::output_pull(pin_config.output_type, pin_config.speed, pin_config.pull)
);
});
PwmPin {
_pin: pin.into(),
pin: pin.into(),
phantom: PhantomData,
}
}
@ -178,12 +179,13 @@ pub struct SimplePwm<'d, T: GeneralInstance4Channel> {
impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
/// Create a new simple PWM driver.
pub fn new(
#[allow(unused)]
pub fn new<#[cfg(afio)] A>(
tim: Peri<'d, T>,
_ch1: Option<PwmPin<'d, T, Ch1>>,
_ch2: Option<PwmPin<'d, T, Ch2>>,
_ch3: Option<PwmPin<'d, T, Ch3>>,
_ch4: Option<PwmPin<'d, T, Ch4>>,
ch1: Option<if_afio!(PwmPin<'d, T, Ch1, A>)>,
ch2: Option<if_afio!(PwmPin<'d, T, Ch2, A>)>,
ch3: Option<if_afio!(PwmPin<'d, T, Ch3, A>)>,
ch4: Option<if_afio!(PwmPin<'d, T, Ch4, A>)>,
freq: Hertz,
counting_mode: CountingMode,
) -> Self {

View File

@ -427,7 +427,7 @@ macro_rules! impl_set_io {
pub fn $method<Role: pin_roles::Role>(&mut self, pin: Peri<'d, impl $trait<T>>) -> IOPinWithRole<$group, Role> {
critical_section::with(|_| {
pin.set_low();
pin.set_as_af(pin.af_num(), AfType::output(Role::output_type(), Speed::VeryHigh));
set_as_af!(pin, AfType::output(Role::output_type(), Speed::VeryHigh));
let tsc_io_pin = trait_to_io_pin!($trait);
let new_pin = Pin {
_pin: pin.into(),

View File

@ -208,10 +208,10 @@ impl<'d> SetConfig for BufferedUartTx<'d> {
impl<'d> BufferedUart<'d> {
/// Create a new bidirectional buffered UART driver
pub fn new<T: Instance>(
pub fn new<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
rx: Peri<'d, impl RxPin<T>>,
tx: Peri<'d, impl TxPin<T>>,
rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
tx_buffer: &'d mut [u8],
rx_buffer: &'d mut [u8],
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@ -231,12 +231,12 @@ impl<'d> BufferedUart<'d> {
}
/// Create a new bidirectional buffered UART driver with request-to-send and clear-to-send pins
pub fn new_with_rtscts<T: Instance>(
pub fn new_with_rtscts<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
rx: Peri<'d, impl RxPin<T>>,
tx: Peri<'d, impl TxPin<T>>,
rts: Peri<'d, impl RtsPin<T>>,
cts: Peri<'d, impl CtsPin<T>>,
rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
rts: Peri<'d, if_afio!(impl RtsPin<T, A>)>,
cts: Peri<'d, if_afio!(impl CtsPin<T, A>)>,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
tx_buffer: &'d mut [u8],
rx_buffer: &'d mut [u8],
@ -256,11 +256,11 @@ impl<'d> BufferedUart<'d> {
}
/// Create a new bidirectional buffered UART driver with only the RTS pin as the DE pin
pub fn new_with_rts_as_de<T: Instance>(
pub fn new_with_rts_as_de<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
rx: Peri<'d, impl RxPin<T>>,
tx: Peri<'d, impl TxPin<T>>,
rts: Peri<'d, impl RtsPin<T>>,
rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
rts: Peri<'d, if_afio!(impl RtsPin<T, A>)>,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
tx_buffer: &'d mut [u8],
rx_buffer: &'d mut [u8],
@ -280,11 +280,11 @@ impl<'d> BufferedUart<'d> {
}
/// Create a new bidirectional buffered UART driver with only the request-to-send pin
pub fn new_with_rts<T: Instance>(
pub fn new_with_rts<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
rx: Peri<'d, impl RxPin<T>>,
tx: Peri<'d, impl TxPin<T>>,
rts: Peri<'d, impl RtsPin<T>>,
rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
rts: Peri<'d, if_afio!(impl RtsPin<T, A>)>,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
tx_buffer: &'d mut [u8],
rx_buffer: &'d mut [u8],
@ -305,11 +305,11 @@ impl<'d> BufferedUart<'d> {
/// Create a new bidirectional buffered UART driver with a driver-enable pin
#[cfg(not(any(usart_v1, usart_v2)))]
pub fn new_with_de<T: Instance>(
pub fn new_with_de<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
rx: Peri<'d, impl RxPin<T>>,
tx: Peri<'d, impl TxPin<T>>,
de: Peri<'d, impl DePin<T>>,
rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
de: Peri<'d, if_afio!(impl DePin<T, A>)>,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
tx_buffer: &'d mut [u8],
rx_buffer: &'d mut [u8],
@ -340,9 +340,9 @@ impl<'d> BufferedUart<'d> {
/// Apart from this, the communication protocol is similar to normal USART mode. Any conflict
/// on the line must be managed by software (for instance by using a centralized arbiter).
#[doc(alias("HDSEL"))]
pub fn new_half_duplex<T: Instance>(
pub fn new_half_duplex<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
tx: Peri<'d, impl TxPin<T>>,
tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
tx_buffer: &'d mut [u8],
rx_buffer: &'d mut [u8],
@ -379,9 +379,9 @@ impl<'d> BufferedUart<'d> {
/// on the line must be managed by software (for instance by using a centralized arbiter).
#[cfg(not(any(usart_v1, usart_v2)))]
#[doc(alias("HDSEL"))]
pub fn new_half_duplex_on_rx<T: Instance>(
pub fn new_half_duplex_on_rx<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
rx: Peri<'d, impl RxPin<T>>,
rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
tx_buffer: &'d mut [u8],
rx_buffer: &'d mut [u8],

View File

@ -429,9 +429,9 @@ impl<'d, M: Mode> SetConfig for UartRx<'d, M> {
impl<'d> UartTx<'d, Async> {
/// Useful if you only want Uart Tx. It saves 1 pin and consumes a little less power.
pub fn new<T: Instance>(
pub fn new<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
tx: Peri<'d, impl TxPin<T>>,
tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
tx_dma: Peri<'d, impl TxDma<T>>,
config: Config,
) -> Result<Self, ConfigError> {
@ -439,10 +439,10 @@ impl<'d> UartTx<'d, Async> {
}
/// Create a new tx-only UART with a clear-to-send pin
pub fn new_with_cts<T: Instance>(
pub fn new_with_cts<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
tx: Peri<'d, impl TxPin<T>>,
cts: Peri<'d, impl CtsPin<T>>,
tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
cts: Peri<'d, if_afio!(impl CtsPin<T, A>)>,
tx_dma: Peri<'d, impl TxDma<T>>,
config: Config,
) -> Result<Self, ConfigError> {
@ -482,19 +482,19 @@ impl<'d> UartTx<'d, Blocking> {
/// Create a new blocking tx-only UART with no hardware flow control.
///
/// Useful if you only want Uart Tx. It saves 1 pin and consumes a little less power.
pub fn new_blocking<T: Instance>(
pub fn new_blocking<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
tx: Peri<'d, impl TxPin<T>>,
tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
config: Config,
) -> Result<Self, ConfigError> {
Self::new_inner(peri, new_pin!(tx, config.tx_af()), None, None, config)
}
/// Create a new blocking tx-only UART with a clear-to-send pin
pub fn new_blocking_with_cts<T: Instance>(
pub fn new_blocking_with_cts<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
tx: Peri<'d, impl TxPin<T>>,
cts: Peri<'d, impl CtsPin<T>>,
tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
cts: Peri<'d, if_afio!(impl CtsPin<T, A>)>,
config: Config,
) -> Result<Self, ConfigError> {
Self::new_inner(
@ -662,10 +662,10 @@ impl<'d> UartRx<'d, Async> {
/// Create a new rx-only UART with no hardware flow control.
///
/// Useful if you only want Uart Rx. It saves 1 pin and consumes a little less power.
pub fn new<T: Instance>(
pub fn new<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
rx: Peri<'d, impl RxPin<T>>,
rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
rx_dma: Peri<'d, impl RxDma<T>>,
config: Config,
) -> Result<Self, ConfigError> {
@ -673,11 +673,11 @@ impl<'d> UartRx<'d, Async> {
}
/// Create a new rx-only UART with a request-to-send pin
pub fn new_with_rts<T: Instance>(
pub fn new_with_rts<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
rx: Peri<'d, impl RxPin<T>>,
rts: Peri<'d, impl RtsPin<T>>,
rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
rts: Peri<'d, if_afio!(impl RtsPin<T, A>)>,
rx_dma: Peri<'d, impl RxDma<T>>,
config: Config,
) -> Result<Self, ConfigError> {
@ -913,19 +913,19 @@ impl<'d> UartRx<'d, Blocking> {
/// Create a new rx-only UART with no hardware flow control.
///
/// Useful if you only want Uart Rx. It saves 1 pin and consumes a little less power.
pub fn new_blocking<T: Instance>(
pub fn new_blocking<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
rx: Peri<'d, impl RxPin<T>>,
rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
config: Config,
) -> Result<Self, ConfigError> {
Self::new_inner(peri, new_pin!(rx, config.rx_af()), None, None, config)
}
/// Create a new rx-only UART with a request-to-send pin
pub fn new_blocking_with_rts<T: Instance>(
pub fn new_blocking_with_rts<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
rx: Peri<'d, impl RxPin<T>>,
rts: Peri<'d, impl RtsPin<T>>,
rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
rts: Peri<'d, if_afio!(impl RtsPin<T, A>)>,
config: Config,
) -> Result<Self, ConfigError> {
Self::new_inner(
@ -1109,10 +1109,10 @@ fn drop_tx_rx(info: &Info, state: &State) {
impl<'d> Uart<'d, Async> {
/// Create a new bidirectional UART
pub fn new<T: Instance>(
pub fn new<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
rx: Peri<'d, impl RxPin<T>>,
tx: Peri<'d, impl TxPin<T>>,
rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
tx_dma: Peri<'d, impl TxDma<T>>,
rx_dma: Peri<'d, impl RxDma<T>>,
@ -1132,13 +1132,13 @@ impl<'d> Uart<'d, Async> {
}
/// Create a new bidirectional UART with request-to-send and clear-to-send pins
pub fn new_with_rtscts<T: Instance>(
pub fn new_with_rtscts<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
rx: Peri<'d, impl RxPin<T>>,
tx: Peri<'d, impl TxPin<T>>,
rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
rts: Peri<'d, impl RtsPin<T>>,
cts: Peri<'d, impl CtsPin<T>>,
rts: Peri<'d, if_afio!(impl RtsPin<T, A>)>,
cts: Peri<'d, if_afio!(impl CtsPin<T, A>)>,
tx_dma: Peri<'d, impl TxDma<T>>,
rx_dma: Peri<'d, impl RxDma<T>>,
config: Config,
@ -1158,12 +1158,12 @@ impl<'d> Uart<'d, Async> {
#[cfg(not(any(usart_v1, usart_v2)))]
/// Create a new bidirectional UART with a driver-enable pin
pub fn new_with_de<T: Instance>(
pub fn new_with_de<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
rx: Peri<'d, impl RxPin<T>>,
tx: Peri<'d, impl TxPin<T>>,
rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
de: Peri<'d, impl DePin<T>>,
de: Peri<'d, if_afio!(impl DePin<T, A>)>,
tx_dma: Peri<'d, impl TxDma<T>>,
rx_dma: Peri<'d, impl RxDma<T>>,
config: Config,
@ -1193,9 +1193,9 @@ impl<'d> Uart<'d, Async> {
/// Apart from this, the communication protocol is similar to normal USART mode. Any conflict
/// on the line must be managed by software (for instance by using a centralized arbiter).
#[doc(alias("HDSEL"))]
pub fn new_half_duplex<T: Instance>(
pub fn new_half_duplex<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
tx: Peri<'d, impl TxPin<T>>,
tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
tx_dma: Peri<'d, impl TxDma<T>>,
rx_dma: Peri<'d, impl RxDma<T>>,
@ -1232,9 +1232,9 @@ impl<'d> Uart<'d, Async> {
/// on the line must be managed by software (for instance by using a centralized arbiter).
#[cfg(not(any(usart_v1, usart_v2)))]
#[doc(alias("HDSEL"))]
pub fn new_half_duplex_on_rx<T: Instance>(
pub fn new_half_duplex_on_rx<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
rx: Peri<'d, impl RxPin<T>>,
rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
tx_dma: Peri<'d, impl TxDma<T>>,
rx_dma: Peri<'d, impl RxDma<T>>,
@ -1280,10 +1280,10 @@ impl<'d> Uart<'d, Async> {
impl<'d> Uart<'d, Blocking> {
/// Create a new blocking bidirectional UART.
pub fn new_blocking<T: Instance>(
pub fn new_blocking<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
rx: Peri<'d, impl RxPin<T>>,
tx: Peri<'d, impl TxPin<T>>,
rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
config: Config,
) -> Result<Self, ConfigError> {
Self::new_inner(
@ -1300,12 +1300,12 @@ impl<'d> Uart<'d, Blocking> {
}
/// Create a new bidirectional UART with request-to-send and clear-to-send pins
pub fn new_blocking_with_rtscts<T: Instance>(
pub fn new_blocking_with_rtscts<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
rx: Peri<'d, impl RxPin<T>>,
tx: Peri<'d, impl TxPin<T>>,
rts: Peri<'d, impl RtsPin<T>>,
cts: Peri<'d, impl CtsPin<T>>,
rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
rts: Peri<'d, if_afio!(impl RtsPin<T, A>)>,
cts: Peri<'d, if_afio!(impl CtsPin<T, A>)>,
config: Config,
) -> Result<Self, ConfigError> {
Self::new_inner(
@ -1323,11 +1323,11 @@ impl<'d> Uart<'d, Blocking> {
#[cfg(not(any(usart_v1, usart_v2)))]
/// Create a new bidirectional UART with a driver-enable pin
pub fn new_blocking_with_de<T: Instance>(
pub fn new_blocking_with_de<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
rx: Peri<'d, impl RxPin<T>>,
tx: Peri<'d, impl TxPin<T>>,
de: Peri<'d, impl DePin<T>>,
rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
de: Peri<'d, if_afio!(impl DePin<T, A>)>,
config: Config,
) -> Result<Self, ConfigError> {
Self::new_inner(
@ -1354,9 +1354,9 @@ impl<'d> Uart<'d, Blocking> {
/// Apart from this, the communication protocol is similar to normal USART mode. Any conflict
/// on the line must be managed by software (for instance by using a centralized arbiter).
#[doc(alias("HDSEL"))]
pub fn new_blocking_half_duplex<T: Instance>(
pub fn new_blocking_half_duplex<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
tx: Peri<'d, impl TxPin<T>>,
tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
mut config: Config,
readback: HalfDuplexReadback,
) -> Result<Self, ConfigError> {
@ -1390,9 +1390,9 @@ impl<'d> Uart<'d, Blocking> {
/// on the line must be managed by software (for instance by using a centralized arbiter).
#[cfg(not(any(usart_v1, usart_v2)))]
#[doc(alias("HDSEL"))]
pub fn new_blocking_half_duplex_on_rx<T: Instance>(
pub fn new_blocking_half_duplex_on_rx<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
rx: Peri<'d, impl RxPin<T>>,
rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
mut config: Config,
readback: HalfDuplexReadback,
) -> Result<Self, ConfigError> {
@ -2055,12 +2055,12 @@ pub trait Instance: SealedInstance + PeripheralType + 'static + Send {
type Interrupt: interrupt::typelevel::Interrupt;
}
pin_trait!(RxPin, Instance);
pin_trait!(TxPin, Instance);
pin_trait!(CtsPin, Instance);
pin_trait!(RtsPin, Instance);
pin_trait!(CkPin, Instance);
pin_trait!(DePin, Instance);
pin_trait!(RxPin, Instance, @A);
pin_trait!(TxPin, Instance, @A);
pin_trait!(CtsPin, Instance, @A);
pin_trait!(RtsPin, Instance, @A);
pin_trait!(CkPin, Instance, @A);
pin_trait!(DePin, Instance, @A);
dma_trait!(TxDma, Instance);
dma_trait!(RxDma, Instance);

View File

@ -34,7 +34,7 @@ macro_rules! config_ulpi_pins {
($($pin:ident),*) => {
critical_section::with(|_| {
$(
$pin.set_as_af($pin.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
set_as_af!($pin, AfType::output(OutputType::PushPull, Speed::VeryHigh));
)*
})
};
@ -68,8 +68,8 @@ impl<'d, T: Instance> Driver<'d, T> {
ep_out_buffer: &'d mut [u8],
config: Config,
) -> Self {
dp.set_as_af(dp.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
dm.set_as_af(dm.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
set_as_af!(dp, AfType::output(OutputType::PushPull, Speed::VeryHigh));
set_as_af!(dm, AfType::output(OutputType::PushPull, Speed::VeryHigh));
let regs = T::regs();
@ -107,8 +107,8 @@ impl<'d, T: Instance> Driver<'d, T> {
// For STM32U5 High speed pins need to be left in analog mode
#[cfg(not(any(all(stm32u5, peri_usb_otg_hs), all(stm32wba, peri_usb_otg_hs))))]
{
_dp.set_as_af(_dp.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
_dm.set_as_af(_dm.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
set_as_af!(_dp, AfType::output(OutputType::PushPull, Speed::VeryHigh));
set_as_af!(_dm, AfType::output(OutputType::PushPull, Speed::VeryHigh));
}
let instance = OtgInstance {

View File

@ -298,7 +298,7 @@ impl<'d, T: Instance> Driver<'d, T> {
) -> Self {
{
use crate::gpio::{AfType, OutputType, Speed};
sof.set_as_af(sof.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
set_as_af!(sof, AfType::output(OutputType::PushPull, Speed::VeryHigh));
}
Self::new(_usb, _irq, dp, dm)
@ -329,8 +329,8 @@ impl<'d, T: Instance> Driver<'d, T> {
#[cfg(not(stm32l1))]
{
use crate::gpio::{AfType, OutputType, Speed};
dp.set_as_af(dp.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
dm.set_as_af(dm.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
set_as_af!(dp, AfType::output(OutputType::PushPull, Speed::VeryHigh));
set_as_af!(dm, AfType::output(OutputType::PushPull, Speed::VeryHigh));
}
#[cfg(stm32l1)]
let _ = (dp, dm); // suppress "unused" warnings.

View File

@ -3,7 +3,7 @@
use defmt::*;
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::timer::input_capture::{CapturePin, InputCapture};
use embassy_stm32::timer::{self, Channel};
@ -40,7 +40,8 @@ async fn main(spawner: Spawner) {
spawner.spawn(unwrap!(blinky(p.PC13)));
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 {
info!("wait for rising edge");

View File

@ -3,7 +3,7 @@
use defmt::*;
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::timer::pwm_input::PwmInput;
use embassy_stm32::{bind_interrupts, peripherals, timer, Peri};
@ -38,7 +38,7 @@ async fn main(spawner: Spawner) {
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();
loop {

View File

@ -9,7 +9,9 @@ publish = false
[features]
stm32c031c6 = ["embassy-stm32/stm32c031c6", "cm0", "not-gpdma"]
stm32c071rb = ["embassy-stm32/stm32c071rb", "cm0", "not-gpdma"]
stm32f103c8 = ["embassy-stm32/stm32f103c8", "spi-v1", "not-gpdma"]
stm32f100rd = ["embassy-stm32/stm32f100rd", "spi-v1", "not-gpdma", "afio", "afio-value-line"]
stm32f103c8 = ["embassy-stm32/stm32f103c8", "spi-v1", "not-gpdma", "afio"]
stm32f107vc = ["embassy-stm32/stm32f107vc", "spi-v1", "not-gpdma", "afio", "afio-connectivity-line"]
stm32f207zg = ["embassy-stm32/stm32f207zg", "spi-v1", "chrono", "not-gpdma", "eth", "rng"]
stm32f303ze = ["embassy-stm32/stm32f303ze", "chrono", "not-gpdma"]
stm32f429zi = ["embassy-stm32/stm32f429zi", "spi-v1", "chrono", "eth", "stop", "can", "not-gpdma", "dac", "rng"]
@ -59,6 +61,9 @@ cordic = ["dep:num-traits"]
dual-bank = ["embassy-stm32/dual-bank"]
single-bank = ["embassy-stm32/single-bank"]
eeprom = []
afio = []
afio-connectivity-line = []
afio-value-line = []
cm0 = ["portable-atomic/unsafe-assume-single-core"]
@ -98,6 +103,11 @@ num-traits = { version="0.2", default-features = false,features = ["libm"], opti
# BEGIN TESTS
# Generated by gen_test.py. DO NOT EDIT.
[[bin]]
name = "afio"
path = "src/bin/afio.rs"
required-features = [ "afio",]
[[bin]]
name = "can"
path = "src/bin/can.rs"

1156
tests/stm32/src/bin/afio.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@ -103,7 +103,7 @@ define_peris!(
SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH3, SPI_RX_DMA = DMA1_CH2,
@irq UART = {USART1 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART1>;},
);
#[cfg(feature = "stm32f103c8")]
#[cfg(any(feature = "stm32f100rd", feature = "stm32f103c8", feature = "stm32f107vc"))]
define_peris!(
UART = USART1, UART_TX = PA9, UART_RX = PA10, UART_TX_DMA = DMA1_CH4, UART_RX_DMA = DMA1_CH5,
SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH3, SPI_RX_DMA = DMA1_CH2,