aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2025-09-05 22:45:57 +0000
committerGitHub <[email protected]>2025-09-05 22:45:57 +0000
commit25e0ebf5206fa2e2906f5826c0b1587739f628d8 (patch)
tree736901f367d2704d9596d392d2ef67d4d4c81b3f
parent24902b9bfb927ef539215c9d657bc39233180360 (diff)
parent23d5c7efd99e7422c63c6e12143856257d1ee651 (diff)
Merge pull request #4430 from fwolter/add-f1-remap
Add STM32F1 AFIO remap
-rw-r--r--.vscode/settings.json2
-rwxr-xr-xci.sh6
-rw-r--r--embassy-stm32/CHANGELOG.md1
-rw-r--r--embassy-stm32/build.rs76
-rw-r--r--embassy-stm32/src/can/bxcan/mod.rs18
-rw-r--r--embassy-stm32/src/can/fdcan.rs4
-rw-r--r--embassy-stm32/src/dcmi.rs2
-rw-r--r--embassy-stm32/src/dsihost.rs2
-rw-r--r--embassy-stm32/src/eth/mod.rs32
-rw-r--r--embassy-stm32/src/eth/v1/mod.rs56
-rw-r--r--embassy-stm32/src/eth/v2/mod.rs2
-rw-r--r--embassy-stm32/src/fmc.rs2
-rw-r--r--embassy-stm32/src/gpio.rs31
-rw-r--r--embassy-stm32/src/hrtim/mod.rs10
-rw-r--r--embassy-stm32/src/i2c/mod.rs16
-rw-r--r--embassy-stm32/src/i2s.rs50
-rw-r--r--embassy-stm32/src/lptim/pwm.rs17
-rw-r--r--embassy-stm32/src/macros.rs120
-rw-r--r--embassy-stm32/src/rcc/mco.rs2
-rw-r--r--embassy-stm32/src/sai/mod.rs10
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs76
-rw-r--r--embassy-stm32/src/spdifrx/mod.rs2
-rw-r--r--embassy-stm32/src/spi/mod.rs62
-rw-r--r--embassy-stm32/src/timer/complementary_pwm.rs39
-rw-r--r--embassy-stm32/src/timer/input_capture.rs26
-rw-r--r--embassy-stm32/src/timer/mod.rs12
-rw-r--r--embassy-stm32/src/timer/one_pulse.rs70
-rw-r--r--embassy-stm32/src/timer/pwm_input.rs18
-rw-r--r--embassy-stm32/src/timer/qei.rs24
-rw-r--r--embassy-stm32/src/timer/simple_pwm.rs44
-rw-r--r--embassy-stm32/src/tsc/pin_groups.rs2
-rw-r--r--embassy-stm32/src/usart/buffered.rs48
-rw-r--r--embassy-stm32/src/usart/mod.rs116
-rw-r--r--embassy-stm32/src/usb/otg.rs10
-rw-r--r--embassy-stm32/src/usb/usb.rs6
-rw-r--r--examples/stm32f1/src/bin/input_capture.rs5
-rw-r--r--examples/stm32f1/src/bin/pwm_input.rs4
-rw-r--r--tests/stm32/Cargo.toml12
-rw-r--r--tests/stm32/src/bin/afio.rs1156
-rw-r--r--tests/stm32/src/common.rs2
40 files changed, 1762 insertions, 431 deletions
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 6edd9312a..c504f3ccd 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -17,7 +17,7 @@
17 //"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf", 17 //"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf",
18 "rust-analyzer.cargo.features": [ 18 "rust-analyzer.cargo.features": [
19 // Comment out these features when working on the examples. Most example crates do not have any cargo features. 19 // Comment out these features when working on the examples. Most example crates do not have any cargo features.
20 "stm32f446re", 20 "stm32f107rb",
21 "time-driver-any", 21 "time-driver-any",
22 "unstable-pac", 22 "unstable-pac",
23 "exti", 23 "exti",
diff --git a/ci.sh b/ci.sh
index e1197f397..50fb3e13d 100755
--- a/ci.sh
+++ b/ci.sh
@@ -311,7 +311,9 @@ cargo batch \
311 --- build --release --manifest-path examples/boot/bootloader/stm32wba-dfu/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-stm32/stm32wba65ri,verify \ 311 --- build --release --manifest-path examples/boot/bootloader/stm32wba-dfu/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-stm32/stm32wba65ri,verify \
312 --- build --release --manifest-path examples/boot/bootloader/stm32-dual-bank/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32h743zi \ 312 --- build --release --manifest-path examples/boot/bootloader/stm32-dual-bank/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32h743zi \
313 --- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --artifact-dir out/examples/wasm \ 313 --- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --artifact-dir out/examples/wasm \
314 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f100rd --artifact-dir out/tests/stm32f100rd \
314 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103c8 --artifact-dir out/tests/stm32f103c8 \ 315 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103c8 --artifact-dir out/tests/stm32f103c8 \
316 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f107vc --artifact-dir out/tests/stm32f107vc \
315 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi --artifact-dir out/tests/stm32f429zi \ 317 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi --artifact-dir out/tests/stm32f429zi \
316 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f446re --artifact-dir out/tests/stm32f446re \ 318 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f446re --artifact-dir out/tests/stm32f446re \
317 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g491re --artifact-dir out/tests/stm32g491re \ 319 --- 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
398rm out/tests/rpi-pico/pwm 400rm out/tests/rpi-pico/pwm
399rm out/tests/rpi-pico/cyw43-perf 401rm out/tests/rpi-pico/cyw43-perf
400 402
401# tests are implemented but the HIL test farm doesn't actually have this board yet 403# tests are implemented but the HIL test farm doesn't actually have these boards, yet
402rm -rf out/tests/stm32c071rb 404rm -rf out/tests/stm32c071rb
405rm -rf out/tests/stm32f100rd
406rm -rf out/tests/stm32f107vc
403 407
404if [[ -z "${TELEPROBE_TOKEN-}" ]]; then 408if [[ -z "${TELEPROBE_TOKEN-}" ]]; then
405 echo No teleprobe token found, skipping running HIL tests 409 echo No teleprobe token found, skipping running HIL tests
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md
index 5635481fa..ba565f663 100644
--- a/embassy-stm32/CHANGELOG.md
+++ b/embassy-stm32/CHANGELOG.md
@@ -30,6 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
30- fix: Fix stm32h7rs init when using external flash via XSPI 30- fix: Fix stm32h7rs init when using external flash via XSPI
31- feat: Add Adc::new_with_clock() to configure analog clock 31- feat: Add Adc::new_with_clock() to configure analog clock
32- feat: Add GPDMA linked-list + ringbuffer support ([#3923](https://github.com/embassy-rs/embassy/pull/3923)) 32- feat: Add GPDMA linked-list + ringbuffer support ([#3923](https://github.com/embassy-rs/embassy/pull/3923))
33- feat: Added support for STM32F1 peripheral pin remapping (AFIO) ([#4430](https://github.com/embassy-rs/embassy/pull/4430))
33 34
34## 0.3.0 - 2025-08-12 35## 0.3.0 - 2025-08-12
35 36
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index b731012c6..b5f1261fe 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -1391,9 +1391,53 @@ fn main() {
1391 }) 1391 })
1392 } 1392 }
1393 1393
1394 g.extend(quote! { 1394 let pin_trait_impl = if let Some(afio) = &p.afio {
1395 pin_trait_impl!(#tr, #peri, #pin_name, #af); 1395 let values = afio
1396 }) 1396 .values
1397 .iter()
1398 .filter(|v| v.pins.contains(&pin.pin))
1399 .map(|v| v.value)
1400 .collect::<Vec<_>>();
1401
1402 if values.is_empty() {
1403 None
1404 } else {
1405 let reg = format_ident!("{}", afio.register.to_lowercase());
1406 let setter = format_ident!("set_{}", afio.field.to_lowercase());
1407 let type_and_values = if is_bool_field("AFIO", afio.register, afio.field) {
1408 let values = values.iter().map(|&v| v > 0);
1409 quote!(AfioRemapBool, [#(#values),*])
1410 } else {
1411 quote!(AfioRemap, [#(#values),*])
1412 };
1413
1414 Some(quote! {
1415 pin_trait_afio_impl!(#tr, #peri, #pin_name, {#reg, #setter, #type_and_values});
1416 })
1417 }
1418 } else {
1419 let peripherals_with_afio = [
1420 "CAN",
1421 "CEC",
1422 "ETH",
1423 "I2C",
1424 "SPI",
1425 "SUBGHZSPI",
1426 "USART",
1427 "UART",
1428 "LPUART",
1429 "TIM",
1430 ];
1431 let not_applicable = if peripherals_with_afio.iter().any(|&x| p.name.starts_with(x)) {
1432 quote!(, crate::gpio::AfioRemapNotApplicable)
1433 } else {
1434 quote!()
1435 };
1436
1437 Some(quote!(pin_trait_impl!(#tr, #peri, #pin_name, #af #not_applicable);))
1438 };
1439
1440 g.extend(pin_trait_impl);
1397 } 1441 }
1398 1442
1399 // ADC is special 1443 // ADC is special
@@ -1588,17 +1632,7 @@ fn main() {
1588 let register = format_ident!("{}", remap_info.register.to_lowercase()); 1632 let register = format_ident!("{}", remap_info.register.to_lowercase());
1589 let setter = format_ident!("set_{}", remap_info.field.to_lowercase()); 1633 let setter = format_ident!("set_{}", remap_info.field.to_lowercase());
1590 1634
1591 let field_metadata = METADATA 1635 let value = if is_bool_field("SYSCFG", &remap_info.register, &remap_info.field) {
1592 .peripherals
1593 .iter()
1594 .filter(|p| p.name == "SYSCFG")
1595 .flat_map(|p| p.registers.as_ref().unwrap().ir.fieldsets.iter())
1596 .filter(|f| f.name.eq_ignore_ascii_case(remap_info.register))
1597 .flat_map(|f| f.fields.iter())
1598 .find(|f| f.name.eq_ignore_ascii_case(remap_info.field))
1599 .unwrap();
1600
1601 let value = if field_metadata.bit_size == 1 {
1602 let bool_value = format_ident!("{}", remap_info.value > 0); 1636 let bool_value = format_ident!("{}", remap_info.value > 0);
1603 quote!(#bool_value) 1637 quote!(#bool_value)
1604 } else { 1638 } else {
@@ -2300,3 +2334,17 @@ fn gcd(a: u32, b: u32) -> u32 {
2300 } 2334 }
2301 gcd(b, a % b) 2335 gcd(b, a % b)
2302} 2336}
2337
2338fn is_bool_field(peripheral: &str, register: &str, field: &str) -> bool {
2339 let field_metadata = METADATA
2340 .peripherals
2341 .iter()
2342 .filter(|p| p.name == peripheral)
2343 .flat_map(|p| p.registers.as_ref().unwrap().ir.fieldsets.iter())
2344 .filter(|f| f.name.eq_ignore_ascii_case(register))
2345 .flat_map(|f| f.fields.iter())
2346 .find(|f| f.name.eq_ignore_ascii_case(field))
2347 .unwrap();
2348
2349 field_metadata.bit_size == 1
2350}
diff --git a/embassy-stm32/src/can/bxcan/mod.rs b/embassy-stm32/src/can/bxcan/mod.rs
index 4c0795a2a..8eb188560 100644
--- a/embassy-stm32/src/can/bxcan/mod.rs
+++ b/embassy-stm32/src/can/bxcan/mod.rs
@@ -181,10 +181,10 @@ pub enum TryWriteError {
181impl<'d> Can<'d> { 181impl<'d> Can<'d> {
182 /// Creates a new Bxcan instance, keeping the peripheral in sleep mode. 182 /// Creates a new Bxcan instance, keeping the peripheral in sleep mode.
183 /// You must call [Can::enable_non_blocking] to use the peripheral. 183 /// You must call [Can::enable_non_blocking] to use the peripheral.
184 pub fn new<T: Instance>( 184 pub fn new<T: Instance, #[cfg(afio)] A>(
185 _peri: Peri<'d, T>, 185 _peri: Peri<'d, T>,
186 rx: Peri<'d, impl RxPin<T>>, 186 rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
187 tx: Peri<'d, impl TxPin<T>>, 187 tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
188 _irqs: impl interrupt::typelevel::Binding<T::TXInterrupt, TxInterruptHandler<T>> 188 _irqs: impl interrupt::typelevel::Binding<T::TXInterrupt, TxInterruptHandler<T>>
189 + interrupt::typelevel::Binding<T::RX0Interrupt, Rx0InterruptHandler<T>> 189 + interrupt::typelevel::Binding<T::RX0Interrupt, Rx0InterruptHandler<T>>
190 + interrupt::typelevel::Binding<T::RX1Interrupt, Rx1InterruptHandler<T>> 190 + interrupt::typelevel::Binding<T::RX1Interrupt, Rx1InterruptHandler<T>>
@@ -194,8 +194,8 @@ impl<'d> Can<'d> {
194 let info = T::info(); 194 let info = T::info();
195 let regs = &T::info().regs; 195 let regs = &T::info().regs;
196 196
197 rx.set_as_af(rx.af_num(), AfType::input(Pull::None)); 197 set_as_af!(rx, AfType::input(Pull::None));
198 tx.set_as_af(tx.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); 198 set_as_af!(tx, AfType::output(OutputType::PushPull, Speed::VeryHigh));
199 199
200 rcc::enable_and_reset::<T>(); 200 rcc::enable_and_reset::<T>();
201 201
@@ -229,8 +229,8 @@ impl<'d> Can<'d> {
229 info.sce_interrupt.enable(); 229 info.sce_interrupt.enable();
230 } 230 }
231 231
232 rx.set_as_af(rx.af_num(), AfType::input(Pull::None)); 232 set_as_af!(rx, AfType::input(Pull::None));
233 tx.set_as_af(tx.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); 233 set_as_af!(tx, AfType::output(OutputType::PushPull, Speed::VeryHigh));
234 234
235 Registers(T::regs()).leave_init_mode(); 235 Registers(T::regs()).leave_init_mode();
236 236
@@ -1218,8 +1218,8 @@ foreach_peripheral!(
1218 }; 1218 };
1219); 1219);
1220 1220
1221pin_trait!(RxPin, Instance); 1221pin_trait!(RxPin, Instance, @A);
1222pin_trait!(TxPin, Instance); 1222pin_trait!(TxPin, Instance, @A);
1223 1223
1224trait Index { 1224trait Index {
1225 fn index(&self) -> usize; 1225 fn index(&self) -> usize;
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs
index 99e40ba62..d8f71e03e 100644
--- a/embassy-stm32/src/can/fdcan.rs
+++ b/embassy-stm32/src/can/fdcan.rs
@@ -185,8 +185,8 @@ impl<'d> CanConfigurator<'d> {
185 + interrupt::typelevel::Binding<T::IT1Interrupt, IT1InterruptHandler<T>> 185 + interrupt::typelevel::Binding<T::IT1Interrupt, IT1InterruptHandler<T>>
186 + 'd, 186 + 'd,
187 ) -> CanConfigurator<'d> { 187 ) -> CanConfigurator<'d> {
188 rx.set_as_af(rx.af_num(), AfType::input(Pull::None)); 188 set_as_af!(rx, AfType::input(Pull::None));
189 tx.set_as_af(tx.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); 189 set_as_af!(tx, AfType::output(OutputType::PushPull, Speed::VeryHigh));
190 190
191 rcc::enable_and_reset::<T>(); 191 rcc::enable_and_reset::<T>();
192 192
diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs
index d05faee21..bd03f1e00 100644
--- a/embassy-stm32/src/dcmi.rs
+++ b/embassy-stm32/src/dcmi.rs
@@ -108,7 +108,7 @@ macro_rules! config_pins {
108 ($($pin:ident),*) => { 108 ($($pin:ident),*) => {
109 critical_section::with(|_| { 109 critical_section::with(|_| {
110 $( 110 $(
111 $pin.set_as_af($pin.af_num(), AfType::input(Pull::None)); 111 set_as_af!($pin, AfType::input(Pull::None));
112 )* 112 )*
113 }) 113 })
114 }; 114 };
diff --git a/embassy-stm32/src/dsihost.rs b/embassy-stm32/src/dsihost.rs
index e97ccd9d0..deda956af 100644
--- a/embassy-stm32/src/dsihost.rs
+++ b/embassy-stm32/src/dsihost.rs
@@ -78,7 +78,7 @@ impl<'d, T: Instance> DsiHost<'d, T> {
78 rcc::enable_and_reset::<T>(); 78 rcc::enable_and_reset::<T>();
79 79
80 // Set Tearing Enable pin according to CubeMx example 80 // Set Tearing Enable pin according to CubeMx example
81 te.set_as_af(te.af_num(), AfType::output(OutputType::PushPull, Speed::Low)); 81 set_as_af!(te, AfType::output(OutputType::PushPull, Speed::Low));
82 /* 82 /*
83 T::regs().wcr().modify(|w| { 83 T::regs().wcr().modify(|w| {
84 w.set_dsien(true); 84 w.set_dsien(true);
diff --git a/embassy-stm32/src/eth/mod.rs b/embassy-stm32/src/eth/mod.rs
index 97d7b4347..10b3a0517 100644
--- a/embassy-stm32/src/eth/mod.rs
+++ b/embassy-stm32/src/eth/mod.rs
@@ -209,19 +209,19 @@ impl SealedInstance for crate::peripherals::ETH {
209} 209}
210impl Instance for crate::peripherals::ETH {} 210impl Instance for crate::peripherals::ETH {}
211 211
212pin_trait!(RXClkPin, Instance); 212pin_trait!(RXClkPin, Instance, @A);
213pin_trait!(TXClkPin, Instance); 213pin_trait!(TXClkPin, Instance, @A);
214pin_trait!(RefClkPin, Instance); 214pin_trait!(RefClkPin, Instance, @A);
215pin_trait!(MDIOPin, Instance); 215pin_trait!(MDIOPin, Instance, @A);
216pin_trait!(MDCPin, Instance); 216pin_trait!(MDCPin, Instance, @A);
217pin_trait!(RXDVPin, Instance); 217pin_trait!(RXDVPin, Instance, @A);
218pin_trait!(CRSPin, Instance); 218pin_trait!(CRSPin, Instance, @A);
219pin_trait!(RXD0Pin, Instance); 219pin_trait!(RXD0Pin, Instance, @A);
220pin_trait!(RXD1Pin, Instance); 220pin_trait!(RXD1Pin, Instance, @A);
221pin_trait!(RXD2Pin, Instance); 221pin_trait!(RXD2Pin, Instance, @A);
222pin_trait!(RXD3Pin, Instance); 222pin_trait!(RXD3Pin, Instance, @A);
223pin_trait!(TXD0Pin, Instance); 223pin_trait!(TXD0Pin, Instance, @A);
224pin_trait!(TXD1Pin, Instance); 224pin_trait!(TXD1Pin, Instance, @A);
225pin_trait!(TXD2Pin, Instance); 225pin_trait!(TXD2Pin, Instance, @A);
226pin_trait!(TXD3Pin, Instance); 226pin_trait!(TXD3Pin, Instance, @A);
227pin_trait!(TXEnPin, Instance); 227pin_trait!(TXEnPin, Instance, @A);
diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs
index b9746231f..5be1c9739 100644
--- a/embassy-stm32/src/eth/v1/mod.rs
+++ b/embassy-stm32/src/eth/v1/mod.rs
@@ -69,7 +69,7 @@ macro_rules! config_in_pins {
69 critical_section::with(|_| { 69 critical_section::with(|_| {
70 $( 70 $(
71 // TODO properly create a set_as_input function 71 // TODO properly create a set_as_input function
72 $pin.set_as_af($pin.af_num(), AfType::input(Pull::None)); 72 set_as_af!($pin, AfType::input(Pull::None));
73 )* 73 )*
74 }) 74 })
75 } 75 }
@@ -80,7 +80,7 @@ macro_rules! config_af_pins {
80 ($($pin:ident),*) => { 80 ($($pin:ident),*) => {
81 critical_section::with(|_| { 81 critical_section::with(|_| {
82 $( 82 $(
83 $pin.set_as_af($pin.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); 83 set_as_af!($pin, AfType::output(OutputType::PushPull, Speed::VeryHigh));
84 )* 84 )*
85 }) 85 })
86 }; 86 };
@@ -91,7 +91,7 @@ macro_rules! config_pins {
91 ($($pin:ident),*) => { 91 ($($pin:ident),*) => {
92 critical_section::with(|_| { 92 critical_section::with(|_| {
93 $( 93 $(
94 $pin.set_as_af($pin.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); 94 set_as_af!($pin, AfType::output(OutputType::PushPull, Speed::VeryHigh));
95 )* 95 )*
96 }) 96 })
97 }; 97 };
@@ -99,19 +99,19 @@ macro_rules! config_pins {
99 99
100impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { 100impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
101 /// safety: the returned instance is not leak-safe 101 /// safety: the returned instance is not leak-safe
102 pub fn new<const TX: usize, const RX: usize>( 102 pub fn new<const TX: usize, const RX: usize, #[cfg(afio)] A>(
103 queue: &'d mut PacketQueue<TX, RX>, 103 queue: &'d mut PacketQueue<TX, RX>,
104 peri: Peri<'d, T>, 104 peri: Peri<'d, T>,
105 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd, 105 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
106 ref_clk: Peri<'d, impl RefClkPin<T>>, 106 ref_clk: Peri<'d, if_afio!(impl RefClkPin<T, A>)>,
107 mdio: Peri<'d, impl MDIOPin<T>>, 107 mdio: Peri<'d, if_afio!(impl MDIOPin<T, A>)>,
108 mdc: Peri<'d, impl MDCPin<T>>, 108 mdc: Peri<'d, if_afio!(impl MDCPin<T, A>)>,
109 crs: Peri<'d, impl CRSPin<T>>, 109 crs: Peri<'d, if_afio!(impl CRSPin<T, A>)>,
110 rx_d0: Peri<'d, impl RXD0Pin<T>>, 110 rx_d0: Peri<'d, if_afio!(impl RXD0Pin<T, A>)>,
111 rx_d1: Peri<'d, impl RXD1Pin<T>>, 111 rx_d1: Peri<'d, if_afio!(impl RXD1Pin<T, A>)>,
112 tx_d0: Peri<'d, impl TXD0Pin<T>>, 112 tx_d0: Peri<'d, if_afio!(impl TXD0Pin<T, A>)>,
113 tx_d1: Peri<'d, impl TXD1Pin<T>>, 113 tx_d1: Peri<'d, if_afio!(impl TXD1Pin<T, A>)>,
114 tx_en: Peri<'d, impl TXEnPin<T>>, 114 tx_en: Peri<'d, if_afio!(impl TXEnPin<T, A>)>,
115 phy: P, 115 phy: P,
116 mac_addr: [u8; 6], 116 mac_addr: [u8; 6],
117 ) -> Self { 117 ) -> Self {
@@ -289,24 +289,24 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
289 } 289 }
290 290
291 /// Create a new MII ethernet driver using 14 pins. 291 /// Create a new MII ethernet driver using 14 pins.
292 pub fn new_mii<const TX: usize, const RX: usize>( 292 pub fn new_mii<const TX: usize, const RX: usize, #[cfg(afio)] A>(
293 queue: &'d mut PacketQueue<TX, RX>, 293 queue: &'d mut PacketQueue<TX, RX>,
294 peri: Peri<'d, T>, 294 peri: Peri<'d, T>,
295 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd, 295 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
296 rx_clk: Peri<'d, impl RXClkPin<T>>, 296 rx_clk: Peri<'d, if_afio!(impl RXClkPin<T, A>)>,
297 tx_clk: Peri<'d, impl TXClkPin<T>>, 297 tx_clk: Peri<'d, if_afio!(impl TXClkPin<T, A>)>,
298 mdio: Peri<'d, impl MDIOPin<T>>, 298 mdio: Peri<'d, if_afio!(impl MDIOPin<T, A>)>,
299 mdc: Peri<'d, impl MDCPin<T>>, 299 mdc: Peri<'d, if_afio!(impl MDCPin<T, A>)>,
300 rxdv: Peri<'d, impl RXDVPin<T>>, 300 rxdv: Peri<'d, if_afio!(impl RXDVPin<T, A>)>,
301 rx_d0: Peri<'d, impl RXD0Pin<T>>, 301 rx_d0: Peri<'d, if_afio!(impl RXD0Pin<T, A>)>,
302 rx_d1: Peri<'d, impl RXD1Pin<T>>, 302 rx_d1: Peri<'d, if_afio!(impl RXD1Pin<T, A>)>,
303 rx_d2: Peri<'d, impl RXD2Pin<T>>, 303 rx_d2: Peri<'d, if_afio!(impl RXD2Pin<T, A>)>,
304 rx_d3: Peri<'d, impl RXD3Pin<T>>, 304 rx_d3: Peri<'d, if_afio!(impl RXD3Pin<T, A>)>,
305 tx_d0: Peri<'d, impl TXD0Pin<T>>, 305 tx_d0: Peri<'d, if_afio!(impl TXD0Pin<T, A>)>,
306 tx_d1: Peri<'d, impl TXD1Pin<T>>, 306 tx_d1: Peri<'d, if_afio!(impl TXD1Pin<T, A>)>,
307 tx_d2: Peri<'d, impl TXD2Pin<T>>, 307 tx_d2: Peri<'d, if_afio!(impl TXD2Pin<T, A>)>,
308 tx_d3: Peri<'d, impl TXD3Pin<T>>, 308 tx_d3: Peri<'d, if_afio!(impl TXD3Pin<T, A>)>,
309 tx_en: Peri<'d, impl TXEnPin<T>>, 309 tx_en: Peri<'d, if_afio!(impl TXEnPin<T, A>)>,
310 phy: P, 310 phy: P,
311 mac_addr: [u8; 6], 311 mac_addr: [u8; 6],
312 ) -> Self { 312 ) -> Self {
diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs
index 034c5dd88..cf7a9901b 100644
--- a/embassy-stm32/src/eth/v2/mod.rs
+++ b/embassy-stm32/src/eth/v2/mod.rs
@@ -57,7 +57,7 @@ macro_rules! config_pins {
57 critical_section::with(|_| { 57 critical_section::with(|_| {
58 $( 58 $(
59 // TODO: shouldn't some pins be configured as inputs? 59 // TODO: shouldn't some pins be configured as inputs?
60 $pin.set_as_af($pin.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); 60 set_as_af!($pin, AfType::output(OutputType::PushPull, Speed::VeryHigh));
61 )* 61 )*
62 }) 62 })
63 }; 63 };
diff --git a/embassy-stm32/src/fmc.rs b/embassy-stm32/src/fmc.rs
index 71ca775cb..ff18a8bee 100644
--- a/embassy-stm32/src/fmc.rs
+++ b/embassy-stm32/src/fmc.rs
@@ -75,7 +75,7 @@ where
75macro_rules! config_pins { 75macro_rules! config_pins {
76 ($($pin:ident),*) => { 76 ($($pin:ident),*) => {
77 $( 77 $(
78 $pin.set_as_af($pin.af_num(), AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up)); 78 set_as_af!($pin, AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up));
79 )* 79 )*
80 }; 80 };
81} 81}
diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs
index bb37c4194..5a8d23183 100644
--- a/embassy-stm32/src/gpio.rs
+++ b/embassy-stm32/src/gpio.rs
@@ -150,9 +150,13 @@ impl<'d> Flex<'d> {
150 /// This puts the pin into the AF mode, with the requested number and AF type. This is 150 /// This puts the pin into the AF mode, with the requested number and AF type. This is
151 /// completely unchecked, it can attach the pin to literally any peripheral, so use with care. 151 /// completely unchecked, it can attach the pin to literally any peripheral, so use with care.
152 #[inline] 152 #[inline]
153 pub fn set_as_af_unchecked(&mut self, af_num: u8, af_type: AfType) { 153 pub fn set_as_af_unchecked(&mut self, #[cfg(not(afio))] af_num: u8, af_type: AfType) {
154 critical_section::with(|_| { 154 critical_section::with(|_| {
155 self.pin.set_as_af(af_num, af_type); 155 self.pin.set_as_af(
156 #[cfg(not(afio))]
157 af_num,
158 af_type,
159 );
156 }); 160 });
157 } 161 }
158 162
@@ -588,7 +592,7 @@ impl AfType {
588 592
589#[inline(never)] 593#[inline(never)]
590#[cfg(gpio_v1)] 594#[cfg(gpio_v1)]
591fn set_as_af(pin_port: u8, _af_num: u8, af_type: AfType) { 595fn set_as_af(pin_port: u8, af_type: AfType) {
592 let pin = unsafe { AnyPin::steal(pin_port) }; 596 let pin = unsafe { AnyPin::steal(pin_port) };
593 let r = pin.block(); 597 let r = pin.block();
594 let n = pin._pin() as usize; 598 let n = pin._pin() as usize;
@@ -710,6 +714,18 @@ fn get_pull(pin_port: u8) -> Pull {
710 }; 714 };
711} 715}
712 716
717#[cfg(afio)]
718/// Holds the AFIO remap value for a peripheral's pin
719pub struct AfioRemap<const V: u8>;
720
721#[cfg(afio)]
722/// Holds the AFIO remap value for a peripheral's pin
723pub struct AfioRemapBool<const V: bool>;
724
725#[cfg(afio)]
726/// Placeholder for a peripheral's pin which cannot be remapped via AFIO.
727pub struct AfioRemapNotApplicable;
728
713pub(crate) trait SealedPin { 729pub(crate) trait SealedPin {
714 fn pin_port(&self) -> u8; 730 fn pin_port(&self) -> u8;
715 731
@@ -743,8 +759,13 @@ pub(crate) trait SealedPin {
743 } 759 }
744 760
745 #[inline] 761 #[inline]
746 fn set_as_af(&self, af_num: u8, af_type: AfType) { 762 fn set_as_af(&self, #[cfg(not(afio))] af_num: u8, af_type: AfType) {
747 set_as_af(self.pin_port(), af_num, af_type) 763 set_as_af(
764 self.pin_port(),
765 #[cfg(not(afio))]
766 af_num,
767 af_type,
768 )
748 } 769 }
749 770
750 #[inline] 771 #[inline]
diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs
index 1d0594125..6fece5eb2 100644
--- a/embassy-stm32/src/hrtim/mod.rs
+++ b/embassy-stm32/src/hrtim/mod.rs
@@ -79,10 +79,7 @@ macro_rules! advanced_channel_impl {
79 pub fn $new_chx(pin: Peri<'d, impl $pin_trait<T>>) -> Self { 79 pub fn $new_chx(pin: Peri<'d, impl $pin_trait<T>>) -> Self {
80 critical_section::with(|_| { 80 critical_section::with(|_| {
81 pin.set_low(); 81 pin.set_low();
82 pin.set_as_af( 82 set_as_af!(pin, AfType::output(OutputType::PushPull, Speed::VeryHigh));
83 pin.af_num(),
84 AfType::output(OutputType::PushPull, Speed::VeryHigh),
85 );
86 }); 83 });
87 PwmPin { 84 PwmPin {
88 _pin: pin.into(), 85 _pin: pin.into(),
@@ -96,10 +93,7 @@ macro_rules! advanced_channel_impl {
96 pub fn $new_chx(pin: Peri<'d, impl $complementary_pin_trait<T>>) -> Self { 93 pub fn $new_chx(pin: Peri<'d, impl $complementary_pin_trait<T>>) -> Self {
97 critical_section::with(|_| { 94 critical_section::with(|_| {
98 pin.set_low(); 95 pin.set_low();
99 pin.set_as_af( 96 set_as_af!(pin, AfType::output(OutputType::PushPull, Speed::VeryHigh));
100 pin.af_num(),
101 AfType::output(OutputType::PushPull, Speed::VeryHigh),
102 );
103 }); 97 });
104 ComplementaryPwmPin { 98 ComplementaryPwmPin {
105 _pin: pin.into(), 99 _pin: pin.into(),
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs
index 5fb49f943..249bac41c 100644
--- a/embassy-stm32/src/i2c/mod.rs
+++ b/embassy-stm32/src/i2c/mod.rs
@@ -149,10 +149,10 @@ pub struct I2c<'d, M: Mode, IM: MasterMode> {
149 149
150impl<'d> I2c<'d, Async, Master> { 150impl<'d> I2c<'d, Async, Master> {
151 /// Create a new I2C driver. 151 /// Create a new I2C driver.
152 pub fn new<T: Instance>( 152 pub fn new<T: Instance, #[cfg(afio)] A>(
153 peri: Peri<'d, T>, 153 peri: Peri<'d, T>,
154 scl: Peri<'d, impl SclPin<T>>, 154 scl: Peri<'d, if_afio!(impl SclPin<T, A>)>,
155 sda: Peri<'d, impl SdaPin<T>>, 155 sda: Peri<'d, if_afio!(impl SdaPin<T, A>)>,
156 _irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>> 156 _irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>>
157 + interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>> 157 + interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>>
158 + 'd, 158 + 'd,
@@ -173,10 +173,10 @@ impl<'d> I2c<'d, Async, Master> {
173 173
174impl<'d> I2c<'d, Blocking, Master> { 174impl<'d> I2c<'d, Blocking, Master> {
175 /// Create a new blocking I2C driver. 175 /// Create a new blocking I2C driver.
176 pub fn new_blocking<T: Instance>( 176 pub fn new_blocking<T: Instance, #[cfg(afio)] A>(
177 peri: Peri<'d, T>, 177 peri: Peri<'d, T>,
178 scl: Peri<'d, impl SclPin<T>>, 178 scl: Peri<'d, if_afio!(impl SclPin<T, A>)>,
179 sda: Peri<'d, impl SdaPin<T>>, 179 sda: Peri<'d, if_afio!(impl SdaPin<T, A>)>,
180 config: Config, 180 config: Config,
181 ) -> Self { 181 ) -> Self {
182 Self::new_inner( 182 Self::new_inner(
@@ -296,8 +296,8 @@ peri_trait!(
296 irqs: [EventInterrupt, ErrorInterrupt], 296 irqs: [EventInterrupt, ErrorInterrupt],
297); 297);
298 298
299pin_trait!(SclPin, Instance); 299pin_trait!(SclPin, Instance, @A);
300pin_trait!(SdaPin, Instance); 300pin_trait!(SdaPin, Instance, @A);
301dma_trait!(RxDma, Instance); 301dma_trait!(RxDma, Instance);
302dma_trait!(TxDma, Instance); 302dma_trait!(TxDma, Instance);
303 303
diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs
index 0c4ab56e3..b6d3daf54 100644
--- a/embassy-stm32/src/i2s.rs
+++ b/embassy-stm32/src/i2s.rs
@@ -237,12 +237,12 @@ pub struct I2S<'d, W: Word> {
237 237
238impl<'d, W: Word> I2S<'d, W> { 238impl<'d, W: Word> I2S<'d, W> {
239 /// Create a transmitter driver. 239 /// Create a transmitter driver.
240 pub fn new_txonly<T: Instance>( 240 pub fn new_txonly<T: Instance, #[cfg(afio)] A>(
241 peri: Peri<'d, T>, 241 peri: Peri<'d, T>,
242 sd: Peri<'d, impl MosiPin<T>>, 242 sd: Peri<'d, if_afio!(impl MosiPin<T, A>)>,
243 ws: Peri<'d, impl WsPin<T>>, 243 ws: Peri<'d, if_afio!(impl WsPin<T, A>)>,
244 ck: Peri<'d, impl CkPin<T>>, 244 ck: Peri<'d, if_afio!(impl CkPin<T, A>)>,
245 mck: Peri<'d, impl MckPin<T>>, 245 mck: Peri<'d, if_afio!(impl MckPin<T, A>)>,
246 txdma: Peri<'d, impl TxDma<T>>, 246 txdma: Peri<'d, impl TxDma<T>>,
247 txdma_buf: &'d mut [W], 247 txdma_buf: &'d mut [W],
248 config: Config, 248 config: Config,
@@ -262,11 +262,11 @@ impl<'d, W: Word> I2S<'d, W> {
262 } 262 }
263 263
264 /// Create a transmitter driver without a master clock pin. 264 /// Create a transmitter driver without a master clock pin.
265 pub fn new_txonly_nomck<T: Instance>( 265 pub fn new_txonly_nomck<T: Instance, #[cfg(afio)] A>(
266 peri: Peri<'d, T>, 266 peri: Peri<'d, T>,
267 sd: Peri<'d, impl MosiPin<T>>, 267 sd: Peri<'d, if_afio!(impl MosiPin<T, A>)>,
268 ws: Peri<'d, impl WsPin<T>>, 268 ws: Peri<'d, if_afio!(impl WsPin<T, A>)>,
269 ck: Peri<'d, impl CkPin<T>>, 269 ck: Peri<'d, if_afio!(impl CkPin<T, A>)>,
270 txdma: Peri<'d, impl TxDma<T>>, 270 txdma: Peri<'d, impl TxDma<T>>,
271 txdma_buf: &'d mut [W], 271 txdma_buf: &'d mut [W],
272 config: Config, 272 config: Config,
@@ -286,12 +286,12 @@ impl<'d, W: Word> I2S<'d, W> {
286 } 286 }
287 287
288 /// Create a receiver driver. 288 /// Create a receiver driver.
289 pub fn new_rxonly<T: Instance>( 289 pub fn new_rxonly<T: Instance, #[cfg(afio)] A>(
290 peri: Peri<'d, T>, 290 peri: Peri<'d, T>,
291 sd: Peri<'d, impl MisoPin<T>>, 291 sd: Peri<'d, if_afio!(impl MisoPin<T, A>)>,
292 ws: Peri<'d, impl WsPin<T>>, 292 ws: Peri<'d, if_afio!(impl WsPin<T, A>)>,
293 ck: Peri<'d, impl CkPin<T>>, 293 ck: Peri<'d, if_afio!(impl CkPin<T, A>)>,
294 mck: Peri<'d, impl MckPin<T>>, 294 mck: Peri<'d, if_afio!(impl MckPin<T, A>)>,
295 rxdma: Peri<'d, impl RxDma<T>>, 295 rxdma: Peri<'d, impl RxDma<T>>,
296 rxdma_buf: &'d mut [W], 296 rxdma_buf: &'d mut [W],
297 config: Config, 297 config: Config,
@@ -313,13 +313,13 @@ impl<'d, W: Word> I2S<'d, W> {
313 #[cfg(any(spi_v4, spi_v5))] 313 #[cfg(any(spi_v4, spi_v5))]
314 314
315 /// Create a full duplex driver. 315 /// Create a full duplex driver.
316 pub fn new_full_duplex<T: Instance>( 316 pub fn new_full_duplex<T: Instance, #[cfg(afio)] A>(
317 peri: Peri<'d, T>, 317 peri: Peri<'d, T>,
318 txsd: Peri<'d, impl MosiPin<T>>, 318 txsd: Peri<'d, if_afio!(impl MosiPin<T, A>)>,
319 rxsd: Peri<'d, impl MisoPin<T>>, 319 rxsd: Peri<'d, if_afio!(impl MisoPin<T, A>)>,
320 ws: Peri<'d, impl WsPin<T>>, 320 ws: Peri<'d, if_afio!(impl WsPin<T, A>)>,
321 ck: Peri<'d, impl CkPin<T>>, 321 ck: Peri<'d, if_afio!(impl CkPin<T, A>)>,
322 mck: Peri<'d, impl MckPin<T>>, 322 mck: Peri<'d, if_afio!(impl MckPin<T, A>)>,
323 txdma: Peri<'d, impl TxDma<T>>, 323 txdma: Peri<'d, impl TxDma<T>>,
324 txdma_buf: &'d mut [W], 324 txdma_buf: &'d mut [W],
325 rxdma: Peri<'d, impl RxDma<T>>, 325 rxdma: Peri<'d, impl RxDma<T>>,
@@ -459,20 +459,20 @@ impl<'d, W: Word> I2S<'d, W> {
459 } 459 }
460 } 460 }
461 461
462 fn new_inner<T: Instance>( 462 fn new_inner<T: Instance, #[cfg(afio)] A>(
463 peri: Peri<'d, T>, 463 peri: Peri<'d, T>,
464 txsd: Option<Peri<'d, AnyPin>>, 464 txsd: Option<Peri<'d, AnyPin>>,
465 rxsd: Option<Peri<'d, AnyPin>>, 465 rxsd: Option<Peri<'d, AnyPin>>,
466 ws: Peri<'d, impl WsPin<T>>, 466 ws: Peri<'d, if_afio!(impl WsPin<T, A>)>,
467 ck: Peri<'d, impl CkPin<T>>, 467 ck: Peri<'d, if_afio!(impl CkPin<T, A>)>,
468 mck: Option<Peri<'d, AnyPin>>, 468 mck: Option<Peri<'d, AnyPin>>,
469 txdma: Option<(ChannelAndRequest<'d>, &'d mut [W])>, 469 txdma: Option<(ChannelAndRequest<'d>, &'d mut [W])>,
470 rxdma: Option<(ChannelAndRequest<'d>, &'d mut [W])>, 470 rxdma: Option<(ChannelAndRequest<'d>, &'d mut [W])>,
471 config: Config, 471 config: Config,
472 function: Function, 472 function: Function,
473 ) -> Self { 473 ) -> Self {
474 ws.set_as_af(ws.af_num(), AfType::output(OutputType::PushPull, config.gpio_speed)); 474 set_as_af!(ws, AfType::output(OutputType::PushPull, config.gpio_speed));
475 ck.set_as_af(ck.af_num(), AfType::output(OutputType::PushPull, config.gpio_speed)); 475 set_as_af!(ck, AfType::output(OutputType::PushPull, config.gpio_speed));
476 476
477 let spi = Spi::new_internal(peri, None, None, { 477 let spi = Spi::new_internal(peri, None, None, {
478 let mut spi_config = SpiConfig::default(); 478 let mut spi_config = SpiConfig::default();
diff --git a/embassy-stm32/src/lptim/pwm.rs b/embassy-stm32/src/lptim/pwm.rs
index 2f2d7ba01..96af9f4d9 100644
--- a/embassy-stm32/src/lptim/pwm.rs
+++ b/embassy-stm32/src/lptim/pwm.rs
@@ -50,10 +50,7 @@ macro_rules! channel_impl {
50 pub fn $new_chx(pin: Peri<'d, impl $pin_trait<T>>) -> Self { 50 pub fn $new_chx(pin: Peri<'d, impl $pin_trait<T>>) -> Self {
51 critical_section::with(|_| { 51 critical_section::with(|_| {
52 pin.set_low(); 52 pin.set_low();
53 pin.set_as_af( 53 set_as_af!(pin, AfType::output(OutputType::PushPull, Speed::VeryHigh));
54 pin.af_num(),
55 AfType::output(OutputType::PushPull, Speed::VeryHigh),
56 );
57 }); 54 });
58 PwmPin { 55 PwmPin {
59 _pin: pin.into(), 56 _pin: pin.into(),
@@ -64,12 +61,12 @@ macro_rules! channel_impl {
64 pub fn $new_chx_with_config(pin: Peri<'d, impl $pin_trait<T>>, pin_config: PwmPinConfig) -> Self { 61 pub fn $new_chx_with_config(pin: Peri<'d, impl $pin_trait<T>>, pin_config: PwmPinConfig) -> Self {
65 critical_section::with(|_| { 62 critical_section::with(|_| {
66 pin.set_low(); 63 pin.set_low();
67 pin.set_as_af( 64 #[cfg(gpio_v1)]
68 pin.af_num(), 65 set_as_af!(pin, AfType::output(pin_config.output_type, pin_config.speed));
69 #[cfg(gpio_v1)] 66 #[cfg(gpio_v2)]
70 AfType::output(pin_config.output_type, pin_config.speed), 67 set_as_af!(
71 #[cfg(gpio_v2)] 68 pin,
72 AfType::output_pull(pin_config.output_type, pin_config.speed, pin_config.pull), 69 AfType::output_pull(pin_config.output_type, pin_config.speed, pin_config.pull)
73 ); 70 );
74 }); 71 });
75 PwmPin { 72 PwmPin {
diff --git a/embassy-stm32/src/macros.rs b/embassy-stm32/src/macros.rs
index 3a0b490ba..22cc2e049 100644
--- a/embassy-stm32/src/macros.rs
+++ b/embassy-stm32/src/macros.rs
@@ -41,17 +41,30 @@ macro_rules! peri_trait_impl {
41} 41}
42 42
43macro_rules! pin_trait { 43macro_rules! pin_trait {
44 ($signal:ident, $instance:path $(, $mode:path)?) => { 44 ($signal:ident, $instance:path $(, $mode:path)? $(, @$afio:ident)?) => {
45 #[doc = concat!(stringify!($signal), " pin trait")] 45 #[doc = concat!(stringify!($signal), " pin trait")]
46 pub trait $signal<T: $instance $(, M: $mode)?>: crate::gpio::Pin { 46 pub trait $signal<T: $instance $(, M: $mode)? $(, #[cfg(afio)] $afio)?>: crate::gpio::Pin {
47 #[cfg(not(afio))]
47 #[doc = concat!("Get the AF number needed to use this pin as ", stringify!($signal))] 48 #[doc = concat!("Get the AF number needed to use this pin as ", stringify!($signal))]
48 fn af_num(&self) -> u8; 49 fn af_num(&self) -> u8;
50
51 #[cfg(afio)]
52 #[doc = concat!("Configures AFIO_MAPR to use this pin as ", stringify!($signal))]
53 fn afio_remap(&self);
49 } 54 }
50 }; 55 };
51} 56}
52 57
53macro_rules! pin_trait_impl { 58macro_rules! pin_trait_impl {
54 (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, $pin:ident, $af:expr) => { 59 (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, $pin:ident, $af:expr $(, $afio:path)?) => {
60 #[cfg(afio)]
61 impl crate::$mod::$trait<crate::peripherals::$instance $(, crate::$mod::$mode)? $(, $afio)?> for crate::peripherals::$pin {
62 fn afio_remap(&self) {
63 // nothing
64 }
65 }
66
67 #[cfg(not(afio))]
55 impl crate::$mod::$trait<crate::peripherals::$instance $(, crate::$mod::$mode)?> for crate::peripherals::$pin { 68 impl crate::$mod::$trait<crate::peripherals::$instance $(, crate::$mod::$mode)?> for crate::peripherals::$pin {
56 fn af_num(&self) -> u8 { 69 fn af_num(&self) -> u8 {
57 $af 70 $af
@@ -60,6 +73,39 @@ macro_rules! pin_trait_impl {
60 }; 73 };
61} 74}
62 75
76#[cfg(afio)]
77macro_rules! pin_trait_afio_impl {
78 (@set mapr, $setter:ident, $val:expr) => {
79 crate::pac::AFIO.mapr().modify(|w| {
80 w.set_swj_cfg(crate::pac::afio::vals::SwjCfg::NO_OP);
81 w.$setter($val);
82 });
83 };
84 (@set mapr2, $setter:ident, $val:expr) => {
85 crate::pac::AFIO.mapr2().modify(|w| {
86 w.$setter($val);
87 });
88 };
89 (crate::$mod:ident::$trait:ident<$mode:ident>, $instance:ident, $pin:ident, {$reg:ident, $setter:ident, $type:ident, [$($val:expr),+]}) => {
90 $(
91 impl crate::$mod::$trait<crate::peripherals::$instance, crate::$mod::$mode, crate::gpio::$type<$val>> for crate::peripherals::$pin {
92 fn afio_remap(&self) {
93 pin_trait_afio_impl!(@set $reg, $setter, $val);
94 }
95 }
96 )+
97 };
98 (crate::$mod:ident::$trait:ident, $instance:ident, $pin:ident, {$reg:ident, $setter:ident, $type:ident, [$($val:expr),+]}) => {
99 $(
100 impl crate::$mod::$trait<crate::peripherals::$instance, crate::gpio::$type<$val>> for crate::peripherals::$pin {
101 fn afio_remap(&self) {
102 pin_trait_afio_impl!(@set $reg, $setter, $val);
103 }
104 }
105 )+
106 };
107}
108
63#[allow(unused_macros)] 109#[allow(unused_macros)]
64macro_rules! sel_trait_impl { 110macro_rules! sel_trait_impl {
65 (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, $pin:ident, $sel:expr) => { 111 (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, $pin:ident, $sel:expr) => {
@@ -134,7 +180,73 @@ macro_rules! new_dma {
134macro_rules! new_pin { 180macro_rules! new_pin {
135 ($name:ident, $af_type:expr) => {{ 181 ($name:ident, $af_type:expr) => {{
136 let pin = $name; 182 let pin = $name;
137 pin.set_as_af(pin.af_num(), $af_type); 183 #[cfg(afio)]
184 pin.afio_remap();
185 pin.set_as_af(
186 #[cfg(not(afio))]
187 pin.af_num(),
188 $af_type,
189 );
138 Some(pin.into()) 190 Some(pin.into())
139 }}; 191 }};
140} 192}
193
194/// Macro to configure a pin for alternate function use.
195/// For AFIO chips (STM32F1), it calls afio_remap().
196/// For non-AFIO chips, it calls set_as_af() with the pin's af_num().
197macro_rules! set_as_af {
198 ($pin:expr, $af_type:expr) => {
199 #[cfg(afio)]
200 {
201 $pin.set_as_af($af_type);
202 $pin.afio_remap();
203 }
204 #[cfg(not(afio))]
205 {
206 $pin.set_as_af($pin.af_num(), $af_type);
207 }
208 };
209}
210
211#[cfg(afio)]
212macro_rules! if_afio {
213 ($($t:tt)*) => {
214 $($t)*
215 }
216}
217#[cfg(not(afio))]
218macro_rules! if_afio {
219 (($a:ty, A)) => {
220 ($a,)
221 };
222 (($a:ty, $b:ty, A)) => {
223 ($a,$b)
224 };
225 (($a:ty, $b:ty, $c:ty, A)) => {
226 ($a,$b, $c)
227 };
228 ($type:ident<$lt:lifetime, $a:ty, $b:ty, A>) => {
229 $type<$lt, $a, $b>
230 };
231 ($type:ident<$lt:lifetime, $a:ty, $b:ty, $c:ty, A>) => {
232 $type<$lt, $a, $b, $c>
233 };
234 ($type:ident<$a:ty, A>) => {
235 $type<$a>
236 };
237 ($type:ident<$a:ty, $b:ty, A>) => {
238 $type<$a, $b>
239 };
240 ($type:ident<$a:ty, $b:ty, $c:ty, A>) => {
241 $type<$a, $b, $c>
242 };
243 (impl $trait:ident<$a:ty, A>) => {
244 impl $trait<$a>
245 };
246 (impl $trait:ident<$a:ty, $b:ty, A>) => {
247 impl $trait<$a, $b>
248 };
249 (impl $trait:ident<$a:ty, $b:ty, $c:ty, A>) => {
250 impl $trait<$a, $b, $c>
251 };
252}
diff --git a/embassy-stm32/src/rcc/mco.rs b/embassy-stm32/src/rcc/mco.rs
index 96e628b1a..59ccc8cb5 100644
--- a/embassy-stm32/src/rcc/mco.rs
+++ b/embassy-stm32/src/rcc/mco.rs
@@ -94,7 +94,7 @@ impl<'d, T: McoInstance> Mco<'d, T> {
94 pub fn new(_peri: Peri<'d, T>, pin: Peri<'d, impl McoPin<T>>, source: T::Source, prescaler: McoPrescaler) -> Self { 94 pub fn new(_peri: Peri<'d, T>, pin: Peri<'d, impl McoPin<T>>, source: T::Source, prescaler: McoPrescaler) -> Self {
95 critical_section::with(|_| unsafe { 95 critical_section::with(|_| unsafe {
96 T::_apply_clock_settings(source, prescaler); 96 T::_apply_clock_settings(source, prescaler);
97 pin.set_as_af(pin.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); 97 set_as_af!(pin, AfType::output(OutputType::PushPull, Speed::VeryHigh));
98 }); 98 });
99 99
100 Self { phantom: PhantomData } 100 Self { phantom: PhantomData }
diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs
index cde2a56c2..fb8b23b79 100644
--- a/embassy-stm32/src/sai/mod.rs
+++ b/embassy-stm32/src/sai/mod.rs
@@ -558,7 +558,7 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> {
558 config: Config, 558 config: Config,
559 ) -> Self { 559 ) -> Self {
560 let (_sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx); 560 let (_sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx);
561 mclk.set_as_af(mclk.af_num(), ck_af_type); 561 set_as_af!(mclk, ck_af_type);
562 562
563 Self::new_asynchronous(peri, sck, sd, fs, dma, dma_buf, config) 563 Self::new_asynchronous(peri, sck, sd, fs, dma, dma_buf, config)
564 } 564 }
@@ -578,9 +578,9 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> {
578 let peri = peri.peri; 578 let peri = peri.peri;
579 579
580 let (sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx); 580 let (sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx);
581 sd.set_as_af(sd.af_num(), sd_af_type); 581 set_as_af!(sd, sd_af_type);
582 sck.set_as_af(sck.af_num(), ck_af_type); 582 set_as_af!(sck, ck_af_type);
583 fs.set_as_af(fs.af_num(), ck_af_type); 583 set_as_af!(fs, ck_af_type);
584 584
585 let sub_block = S::WHICH; 585 let sub_block = S::WHICH;
586 let request = dma.request(); 586 let request = dma.request();
@@ -612,7 +612,7 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> {
612 let peri = peri.peri; 612 let peri = peri.peri;
613 613
614 let (sd_af_type, _ck_af_type) = get_af_types(config.mode, config.tx_rx); 614 let (sd_af_type, _ck_af_type) = get_af_types(config.mode, config.tx_rx);
615 sd.set_as_af(sd.af_num(), sd_af_type); 615 set_as_af!(sd, sd_af_type);
616 616
617 let sub_block = S::WHICH; 617 let sub_block = S::WHICH;
618 let request = dma.request(); 618 let request = dma.request();
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index 6e5d735d7..ccbd16cbf 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -428,9 +428,9 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
428 config: Config, 428 config: Config,
429 ) -> Self { 429 ) -> Self {
430 critical_section::with(|_| { 430 critical_section::with(|_| {
431 clk.set_as_af(clk.af_num(), CLK_AF); 431 set_as_af!(clk, CLK_AF);
432 cmd.set_as_af(cmd.af_num(), CMD_AF); 432 set_as_af!(cmd, CMD_AF);
433 d0.set_as_af(d0.af_num(), DATA_AF); 433 set_as_af!(d0, DATA_AF);
434 }); 434 });
435 435
436 Self::new_inner( 436 Self::new_inner(
@@ -464,12 +464,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
464 config: Config, 464 config: Config,
465 ) -> Self { 465 ) -> Self {
466 critical_section::with(|_| { 466 critical_section::with(|_| {
467 clk.set_as_af(clk.af_num(), CLK_AF); 467 set_as_af!(clk, CLK_AF);
468 cmd.set_as_af(cmd.af_num(), CMD_AF); 468 set_as_af!(cmd, CMD_AF);
469 d0.set_as_af(d0.af_num(), DATA_AF); 469 set_as_af!(d0, DATA_AF);
470 d1.set_as_af(d1.af_num(), DATA_AF); 470 set_as_af!(d1, DATA_AF);
471 d2.set_as_af(d2.af_num(), DATA_AF); 471 set_as_af!(d2, DATA_AF);
472 d3.set_as_af(d3.af_num(), DATA_AF); 472 set_as_af!(d3, DATA_AF);
473 }); 473 });
474 474
475 Self::new_inner( 475 Self::new_inner(
@@ -510,16 +510,16 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
510 config: Config, 510 config: Config,
511 ) -> Self { 511 ) -> Self {
512 critical_section::with(|_| { 512 critical_section::with(|_| {
513 clk.set_as_af(clk.af_num(), CLK_AF); 513 set_as_af!(clk, CLK_AF);
514 cmd.set_as_af(cmd.af_num(), CMD_AF); 514 set_as_af!(cmd, CMD_AF);
515 d0.set_as_af(d0.af_num(), DATA_AF); 515 set_as_af!(d0, DATA_AF);
516 d1.set_as_af(d1.af_num(), DATA_AF); 516 set_as_af!(d1, DATA_AF);
517 d2.set_as_af(d2.af_num(), DATA_AF); 517 set_as_af!(d2, DATA_AF);
518 d3.set_as_af(d3.af_num(), DATA_AF); 518 set_as_af!(d3, DATA_AF);
519 d4.set_as_af(d4.af_num(), DATA_AF); 519 set_as_af!(d4, DATA_AF);
520 d5.set_as_af(d5.af_num(), DATA_AF); 520 set_as_af!(d5, DATA_AF);
521 d6.set_as_af(d6.af_num(), DATA_AF); 521 set_as_af!(d6, DATA_AF);
522 d7.set_as_af(d7.af_num(), DATA_AF); 522 set_as_af!(d7, DATA_AF);
523 }); 523 });
524 524
525 Self::new_inner( 525 Self::new_inner(
@@ -552,9 +552,9 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
552 config: Config, 552 config: Config,
553 ) -> Self { 553 ) -> Self {
554 critical_section::with(|_| { 554 critical_section::with(|_| {
555 clk.set_as_af(clk.af_num(), CLK_AF); 555 set_as_af!(clk, CLK_AF);
556 cmd.set_as_af(cmd.af_num(), CMD_AF); 556 set_as_af!(cmd, CMD_AF);
557 d0.set_as_af(d0.af_num(), DATA_AF); 557 set_as_af!(d0, DATA_AF);
558 }); 558 });
559 559
560 Self::new_inner( 560 Self::new_inner(
@@ -586,12 +586,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
586 config: Config, 586 config: Config,
587 ) -> Self { 587 ) -> Self {
588 critical_section::with(|_| { 588 critical_section::with(|_| {
589 clk.set_as_af(clk.af_num(), CLK_AF); 589 set_as_af!(clk, CLK_AF);
590 cmd.set_as_af(cmd.af_num(), CMD_AF); 590 set_as_af!(cmd, CMD_AF);
591 d0.set_as_af(d0.af_num(), DATA_AF); 591 set_as_af!(d0, DATA_AF);
592 d1.set_as_af(d1.af_num(), DATA_AF); 592 set_as_af!(d1, DATA_AF);
593 d2.set_as_af(d2.af_num(), DATA_AF); 593 set_as_af!(d2, DATA_AF);
594 d3.set_as_af(d3.af_num(), DATA_AF); 594 set_as_af!(d3, DATA_AF);
595 }); 595 });
596 596
597 Self::new_inner( 597 Self::new_inner(
@@ -630,16 +630,16 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
630 config: Config, 630 config: Config,
631 ) -> Self { 631 ) -> Self {
632 critical_section::with(|_| { 632 critical_section::with(|_| {
633 clk.set_as_af(clk.af_num(), CLK_AF); 633 set_as_af!(clk, CLK_AF);
634 cmd.set_as_af(cmd.af_num(), CMD_AF); 634 set_as_af!(cmd, CMD_AF);
635 d0.set_as_af(d0.af_num(), DATA_AF); 635 set_as_af!(d0, DATA_AF);
636 d1.set_as_af(d1.af_num(), DATA_AF); 636 set_as_af!(d1, DATA_AF);
637 d2.set_as_af(d2.af_num(), DATA_AF); 637 set_as_af!(d2, DATA_AF);
638 d3.set_as_af(d3.af_num(), DATA_AF); 638 set_as_af!(d3, DATA_AF);
639 d4.set_as_af(d4.af_num(), DATA_AF); 639 set_as_af!(d4, DATA_AF);
640 d5.set_as_af(d5.af_num(), DATA_AF); 640 set_as_af!(d5, DATA_AF);
641 d6.set_as_af(d6.af_num(), DATA_AF); 641 set_as_af!(d6, DATA_AF);
642 d7.set_as_af(d7.af_num(), DATA_AF); 642 set_as_af!(d7, DATA_AF);
643 }); 643 });
644 644
645 Self::new_inner( 645 Self::new_inner(
diff --git a/embassy-stm32/src/spdifrx/mod.rs b/embassy-stm32/src/spdifrx/mod.rs
index 466639e83..b0a32d5d1 100644
--- a/embassy-stm32/src/spdifrx/mod.rs
+++ b/embassy-stm32/src/spdifrx/mod.rs
@@ -35,7 +35,7 @@ macro_rules! new_spdifrx_pin {
35 ($name:ident, $af_type:expr) => {{ 35 ($name:ident, $af_type:expr) => {{
36 let pin = $name; 36 let pin = $name;
37 let input_sel = pin.input_sel(); 37 let input_sel = pin.input_sel();
38 pin.set_as_af(pin.af_num(), $af_type); 38 set_as_af!(pin, $af_type);
39 (Some(pin.into()), input_sel) 39 (Some(pin.into()), input_sel)
40 }}; 40 }};
41} 41}
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index a49ebcbee..c5373a54d 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -471,11 +471,11 @@ impl<'d, M: PeriMode> Spi<'d, M> {
471 471
472impl<'d> Spi<'d, Blocking> { 472impl<'d> Spi<'d, Blocking> {
473 /// Create a new blocking SPI driver. 473 /// Create a new blocking SPI driver.
474 pub fn new_blocking<T: Instance>( 474 pub fn new_blocking<T: Instance, #[cfg(afio)] A>(
475 peri: Peri<'d, T>, 475 peri: Peri<'d, T>,
476 sck: Peri<'d, impl SckPin<T>>, 476 sck: Peri<'d, if_afio!(impl SckPin<T, A>)>,
477 mosi: Peri<'d, impl MosiPin<T>>, 477 mosi: Peri<'d, if_afio!(impl MosiPin<T, A>)>,
478 miso: Peri<'d, impl MisoPin<T>>, 478 miso: Peri<'d, if_afio!(impl MisoPin<T, A>)>,
479 config: Config, 479 config: Config,
480 ) -> Self { 480 ) -> Self {
481 Self::new_inner( 481 Self::new_inner(
@@ -490,10 +490,10 @@ impl<'d> Spi<'d, Blocking> {
490 } 490 }
491 491
492 /// Create a new blocking SPI driver, in RX-only mode (only MISO pin, no MOSI). 492 /// Create a new blocking SPI driver, in RX-only mode (only MISO pin, no MOSI).
493 pub fn new_blocking_rxonly<T: Instance>( 493 pub fn new_blocking_rxonly<T: Instance, #[cfg(afio)] A>(
494 peri: Peri<'d, T>, 494 peri: Peri<'d, T>,
495 sck: Peri<'d, impl SckPin<T>>, 495 sck: Peri<'d, if_afio!(impl SckPin<T, A>)>,
496 miso: Peri<'d, impl MisoPin<T>>, 496 miso: Peri<'d, if_afio!(impl MisoPin<T, A>)>,
497 config: Config, 497 config: Config,
498 ) -> Self { 498 ) -> Self {
499 Self::new_inner( 499 Self::new_inner(
@@ -508,10 +508,10 @@ impl<'d> Spi<'d, Blocking> {
508 } 508 }
509 509
510 /// Create a new blocking SPI driver, in TX-only mode (only MOSI pin, no MISO). 510 /// Create a new blocking SPI driver, in TX-only mode (only MOSI pin, no MISO).
511 pub fn new_blocking_txonly<T: Instance>( 511 pub fn new_blocking_txonly<T: Instance, #[cfg(afio)] A>(
512 peri: Peri<'d, T>, 512 peri: Peri<'d, T>,
513 sck: Peri<'d, impl SckPin<T>>, 513 sck: Peri<'d, if_afio!(impl SckPin<T, A>)>,
514 mosi: Peri<'d, impl MosiPin<T>>, 514 mosi: Peri<'d, if_afio!(impl MosiPin<T, A>)>,
515 config: Config, 515 config: Config,
516 ) -> Self { 516 ) -> Self {
517 Self::new_inner( 517 Self::new_inner(
@@ -528,9 +528,9 @@ impl<'d> Spi<'d, Blocking> {
528 /// Create a new SPI driver, in TX-only mode, without SCK pin. 528 /// Create a new SPI driver, in TX-only mode, without SCK pin.
529 /// 529 ///
530 /// This can be useful for bit-banging non-SPI protocols. 530 /// This can be useful for bit-banging non-SPI protocols.
531 pub fn new_blocking_txonly_nosck<T: Instance>( 531 pub fn new_blocking_txonly_nosck<T: Instance, #[cfg(afio)] A>(
532 peri: Peri<'d, T>, 532 peri: Peri<'d, T>,
533 mosi: Peri<'d, impl MosiPin<T>>, 533 mosi: Peri<'d, if_afio!(impl MosiPin<T, A>)>,
534 config: Config, 534 config: Config,
535 ) -> Self { 535 ) -> Self {
536 Self::new_inner( 536 Self::new_inner(
@@ -547,11 +547,11 @@ impl<'d> Spi<'d, Blocking> {
547 547
548impl<'d> Spi<'d, Async> { 548impl<'d> Spi<'d, Async> {
549 /// Create a new SPI driver. 549 /// Create a new SPI driver.
550 pub fn new<T: Instance>( 550 pub fn new<T: Instance, #[cfg(afio)] A>(
551 peri: Peri<'d, T>, 551 peri: Peri<'d, T>,
552 sck: Peri<'d, impl SckPin<T>>, 552 sck: Peri<'d, if_afio!(impl SckPin<T, A>)>,
553 mosi: Peri<'d, impl MosiPin<T>>, 553 mosi: Peri<'d, if_afio!(impl MosiPin<T, A>)>,
554 miso: Peri<'d, impl MisoPin<T>>, 554 miso: Peri<'d, if_afio!(impl MisoPin<T, A>)>,
555 tx_dma: Peri<'d, impl TxDma<T>>, 555 tx_dma: Peri<'d, impl TxDma<T>>,
556 rx_dma: Peri<'d, impl RxDma<T>>, 556 rx_dma: Peri<'d, impl RxDma<T>>,
557 config: Config, 557 config: Config,
@@ -568,10 +568,10 @@ impl<'d> Spi<'d, Async> {
568 } 568 }
569 569
570 /// Create a new SPI driver, in RX-only mode (only MISO pin, no MOSI). 570 /// Create a new SPI driver, in RX-only mode (only MISO pin, no MOSI).
571 pub fn new_rxonly<T: Instance>( 571 pub fn new_rxonly<T: Instance, #[cfg(afio)] A>(
572 peri: Peri<'d, T>, 572 peri: Peri<'d, T>,
573 sck: Peri<'d, impl SckPin<T>>, 573 sck: Peri<'d, if_afio!(impl SckPin<T, A>)>,
574 miso: Peri<'d, impl MisoPin<T>>, 574 miso: Peri<'d, if_afio!(impl MisoPin<T, A>)>,
575 #[cfg(any(spi_v1, spi_v2, spi_v3))] tx_dma: Peri<'d, impl TxDma<T>>, 575 #[cfg(any(spi_v1, spi_v2, spi_v3))] tx_dma: Peri<'d, impl TxDma<T>>,
576 rx_dma: Peri<'d, impl RxDma<T>>, 576 rx_dma: Peri<'d, impl RxDma<T>>,
577 config: Config, 577 config: Config,
@@ -591,10 +591,10 @@ impl<'d> Spi<'d, Async> {
591 } 591 }
592 592
593 /// Create a new SPI driver, in TX-only mode (only MOSI pin, no MISO). 593 /// Create a new SPI driver, in TX-only mode (only MOSI pin, no MISO).
594 pub fn new_txonly<T: Instance>( 594 pub fn new_txonly<T: Instance, #[cfg(afio)] A>(
595 peri: Peri<'d, T>, 595 peri: Peri<'d, T>,
596 sck: Peri<'d, impl SckPin<T>>, 596 sck: Peri<'d, if_afio!(impl SckPin<T, A>)>,
597 mosi: Peri<'d, impl MosiPin<T>>, 597 mosi: Peri<'d, if_afio!(impl MosiPin<T, A>)>,
598 tx_dma: Peri<'d, impl TxDma<T>>, 598 tx_dma: Peri<'d, impl TxDma<T>>,
599 config: Config, 599 config: Config,
600 ) -> Self { 600 ) -> Self {
@@ -612,9 +612,9 @@ impl<'d> Spi<'d, Async> {
612 /// Create a new SPI driver, in TX-only mode, without SCK pin. 612 /// Create a new SPI driver, in TX-only mode, without SCK pin.
613 /// 613 ///
614 /// This can be useful for bit-banging non-SPI protocols. 614 /// This can be useful for bit-banging non-SPI protocols.
615 pub fn new_txonly_nosck<T: Instance>( 615 pub fn new_txonly_nosck<T: Instance, #[cfg(afio)] A>(
616 peri: Peri<'d, T>, 616 peri: Peri<'d, T>,
617 mosi: Peri<'d, impl MosiPin<T>>, 617 mosi: Peri<'d, if_afio!(impl MosiPin<T, A>)>,
618 tx_dma: Peri<'d, impl TxDma<T>>, 618 tx_dma: Peri<'d, impl TxDma<T>>,
619 config: Config, 619 config: Config,
620 ) -> Self { 620 ) -> Self {
@@ -1309,13 +1309,13 @@ impl State {
1309 1309
1310peri_trait!(); 1310peri_trait!();
1311 1311
1312pin_trait!(SckPin, Instance); 1312pin_trait!(SckPin, Instance, @A);
1313pin_trait!(MosiPin, Instance); 1313pin_trait!(MosiPin, Instance, @A);
1314pin_trait!(MisoPin, Instance); 1314pin_trait!(MisoPin, Instance, @A);
1315pin_trait!(CsPin, Instance); 1315pin_trait!(CsPin, Instance, @A);
1316pin_trait!(MckPin, Instance); 1316pin_trait!(MckPin, Instance, @A);
1317pin_trait!(CkPin, Instance); 1317pin_trait!(CkPin, Instance, @A);
1318pin_trait!(WsPin, Instance); 1318pin_trait!(WsPin, Instance, @A);
1319dma_trait!(RxDma, Instance); 1319dma_trait!(RxDma, Instance);
1320dma_trait!(TxDma, Instance); 1320dma_trait!(TxDma, Instance);
1321 1321
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs
index 68cdec302..484aae1d0 100644
--- a/embassy-stm32/src/timer/complementary_pwm.rs
+++ b/embassy-stm32/src/timer/complementary_pwm.rs
@@ -16,23 +16,24 @@ use crate::Peri;
16/// Complementary PWM pin wrapper. 16/// Complementary PWM pin wrapper.
17/// 17///
18/// This wraps a pin to make it usable with PWM. 18/// This wraps a pin to make it usable with PWM.
19pub struct ComplementaryPwmPin<'d, T, C> { 19pub struct ComplementaryPwmPin<'d, T, C, #[cfg(afio)] A> {
20 _pin: Peri<'d, AnyPin>, 20 #[allow(unused)]
21 phantom: PhantomData<(T, C)>, 21 pin: Peri<'d, AnyPin>,
22 phantom: PhantomData<if_afio!((T, C, A))>,
22} 23}
23 24
24impl<'d, T: AdvancedInstance4Channel, C: TimerChannel> ComplementaryPwmPin<'d, T, C> { 25impl<'d, T: AdvancedInstance4Channel, C: TimerChannel, #[cfg(afio)] A> if_afio!(ComplementaryPwmPin<'d, T, C, A>) {
25 /// Create a new complementary PWM pin instance. 26 /// Create a new complementary PWM pin instance.
26 pub fn new(pin: Peri<'d, impl TimerComplementaryPin<T, C>>, output_type: OutputType) -> Self { 27 pub fn new(pin: Peri<'d, if_afio!(impl TimerComplementaryPin<T, C, A>)>, output_type: OutputType) -> Self {
27 critical_section::with(|_| { 28 critical_section::with(|_| {
28 pin.set_low(); 29 pin.set_low();
29 pin.set_as_af( 30 set_as_af!(
30 pin.af_num(), 31 pin,
31 crate::gpio::AfType::output(output_type, crate::gpio::Speed::VeryHigh), 32 crate::gpio::AfType::output(output_type, crate::gpio::Speed::VeryHigh)
32 ); 33 );
33 }); 34 });
34 ComplementaryPwmPin { 35 ComplementaryPwmPin {
35 _pin: pin.into(), 36 pin: pin.into(),
36 phantom: PhantomData, 37 phantom: PhantomData,
37 } 38 }
38 } 39 }
@@ -54,17 +55,17 @@ pub enum IdlePolarity {
54 55
55impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { 56impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
56 /// Create a new complementary PWM driver. 57 /// Create a new complementary PWM driver.
57 #[allow(clippy::too_many_arguments)] 58 #[allow(clippy::too_many_arguments, unused)]
58 pub fn new( 59 pub fn new<#[cfg(afio)] A>(
59 tim: Peri<'d, T>, 60 tim: Peri<'d, T>,
60 _ch1: Option<PwmPin<'d, T, Ch1>>, 61 ch1: Option<if_afio!(PwmPin<'d, T, Ch1, A>)>,
61 _ch1n: Option<ComplementaryPwmPin<'d, T, Ch1>>, 62 ch1n: Option<if_afio!(ComplementaryPwmPin<'d, T, Ch1, A>)>,
62 _ch2: Option<PwmPin<'d, T, Ch2>>, 63 ch2: Option<if_afio!(PwmPin<'d, T, Ch2, A>)>,
63 _ch2n: Option<ComplementaryPwmPin<'d, T, Ch2>>, 64 ch2n: Option<if_afio!(ComplementaryPwmPin<'d, T, Ch2, A>)>,
64 _ch3: Option<PwmPin<'d, T, Ch3>>, 65 ch3: Option<if_afio!(PwmPin<'d, T, Ch3, A>)>,
65 _ch3n: Option<ComplementaryPwmPin<'d, T, Ch3>>, 66 ch3n: Option<if_afio!(ComplementaryPwmPin<'d, T, Ch3, A>)>,
66 _ch4: Option<PwmPin<'d, T, Ch4>>, 67 ch4: Option<if_afio!(PwmPin<'d, T, Ch4, A>)>,
67 _ch4n: Option<ComplementaryPwmPin<'d, T, Ch4>>, 68 ch4n: Option<if_afio!(ComplementaryPwmPin<'d, T, Ch4, A>)>,
68 freq: Hertz, 69 freq: Hertz,
69 counting_mode: CountingMode, 70 counting_mode: CountingMode,
70 ) -> Self { 71 ) -> Self {
diff --git a/embassy-stm32/src/timer/input_capture.rs b/embassy-stm32/src/timer/input_capture.rs
index dda33e7f1..7a25e6c21 100644
--- a/embassy-stm32/src/timer/input_capture.rs
+++ b/embassy-stm32/src/timer/input_capture.rs
@@ -17,16 +17,17 @@ use crate::Peri;
17/// Capture pin wrapper. 17/// Capture pin wrapper.
18/// 18///
19/// This wraps a pin to make it usable with capture. 19/// This wraps a pin to make it usable with capture.
20pub struct CapturePin<'d, T, C> { 20pub struct CapturePin<'d, T, C, #[cfg(afio)] A> {
21 _pin: Peri<'d, AnyPin>, 21 #[allow(unused)]
22 phantom: PhantomData<(T, C)>, 22 pin: Peri<'d, AnyPin>,
23 phantom: PhantomData<if_afio!((T, C, A))>,
23} 24}
24impl<'d, T: GeneralInstance4Channel, C: TimerChannel> CapturePin<'d, T, C> { 25impl<'d, T: GeneralInstance4Channel, C: TimerChannel, #[cfg(afio)] A> if_afio!(CapturePin<'d, T, C, A>) {
25 /// Create a new capture pin instance. 26 /// Create a new capture pin instance.
26 pub fn new(pin: Peri<'d, impl TimerPin<T, C>>, pull: Pull) -> Self { 27 pub fn new(pin: Peri<'d, if_afio!(impl TimerPin<T, C, A>)>, pull: Pull) -> Self {
27 pin.set_as_af(pin.af_num(), AfType::input(pull)); 28 set_as_af!(pin, AfType::input(pull));
28 CapturePin { 29 CapturePin {
29 _pin: pin.into(), 30 pin: pin.into(),
30 phantom: PhantomData, 31 phantom: PhantomData,
31 } 32 }
32 } 33 }
@@ -39,12 +40,13 @@ pub struct InputCapture<'d, T: GeneralInstance4Channel> {
39 40
40impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> { 41impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> {
41 /// Create a new input capture driver. 42 /// Create a new input capture driver.
42 pub fn new( 43 #[allow(unused)]
44 pub fn new<#[cfg(afio)] A>(
43 tim: Peri<'d, T>, 45 tim: Peri<'d, T>,
44 _ch1: Option<CapturePin<'d, T, Ch1>>, 46 ch1: Option<if_afio!(CapturePin<'d, T, Ch1, A>)>,
45 _ch2: Option<CapturePin<'d, T, Ch2>>, 47 ch2: Option<if_afio!(CapturePin<'d, T, Ch2, A>)>,
46 _ch3: Option<CapturePin<'d, T, Ch3>>, 48 ch3: Option<if_afio!(CapturePin<'d, T, Ch3, A>)>,
47 _ch4: Option<CapturePin<'d, T, Ch4>>, 49 ch4: Option<if_afio!(CapturePin<'d, T, Ch4, A>)>,
48 _irq: impl Binding<T::CaptureCompareInterrupt, CaptureCompareInterruptHandler<T>> + 'd, 50 _irq: impl Binding<T::CaptureCompareInterrupt, CaptureCompareInterruptHandler<T>> + 'd,
49 freq: Hertz, 51 freq: Hertz,
50 counting_mode: CountingMode, 52 counting_mode: CountingMode,
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs
index 7062f5f4c..b09bc7166 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -223,15 +223,15 @@ pub trait AdvancedInstance2Channel: BasicInstance + GeneralInstance2Channel + Ad
223/// Advanced 16-bit timer with 4 channels instance. 223/// Advanced 16-bit timer with 4 channels instance.
224pub trait AdvancedInstance4Channel: AdvancedInstance2Channel + GeneralInstance4Channel {} 224pub trait AdvancedInstance4Channel: AdvancedInstance2Channel + GeneralInstance4Channel {}
225 225
226pin_trait!(TimerPin, GeneralInstance4Channel, TimerChannel); 226pin_trait!(TimerPin, GeneralInstance4Channel, TimerChannel, @A);
227pin_trait!(ExternalTriggerPin, GeneralInstance4Channel); 227pin_trait!(ExternalTriggerPin, GeneralInstance4Channel, @A);
228 228
229pin_trait!(TimerComplementaryPin, AdvancedInstance4Channel, TimerChannel); 229pin_trait!(TimerComplementaryPin, AdvancedInstance4Channel, TimerChannel, @A);
230 230
231pin_trait!(BreakInputPin, AdvancedInstance4Channel, BreakInput); 231pin_trait!(BreakInputPin, AdvancedInstance4Channel, BreakInput, @A);
232 232
233pin_trait!(BreakInputComparator1Pin, AdvancedInstance4Channel, BreakInput); 233pin_trait!(BreakInputComparator1Pin, AdvancedInstance4Channel, BreakInput, @A);
234pin_trait!(BreakInputComparator2Pin, AdvancedInstance4Channel, BreakInput); 234pin_trait!(BreakInputComparator2Pin, AdvancedInstance4Channel, BreakInput, @A);
235 235
236// Update Event trigger DMA for every timer 236// Update Event trigger DMA for every timer
237dma_trait!(UpDma, BasicInstance); 237dma_trait!(UpDma, BasicInstance);
diff --git a/embassy-stm32/src/timer/one_pulse.rs b/embassy-stm32/src/timer/one_pulse.rs
index 498d9c082..a75b41bd7 100644
--- a/embassy-stm32/src/timer/one_pulse.rs
+++ b/embassy-stm32/src/timer/one_pulse.rs
@@ -15,6 +15,7 @@ use crate::gpio::{AfType, AnyPin, Pull};
15use crate::interrupt::typelevel::{Binding, Interrupt}; 15use crate::interrupt::typelevel::{Binding, Interrupt};
16use crate::pac::timer::vals::Etp; 16use crate::pac::timer::vals::Etp;
17use crate::time::Hertz; 17use crate::time::Hertz;
18use crate::timer::TimerChannel;
18use crate::Peri; 19use crate::Peri;
19 20
20/// External input marker type. 21/// External input marker type.
@@ -42,7 +43,8 @@ impl From<ExternalTriggerPolarity> for Etp {
42/// 43///
43/// This wraps a pin to make it usable as a timer trigger. 44/// This wraps a pin to make it usable as a timer trigger.
44pub struct TriggerPin<'d, T, C> { 45pub struct TriggerPin<'d, T, C> {
45 _pin: Peri<'d, AnyPin>, 46 #[allow(unused)]
47 pin: Peri<'d, AnyPin>,
46 phantom: PhantomData<(T, C)>, 48 phantom: PhantomData<(T, C)>,
47} 49}
48 50
@@ -60,60 +62,23 @@ impl SealedTriggerSource for Ch1 {}
60impl SealedTriggerSource for Ch2 {} 62impl SealedTriggerSource for Ch2 {}
61impl SealedTriggerSource for Ext {} 63impl SealedTriggerSource for Ext {}
62 64
63trait SealedTimerTriggerPin<T, S>: crate::gpio::Pin {} 65impl<'d, T: GeneralInstance4Channel, C: TriggerSource + TimerChannel> TriggerPin<'d, T, C> {
64 66 /// Create a new Channel trigger pin instance.
65/// Marker trait for a trigger pin. 67 pub fn new<#[cfg(afio)] A>(pin: Peri<'d, if_afio!(impl TimerPin<T, C, A>)>, pull: Pull) -> Self {
66#[expect(private_bounds)] 68 set_as_af!(pin, AfType::input(pull));
67// TODO: find better naming scheme than prefixing all pin traits with "Timer". 69 TriggerPin {
68// The trait name cannot conflict with the corresponding type's name. 70 pin: pin.into(),
69// Applies to other timer submodules as well. 71 phantom: PhantomData,
70pub trait TimerTriggerPin<T, S>: SealedTimerTriggerPin<T, S> { 72 }
71 /// Get the AF number needed to use this pin as a trigger source.
72 fn af_num(&self) -> u8;
73}
74
75impl<T, P, C> TimerTriggerPin<T, C> for P
76where
77 T: GeneralInstance4Channel,
78 P: TimerPin<T, C>,
79 C: super::TimerChannel + TriggerSource,
80{
81 fn af_num(&self) -> u8 {
82 TimerPin::af_num(self)
83 }
84}
85
86impl<T, P> TimerTriggerPin<T, Ext> for P
87where
88 T: GeneralInstance4Channel,
89 P: ExternalTriggerPin<T>,
90{
91 fn af_num(&self) -> u8 {
92 ExternalTriggerPin::af_num(self)
93 } 73 }
94} 74}
95 75
96impl<T, P, C> SealedTimerTriggerPin<T, C> for P 76impl<'d, T: GeneralInstance4Channel> TriggerPin<'d, T, Ext> {
97where 77 /// Create a new external trigger pin instance.
98 T: GeneralInstance4Channel, 78 pub fn new_external<#[cfg(afio)] A>(pin: Peri<'d, if_afio!(impl ExternalTriggerPin<T, A>)>, pull: Pull) -> Self {
99 P: TimerPin<T, C>, 79 set_as_af!(pin, AfType::input(pull));
100 C: super::TimerChannel + TriggerSource,
101{
102}
103
104impl<T, P> SealedTimerTriggerPin<T, Ext> for P
105where
106 T: GeneralInstance4Channel,
107 P: ExternalTriggerPin<T>,
108{
109}
110
111impl<'d, T: GeneralInstance4Channel, C: TriggerSource> TriggerPin<'d, T, C> {
112 /// "Create a new Ch1 trigger pin instance.
113 pub fn new(pin: Peri<'d, impl TimerTriggerPin<T, C>>, pull: Pull) -> Self {
114 pin.set_as_af(pin.af_num(), AfType::input(pull));
115 TriggerPin { 80 TriggerPin {
116 _pin: pin.into(), 81 pin: pin.into(),
117 phantom: PhantomData, 82 phantom: PhantomData,
118 } 83 }
119 } 84 }
@@ -131,9 +96,10 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> {
131 /// 96 ///
132 /// The pulse is triggered by a channel 1 input pin on both rising and 97 /// The pulse is triggered by a channel 1 input pin on both rising and
133 /// falling edges. Channel 1 will unusable as an output. 98 /// falling edges. Channel 1 will unusable as an output.
99 #[allow(unused)]
134 pub fn new_ch1_edge_detect( 100 pub fn new_ch1_edge_detect(
135 tim: Peri<'d, T>, 101 tim: Peri<'d, T>,
136 _pin: TriggerPin<'d, T, Ch1>, 102 pin: TriggerPin<'d, T, Ch1>,
137 _irq: impl Binding<T::CaptureCompareInterrupt, CaptureCompareInterruptHandler<T>> + 'd, 103 _irq: impl Binding<T::CaptureCompareInterrupt, CaptureCompareInterruptHandler<T>> + 'd,
138 freq: Hertz, 104 freq: Hertz,
139 pulse_end: u32, 105 pulse_end: u32,
diff --git a/embassy-stm32/src/timer/pwm_input.rs b/embassy-stm32/src/timer/pwm_input.rs
index 1e55f2919..159b5a177 100644
--- a/embassy-stm32/src/timer/pwm_input.rs
+++ b/embassy-stm32/src/timer/pwm_input.rs
@@ -18,15 +18,25 @@ pub struct PwmInput<'d, T: GeneralInstance4Channel> {
18 18
19impl<'d, T: GeneralInstance4Channel> PwmInput<'d, T> { 19impl<'d, T: GeneralInstance4Channel> PwmInput<'d, T> {
20 /// Create a new PWM input driver. 20 /// Create a new PWM input driver.
21 pub fn new_ch1(tim: Peri<'d, T>, pin: Peri<'d, impl TimerPin<T, Ch1>>, pull: Pull, freq: Hertz) -> Self { 21 pub fn new_ch1<#[cfg(afio)] A>(
22 pin.set_as_af(pin.af_num(), AfType::input(pull)); 22 tim: Peri<'d, T>,
23 pin: Peri<'d, if_afio!(impl TimerPin<T, Ch1, A>)>,
24 pull: Pull,
25 freq: Hertz,
26 ) -> Self {
27 set_as_af!(pin, AfType::input(pull));
23 28
24 Self::new_inner(tim, freq, Channel::Ch1, Channel::Ch2) 29 Self::new_inner(tim, freq, Channel::Ch1, Channel::Ch2)
25 } 30 }
26 31
27 /// Create a new PWM input driver. 32 /// Create a new PWM input driver.
28 pub fn new_ch2(tim: Peri<'d, T>, pin: Peri<'d, impl TimerPin<T, Ch2>>, pull: Pull, freq: Hertz) -> Self { 33 pub fn new_ch2<#[cfg(afio)] A>(
29 pin.set_as_af(pin.af_num(), AfType::input(pull)); 34 tim: Peri<'d, T>,
35 pin: Peri<'d, if_afio!(impl TimerPin<T, Ch2, A>)>,
36 pull: Pull,
37 freq: Hertz,
38 ) -> Self {
39 set_as_af!(pin, AfType::input(pull));
30 40
31 Self::new_inner(tim, freq, Channel::Ch2, Channel::Ch1) 41 Self::new_inner(tim, freq, Channel::Ch2, Channel::Ch1)
32 } 42 }
diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs
index eabe1b22a..82b5968b0 100644
--- a/embassy-stm32/src/timer/qei.rs
+++ b/embassy-stm32/src/timer/qei.rs
@@ -20,20 +20,21 @@ pub enum Direction {
20} 20}
21 21
22/// Wrapper for using a pin with QEI. 22/// Wrapper for using a pin with QEI.
23pub struct QeiPin<'d, T, Channel> { 23pub struct QeiPin<'d, T, Channel, #[cfg(afio)] A> {
24 _pin: Peri<'d, AnyPin>, 24 #[allow(unused)]
25 phantom: PhantomData<(T, Channel)>, 25 pin: Peri<'d, AnyPin>,
26 phantom: PhantomData<if_afio!((T, Channel, A))>,
26} 27}
27 28
28impl<'d, T: GeneralInstance4Channel, C: QeiChannel> QeiPin<'d, T, C> { 29impl<'d, T: GeneralInstance4Channel, C: QeiChannel, #[cfg(afio)] A> if_afio!(QeiPin<'d, T, C, A>) {
29 /// Create a new QEI pin instance. 30 /// Create a new QEI pin instance.
30 pub fn new(pin: Peri<'d, impl TimerPin<T, C>>) -> Self { 31 pub fn new(pin: Peri<'d, if_afio!(impl TimerPin<T, C, A>)>) -> Self {
31 critical_section::with(|_| { 32 critical_section::with(|_| {
32 pin.set_low(); 33 pin.set_low();
33 pin.set_as_af(pin.af_num(), AfType::input(Pull::None)); 34 set_as_af!(pin, AfType::input(Pull::None));
34 }); 35 });
35 QeiPin { 36 QeiPin {
36 _pin: pin.into(), 37 pin: pin.into(),
37 phantom: PhantomData, 38 phantom: PhantomData,
38 } 39 }
39 } 40 }
@@ -58,7 +59,12 @@ pub struct Qei<'d, T: GeneralInstance4Channel> {
58 59
59impl<'d, T: GeneralInstance4Channel> Qei<'d, T> { 60impl<'d, T: GeneralInstance4Channel> Qei<'d, T> {
60 /// Create a new quadrature decoder driver. 61 /// Create a new quadrature decoder driver.
61 pub fn new(tim: Peri<'d, T>, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self { 62 #[allow(unused)]
63 pub fn new<#[cfg(afio)] A>(
64 tim: Peri<'d, T>,
65 ch1: if_afio!(QeiPin<'d, T, Ch1, A>),
66 ch2: if_afio!(QeiPin<'d, T, Ch2, A>),
67 ) -> Self {
62 Self::new_inner(tim) 68 Self::new_inner(tim)
63 } 69 }
64 70
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs
index c04b1ab97..e6165e42b 100644
--- a/embassy-stm32/src/timer/simple_pwm.rs
+++ b/embassy-stm32/src/timer/simple_pwm.rs
@@ -14,9 +14,10 @@ use crate::Peri;
14/// PWM pin wrapper. 14/// PWM pin wrapper.
15/// 15///
16/// This wraps a pin to make it usable with PWM. 16/// This wraps a pin to make it usable with PWM.
17pub struct PwmPin<'d, T, C> { 17pub struct PwmPin<'d, T, C, #[cfg(afio)] A> {
18 _pin: Peri<'d, AnyPin>, 18 #[allow(unused)]
19 phantom: PhantomData<(T, C)>, 19 pub(crate) pin: Peri<'d, AnyPin>,
20 phantom: PhantomData<if_afio!((T, C, A))>,
20} 21}
21 22
22/// PWM pin config 23/// PWM pin config
@@ -34,33 +35,33 @@ pub struct PwmPinConfig {
34 pub pull: Pull, 35 pub pull: Pull,
35} 36}
36 37
37impl<'d, T: GeneralInstance4Channel, C: TimerChannel> PwmPin<'d, T, C> { 38impl<'d, T: GeneralInstance4Channel, C: TimerChannel, #[cfg(afio)] A> if_afio!(PwmPin<'d, T, C, A>) {
38 /// Create a new PWM pin instance. 39 /// Create a new PWM pin instance.
39 pub fn new(pin: Peri<'d, impl TimerPin<T, C>>, output_type: OutputType) -> Self { 40 pub fn new(pin: Peri<'d, if_afio!(impl TimerPin<T, C, A>)>, output_type: OutputType) -> Self {
40 critical_section::with(|_| { 41 critical_section::with(|_| {
41 pin.set_low(); 42 pin.set_low();
42 pin.set_as_af(pin.af_num(), AfType::output(output_type, Speed::VeryHigh)); 43 set_as_af!(pin, AfType::output(output_type, Speed::VeryHigh));
43 }); 44 });
44 PwmPin { 45 PwmPin {
45 _pin: pin.into(), 46 pin: pin.into(),
46 phantom: PhantomData, 47 phantom: PhantomData,
47 } 48 }
48 } 49 }
49 50
50 /// Create a new PWM pin instance with config. 51 /// Create a new PWM pin instance with a specific configuration.
51 pub fn new_with_config(pin: Peri<'d, impl TimerPin<T, C>>, pin_config: PwmPinConfig) -> Self { 52 pub fn new_with_config(pin: Peri<'d, if_afio!(impl TimerPin<T, C, A>)>, pin_config: PwmPinConfig) -> Self {
52 critical_section::with(|_| { 53 critical_section::with(|_| {
53 pin.set_low(); 54 pin.set_low();
54 pin.set_as_af( 55 #[cfg(gpio_v1)]
55 pin.af_num(), 56 set_as_af!(pin, AfType::output(pin_config.output_type, pin_config.speed));
56 #[cfg(gpio_v1)] 57 #[cfg(gpio_v2)]
57 AfType::output(pin_config.output_type, pin_config.speed), 58 set_as_af!(
58 #[cfg(gpio_v2)] 59 pin,
59 AfType::output_pull(pin_config.output_type, pin_config.speed, pin_config.pull), 60 AfType::output_pull(pin_config.output_type, pin_config.speed, pin_config.pull)
60 ); 61 );
61 }); 62 });
62 PwmPin { 63 PwmPin {
63 _pin: pin.into(), 64 pin: pin.into(),
64 phantom: PhantomData, 65 phantom: PhantomData,
65 } 66 }
66 } 67 }
@@ -178,12 +179,13 @@ pub struct SimplePwm<'d, T: GeneralInstance4Channel> {
178 179
179impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { 180impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
180 /// Create a new simple PWM driver. 181 /// Create a new simple PWM driver.
181 pub fn new( 182 #[allow(unused)]
183 pub fn new<#[cfg(afio)] A>(
182 tim: Peri<'d, T>, 184 tim: Peri<'d, T>,
183 _ch1: Option<PwmPin<'d, T, Ch1>>, 185 ch1: Option<if_afio!(PwmPin<'d, T, Ch1, A>)>,
184 _ch2: Option<PwmPin<'d, T, Ch2>>, 186 ch2: Option<if_afio!(PwmPin<'d, T, Ch2, A>)>,
185 _ch3: Option<PwmPin<'d, T, Ch3>>, 187 ch3: Option<if_afio!(PwmPin<'d, T, Ch3, A>)>,
186 _ch4: Option<PwmPin<'d, T, Ch4>>, 188 ch4: Option<if_afio!(PwmPin<'d, T, Ch4, A>)>,
187 freq: Hertz, 189 freq: Hertz,
188 counting_mode: CountingMode, 190 counting_mode: CountingMode,
189 ) -> Self { 191 ) -> Self {
diff --git a/embassy-stm32/src/tsc/pin_groups.rs b/embassy-stm32/src/tsc/pin_groups.rs
index 6f914a94e..84421f7ff 100644
--- a/embassy-stm32/src/tsc/pin_groups.rs
+++ b/embassy-stm32/src/tsc/pin_groups.rs
@@ -427,7 +427,7 @@ macro_rules! impl_set_io {
427 pub fn $method<Role: pin_roles::Role>(&mut self, pin: Peri<'d, impl $trait<T>>) -> IOPinWithRole<$group, Role> { 427 pub fn $method<Role: pin_roles::Role>(&mut self, pin: Peri<'d, impl $trait<T>>) -> IOPinWithRole<$group, Role> {
428 critical_section::with(|_| { 428 critical_section::with(|_| {
429 pin.set_low(); 429 pin.set_low();
430 pin.set_as_af(pin.af_num(), AfType::output(Role::output_type(), Speed::VeryHigh)); 430 set_as_af!(pin, AfType::output(Role::output_type(), Speed::VeryHigh));
431 let tsc_io_pin = trait_to_io_pin!($trait); 431 let tsc_io_pin = trait_to_io_pin!($trait);
432 let new_pin = Pin { 432 let new_pin = Pin {
433 _pin: pin.into(), 433 _pin: pin.into(),
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs
index 729440c46..890c8a80e 100644
--- a/embassy-stm32/src/usart/buffered.rs
+++ b/embassy-stm32/src/usart/buffered.rs
@@ -208,10 +208,10 @@ impl<'d> SetConfig for BufferedUartTx<'d> {
208 208
209impl<'d> BufferedUart<'d> { 209impl<'d> BufferedUart<'d> {
210 /// Create a new bidirectional buffered UART driver 210 /// Create a new bidirectional buffered UART driver
211 pub fn new<T: Instance>( 211 pub fn new<T: Instance, #[cfg(afio)] A>(
212 peri: Peri<'d, T>, 212 peri: Peri<'d, T>,
213 rx: Peri<'d, impl RxPin<T>>, 213 rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
214 tx: Peri<'d, impl TxPin<T>>, 214 tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
215 tx_buffer: &'d mut [u8], 215 tx_buffer: &'d mut [u8],
216 rx_buffer: &'d mut [u8], 216 rx_buffer: &'d mut [u8],
217 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 217 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@@ -231,12 +231,12 @@ impl<'d> BufferedUart<'d> {
231 } 231 }
232 232
233 /// Create a new bidirectional buffered UART driver with request-to-send and clear-to-send pins 233 /// Create a new bidirectional buffered UART driver with request-to-send and clear-to-send pins
234 pub fn new_with_rtscts<T: Instance>( 234 pub fn new_with_rtscts<T: Instance, #[cfg(afio)] A>(
235 peri: Peri<'d, T>, 235 peri: Peri<'d, T>,
236 rx: Peri<'d, impl RxPin<T>>, 236 rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
237 tx: Peri<'d, impl TxPin<T>>, 237 tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
238 rts: Peri<'d, impl RtsPin<T>>, 238 rts: Peri<'d, if_afio!(impl RtsPin<T, A>)>,
239 cts: Peri<'d, impl CtsPin<T>>, 239 cts: Peri<'d, if_afio!(impl CtsPin<T, A>)>,
240 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 240 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
241 tx_buffer: &'d mut [u8], 241 tx_buffer: &'d mut [u8],
242 rx_buffer: &'d mut [u8], 242 rx_buffer: &'d mut [u8],
@@ -256,11 +256,11 @@ impl<'d> BufferedUart<'d> {
256 } 256 }
257 257
258 /// Create a new bidirectional buffered UART driver with only the RTS pin as the DE pin 258 /// Create a new bidirectional buffered UART driver with only the RTS pin as the DE pin
259 pub fn new_with_rts_as_de<T: Instance>( 259 pub fn new_with_rts_as_de<T: Instance, #[cfg(afio)] A>(
260 peri: Peri<'d, T>, 260 peri: Peri<'d, T>,
261 rx: Peri<'d, impl RxPin<T>>, 261 rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
262 tx: Peri<'d, impl TxPin<T>>, 262 tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
263 rts: Peri<'d, impl RtsPin<T>>, 263 rts: Peri<'d, if_afio!(impl RtsPin<T, A>)>,
264 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 264 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
265 tx_buffer: &'d mut [u8], 265 tx_buffer: &'d mut [u8],
266 rx_buffer: &'d mut [u8], 266 rx_buffer: &'d mut [u8],
@@ -280,11 +280,11 @@ impl<'d> BufferedUart<'d> {
280 } 280 }
281 281
282 /// Create a new bidirectional buffered UART driver with only the request-to-send pin 282 /// Create a new bidirectional buffered UART driver with only the request-to-send pin
283 pub fn new_with_rts<T: Instance>( 283 pub fn new_with_rts<T: Instance, #[cfg(afio)] A>(
284 peri: Peri<'d, T>, 284 peri: Peri<'d, T>,
285 rx: Peri<'d, impl RxPin<T>>, 285 rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
286 tx: Peri<'d, impl TxPin<T>>, 286 tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
287 rts: Peri<'d, impl RtsPin<T>>, 287 rts: Peri<'d, if_afio!(impl RtsPin<T, A>)>,
288 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 288 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
289 tx_buffer: &'d mut [u8], 289 tx_buffer: &'d mut [u8],
290 rx_buffer: &'d mut [u8], 290 rx_buffer: &'d mut [u8],
@@ -305,11 +305,11 @@ impl<'d> BufferedUart<'d> {
305 305
306 /// Create a new bidirectional buffered UART driver with a driver-enable pin 306 /// Create a new bidirectional buffered UART driver with a driver-enable pin
307 #[cfg(not(any(usart_v1, usart_v2)))] 307 #[cfg(not(any(usart_v1, usart_v2)))]
308 pub fn new_with_de<T: Instance>( 308 pub fn new_with_de<T: Instance, #[cfg(afio)] A>(
309 peri: Peri<'d, T>, 309 peri: Peri<'d, T>,
310 rx: Peri<'d, impl RxPin<T>>, 310 rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
311 tx: Peri<'d, impl TxPin<T>>, 311 tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
312 de: Peri<'d, impl DePin<T>>, 312 de: Peri<'d, if_afio!(impl DePin<T, A>)>,
313 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 313 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
314 tx_buffer: &'d mut [u8], 314 tx_buffer: &'d mut [u8],
315 rx_buffer: &'d mut [u8], 315 rx_buffer: &'d mut [u8],
@@ -340,9 +340,9 @@ impl<'d> BufferedUart<'d> {
340 /// Apart from this, the communication protocol is similar to normal USART mode. Any conflict 340 /// Apart from this, the communication protocol is similar to normal USART mode. Any conflict
341 /// on the line must be managed by software (for instance by using a centralized arbiter). 341 /// on the line must be managed by software (for instance by using a centralized arbiter).
342 #[doc(alias("HDSEL"))] 342 #[doc(alias("HDSEL"))]
343 pub fn new_half_duplex<T: Instance>( 343 pub fn new_half_duplex<T: Instance, #[cfg(afio)] A>(
344 peri: Peri<'d, T>, 344 peri: Peri<'d, T>,
345 tx: Peri<'d, impl TxPin<T>>, 345 tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
346 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 346 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
347 tx_buffer: &'d mut [u8], 347 tx_buffer: &'d mut [u8],
348 rx_buffer: &'d mut [u8], 348 rx_buffer: &'d mut [u8],
@@ -379,9 +379,9 @@ impl<'d> BufferedUart<'d> {
379 /// on the line must be managed by software (for instance by using a centralized arbiter). 379 /// on the line must be managed by software (for instance by using a centralized arbiter).
380 #[cfg(not(any(usart_v1, usart_v2)))] 380 #[cfg(not(any(usart_v1, usart_v2)))]
381 #[doc(alias("HDSEL"))] 381 #[doc(alias("HDSEL"))]
382 pub fn new_half_duplex_on_rx<T: Instance>( 382 pub fn new_half_duplex_on_rx<T: Instance, #[cfg(afio)] A>(
383 peri: Peri<'d, T>, 383 peri: Peri<'d, T>,
384 rx: Peri<'d, impl RxPin<T>>, 384 rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
385 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 385 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
386 tx_buffer: &'d mut [u8], 386 tx_buffer: &'d mut [u8],
387 rx_buffer: &'d mut [u8], 387 rx_buffer: &'d mut [u8],
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index 3d95de897..ff211e0c9 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -429,9 +429,9 @@ impl<'d, M: Mode> SetConfig for UartRx<'d, M> {
429 429
430impl<'d> UartTx<'d, Async> { 430impl<'d> UartTx<'d, Async> {
431 /// Useful if you only want Uart Tx. It saves 1 pin and consumes a little less power. 431 /// Useful if you only want Uart Tx. It saves 1 pin and consumes a little less power.
432 pub fn new<T: Instance>( 432 pub fn new<T: Instance, #[cfg(afio)] A>(
433 peri: Peri<'d, T>, 433 peri: Peri<'d, T>,
434 tx: Peri<'d, impl TxPin<T>>, 434 tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
435 tx_dma: Peri<'d, impl TxDma<T>>, 435 tx_dma: Peri<'d, impl TxDma<T>>,
436 config: Config, 436 config: Config,
437 ) -> Result<Self, ConfigError> { 437 ) -> Result<Self, ConfigError> {
@@ -439,10 +439,10 @@ impl<'d> UartTx<'d, Async> {
439 } 439 }
440 440
441 /// Create a new tx-only UART with a clear-to-send pin 441 /// Create a new tx-only UART with a clear-to-send pin
442 pub fn new_with_cts<T: Instance>( 442 pub fn new_with_cts<T: Instance, #[cfg(afio)] A>(
443 peri: Peri<'d, T>, 443 peri: Peri<'d, T>,
444 tx: Peri<'d, impl TxPin<T>>, 444 tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
445 cts: Peri<'d, impl CtsPin<T>>, 445 cts: Peri<'d, if_afio!(impl CtsPin<T, A>)>,
446 tx_dma: Peri<'d, impl TxDma<T>>, 446 tx_dma: Peri<'d, impl TxDma<T>>,
447 config: Config, 447 config: Config,
448 ) -> Result<Self, ConfigError> { 448 ) -> Result<Self, ConfigError> {
@@ -482,19 +482,19 @@ impl<'d> UartTx<'d, Blocking> {
482 /// Create a new blocking tx-only UART with no hardware flow control. 482 /// Create a new blocking tx-only UART with no hardware flow control.
483 /// 483 ///
484 /// Useful if you only want Uart Tx. It saves 1 pin and consumes a little less power. 484 /// Useful if you only want Uart Tx. It saves 1 pin and consumes a little less power.
485 pub fn new_blocking<T: Instance>( 485 pub fn new_blocking<T: Instance, #[cfg(afio)] A>(
486 peri: Peri<'d, T>, 486 peri: Peri<'d, T>,
487 tx: Peri<'d, impl TxPin<T>>, 487 tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
488 config: Config, 488 config: Config,
489 ) -> Result<Self, ConfigError> { 489 ) -> Result<Self, ConfigError> {
490 Self::new_inner(peri, new_pin!(tx, config.tx_af()), None, None, config) 490 Self::new_inner(peri, new_pin!(tx, config.tx_af()), None, None, config)
491 } 491 }
492 492
493 /// Create a new blocking tx-only UART with a clear-to-send pin 493 /// Create a new blocking tx-only UART with a clear-to-send pin
494 pub fn new_blocking_with_cts<T: Instance>( 494 pub fn new_blocking_with_cts<T: Instance, #[cfg(afio)] A>(
495 peri: Peri<'d, T>, 495 peri: Peri<'d, T>,
496 tx: Peri<'d, impl TxPin<T>>, 496 tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
497 cts: Peri<'d, impl CtsPin<T>>, 497 cts: Peri<'d, if_afio!(impl CtsPin<T, A>)>,
498 config: Config, 498 config: Config,
499 ) -> Result<Self, ConfigError> { 499 ) -> Result<Self, ConfigError> {
500 Self::new_inner( 500 Self::new_inner(
@@ -662,10 +662,10 @@ impl<'d> UartRx<'d, Async> {
662 /// Create a new rx-only UART with no hardware flow control. 662 /// Create a new rx-only UART with no hardware flow control.
663 /// 663 ///
664 /// Useful if you only want Uart Rx. It saves 1 pin and consumes a little less power. 664 /// Useful if you only want Uart Rx. It saves 1 pin and consumes a little less power.
665 pub fn new<T: Instance>( 665 pub fn new<T: Instance, #[cfg(afio)] A>(
666 peri: Peri<'d, T>, 666 peri: Peri<'d, T>,
667 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 667 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
668 rx: Peri<'d, impl RxPin<T>>, 668 rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
669 rx_dma: Peri<'d, impl RxDma<T>>, 669 rx_dma: Peri<'d, impl RxDma<T>>,
670 config: Config, 670 config: Config,
671 ) -> Result<Self, ConfigError> { 671 ) -> Result<Self, ConfigError> {
@@ -673,11 +673,11 @@ impl<'d> UartRx<'d, Async> {
673 } 673 }
674 674
675 /// Create a new rx-only UART with a request-to-send pin 675 /// Create a new rx-only UART with a request-to-send pin
676 pub fn new_with_rts<T: Instance>( 676 pub fn new_with_rts<T: Instance, #[cfg(afio)] A>(
677 peri: Peri<'d, T>, 677 peri: Peri<'d, T>,
678 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 678 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
679 rx: Peri<'d, impl RxPin<T>>, 679 rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
680 rts: Peri<'d, impl RtsPin<T>>, 680 rts: Peri<'d, if_afio!(impl RtsPin<T, A>)>,
681 rx_dma: Peri<'d, impl RxDma<T>>, 681 rx_dma: Peri<'d, impl RxDma<T>>,
682 config: Config, 682 config: Config,
683 ) -> Result<Self, ConfigError> { 683 ) -> Result<Self, ConfigError> {
@@ -913,19 +913,19 @@ impl<'d> UartRx<'d, Blocking> {
913 /// Create a new rx-only UART with no hardware flow control. 913 /// Create a new rx-only UART with no hardware flow control.
914 /// 914 ///
915 /// Useful if you only want Uart Rx. It saves 1 pin and consumes a little less power. 915 /// Useful if you only want Uart Rx. It saves 1 pin and consumes a little less power.
916 pub fn new_blocking<T: Instance>( 916 pub fn new_blocking<T: Instance, #[cfg(afio)] A>(
917 peri: Peri<'d, T>, 917 peri: Peri<'d, T>,
918 rx: Peri<'d, impl RxPin<T>>, 918 rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
919 config: Config, 919 config: Config,
920 ) -> Result<Self, ConfigError> { 920 ) -> Result<Self, ConfigError> {
921 Self::new_inner(peri, new_pin!(rx, config.rx_af()), None, None, config) 921 Self::new_inner(peri, new_pin!(rx, config.rx_af()), None, None, config)
922 } 922 }
923 923
924 /// Create a new rx-only UART with a request-to-send pin 924 /// Create a new rx-only UART with a request-to-send pin
925 pub fn new_blocking_with_rts<T: Instance>( 925 pub fn new_blocking_with_rts<T: Instance, #[cfg(afio)] A>(
926 peri: Peri<'d, T>, 926 peri: Peri<'d, T>,
927 rx: Peri<'d, impl RxPin<T>>, 927 rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
928 rts: Peri<'d, impl RtsPin<T>>, 928 rts: Peri<'d, if_afio!(impl RtsPin<T, A>)>,
929 config: Config, 929 config: Config,
930 ) -> Result<Self, ConfigError> { 930 ) -> Result<Self, ConfigError> {
931 Self::new_inner( 931 Self::new_inner(
@@ -1109,10 +1109,10 @@ fn drop_tx_rx(info: &Info, state: &State) {
1109 1109
1110impl<'d> Uart<'d, Async> { 1110impl<'d> Uart<'d, Async> {
1111 /// Create a new bidirectional UART 1111 /// Create a new bidirectional UART
1112 pub fn new<T: Instance>( 1112 pub fn new<T: Instance, #[cfg(afio)] A>(
1113 peri: Peri<'d, T>, 1113 peri: Peri<'d, T>,
1114 rx: Peri<'d, impl RxPin<T>>, 1114 rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
1115 tx: Peri<'d, impl TxPin<T>>, 1115 tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
1116 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 1116 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
1117 tx_dma: Peri<'d, impl TxDma<T>>, 1117 tx_dma: Peri<'d, impl TxDma<T>>,
1118 rx_dma: Peri<'d, impl RxDma<T>>, 1118 rx_dma: Peri<'d, impl RxDma<T>>,
@@ -1132,13 +1132,13 @@ impl<'d> Uart<'d, Async> {
1132 } 1132 }
1133 1133
1134 /// Create a new bidirectional UART with request-to-send and clear-to-send pins 1134 /// Create a new bidirectional UART with request-to-send and clear-to-send pins
1135 pub fn new_with_rtscts<T: Instance>( 1135 pub fn new_with_rtscts<T: Instance, #[cfg(afio)] A>(
1136 peri: Peri<'d, T>, 1136 peri: Peri<'d, T>,
1137 rx: Peri<'d, impl RxPin<T>>, 1137 rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
1138 tx: Peri<'d, impl TxPin<T>>, 1138 tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
1139 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 1139 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
1140 rts: Peri<'d, impl RtsPin<T>>, 1140 rts: Peri<'d, if_afio!(impl RtsPin<T, A>)>,
1141 cts: Peri<'d, impl CtsPin<T>>, 1141 cts: Peri<'d, if_afio!(impl CtsPin<T, A>)>,
1142 tx_dma: Peri<'d, impl TxDma<T>>, 1142 tx_dma: Peri<'d, impl TxDma<T>>,
1143 rx_dma: Peri<'d, impl RxDma<T>>, 1143 rx_dma: Peri<'d, impl RxDma<T>>,
1144 config: Config, 1144 config: Config,
@@ -1158,12 +1158,12 @@ impl<'d> Uart<'d, Async> {
1158 1158
1159 #[cfg(not(any(usart_v1, usart_v2)))] 1159 #[cfg(not(any(usart_v1, usart_v2)))]
1160 /// Create a new bidirectional UART with a driver-enable pin 1160 /// Create a new bidirectional UART with a driver-enable pin
1161 pub fn new_with_de<T: Instance>( 1161 pub fn new_with_de<T: Instance, #[cfg(afio)] A>(
1162 peri: Peri<'d, T>, 1162 peri: Peri<'d, T>,
1163 rx: Peri<'d, impl RxPin<T>>, 1163 rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
1164 tx: Peri<'d, impl TxPin<T>>, 1164 tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
1165 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 1165 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
1166 de: Peri<'d, impl DePin<T>>, 1166 de: Peri<'d, if_afio!(impl DePin<T, A>)>,
1167 tx_dma: Peri<'d, impl TxDma<T>>, 1167 tx_dma: Peri<'d, impl TxDma<T>>,
1168 rx_dma: Peri<'d, impl RxDma<T>>, 1168 rx_dma: Peri<'d, impl RxDma<T>>,
1169 config: Config, 1169 config: Config,
@@ -1193,9 +1193,9 @@ impl<'d> Uart<'d, Async> {
1193 /// Apart from this, the communication protocol is similar to normal USART mode. Any conflict 1193 /// Apart from this, the communication protocol is similar to normal USART mode. Any conflict
1194 /// on the line must be managed by software (for instance by using a centralized arbiter). 1194 /// on the line must be managed by software (for instance by using a centralized arbiter).
1195 #[doc(alias("HDSEL"))] 1195 #[doc(alias("HDSEL"))]
1196 pub fn new_half_duplex<T: Instance>( 1196 pub fn new_half_duplex<T: Instance, #[cfg(afio)] A>(
1197 peri: Peri<'d, T>, 1197 peri: Peri<'d, T>,
1198 tx: Peri<'d, impl TxPin<T>>, 1198 tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
1199 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 1199 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
1200 tx_dma: Peri<'d, impl TxDma<T>>, 1200 tx_dma: Peri<'d, impl TxDma<T>>,
1201 rx_dma: Peri<'d, impl RxDma<T>>, 1201 rx_dma: Peri<'d, impl RxDma<T>>,
@@ -1232,9 +1232,9 @@ impl<'d> Uart<'d, Async> {
1232 /// on the line must be managed by software (for instance by using a centralized arbiter). 1232 /// on the line must be managed by software (for instance by using a centralized arbiter).
1233 #[cfg(not(any(usart_v1, usart_v2)))] 1233 #[cfg(not(any(usart_v1, usart_v2)))]
1234 #[doc(alias("HDSEL"))] 1234 #[doc(alias("HDSEL"))]
1235 pub fn new_half_duplex_on_rx<T: Instance>( 1235 pub fn new_half_duplex_on_rx<T: Instance, #[cfg(afio)] A>(
1236 peri: Peri<'d, T>, 1236 peri: Peri<'d, T>,
1237 rx: Peri<'d, impl RxPin<T>>, 1237 rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
1238 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 1238 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
1239 tx_dma: Peri<'d, impl TxDma<T>>, 1239 tx_dma: Peri<'d, impl TxDma<T>>,
1240 rx_dma: Peri<'d, impl RxDma<T>>, 1240 rx_dma: Peri<'d, impl RxDma<T>>,
@@ -1280,10 +1280,10 @@ impl<'d> Uart<'d, Async> {
1280 1280
1281impl<'d> Uart<'d, Blocking> { 1281impl<'d> Uart<'d, Blocking> {
1282 /// Create a new blocking bidirectional UART. 1282 /// Create a new blocking bidirectional UART.
1283 pub fn new_blocking<T: Instance>( 1283 pub fn new_blocking<T: Instance, #[cfg(afio)] A>(
1284 peri: Peri<'d, T>, 1284 peri: Peri<'d, T>,
1285 rx: Peri<'d, impl RxPin<T>>, 1285 rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
1286 tx: Peri<'d, impl TxPin<T>>, 1286 tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
1287 config: Config, 1287 config: Config,
1288 ) -> Result<Self, ConfigError> { 1288 ) -> Result<Self, ConfigError> {
1289 Self::new_inner( 1289 Self::new_inner(
@@ -1300,12 +1300,12 @@ impl<'d> Uart<'d, Blocking> {
1300 } 1300 }
1301 1301
1302 /// Create a new bidirectional UART with request-to-send and clear-to-send pins 1302 /// Create a new bidirectional UART with request-to-send and clear-to-send pins
1303 pub fn new_blocking_with_rtscts<T: Instance>( 1303 pub fn new_blocking_with_rtscts<T: Instance, #[cfg(afio)] A>(
1304 peri: Peri<'d, T>, 1304 peri: Peri<'d, T>,
1305 rx: Peri<'d, impl RxPin<T>>, 1305 rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
1306 tx: Peri<'d, impl TxPin<T>>, 1306 tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
1307 rts: Peri<'d, impl RtsPin<T>>, 1307 rts: Peri<'d, if_afio!(impl RtsPin<T, A>)>,
1308 cts: Peri<'d, impl CtsPin<T>>, 1308 cts: Peri<'d, if_afio!(impl CtsPin<T, A>)>,
1309 config: Config, 1309 config: Config,
1310 ) -> Result<Self, ConfigError> { 1310 ) -> Result<Self, ConfigError> {
1311 Self::new_inner( 1311 Self::new_inner(
@@ -1323,11 +1323,11 @@ impl<'d> Uart<'d, Blocking> {
1323 1323
1324 #[cfg(not(any(usart_v1, usart_v2)))] 1324 #[cfg(not(any(usart_v1, usart_v2)))]
1325 /// Create a new bidirectional UART with a driver-enable pin 1325 /// Create a new bidirectional UART with a driver-enable pin
1326 pub fn new_blocking_with_de<T: Instance>( 1326 pub fn new_blocking_with_de<T: Instance, #[cfg(afio)] A>(
1327 peri: Peri<'d, T>, 1327 peri: Peri<'d, T>,
1328 rx: Peri<'d, impl RxPin<T>>, 1328 rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
1329 tx: Peri<'d, impl TxPin<T>>, 1329 tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
1330 de: Peri<'d, impl DePin<T>>, 1330 de: Peri<'d, if_afio!(impl DePin<T, A>)>,
1331 config: Config, 1331 config: Config,
1332 ) -> Result<Self, ConfigError> { 1332 ) -> Result<Self, ConfigError> {
1333 Self::new_inner( 1333 Self::new_inner(
@@ -1354,9 +1354,9 @@ impl<'d> Uart<'d, Blocking> {
1354 /// Apart from this, the communication protocol is similar to normal USART mode. Any conflict 1354 /// Apart from this, the communication protocol is similar to normal USART mode. Any conflict
1355 /// on the line must be managed by software (for instance by using a centralized arbiter). 1355 /// on the line must be managed by software (for instance by using a centralized arbiter).
1356 #[doc(alias("HDSEL"))] 1356 #[doc(alias("HDSEL"))]
1357 pub fn new_blocking_half_duplex<T: Instance>( 1357 pub fn new_blocking_half_duplex<T: Instance, #[cfg(afio)] A>(
1358 peri: Peri<'d, T>, 1358 peri: Peri<'d, T>,
1359 tx: Peri<'d, impl TxPin<T>>, 1359 tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
1360 mut config: Config, 1360 mut config: Config,
1361 readback: HalfDuplexReadback, 1361 readback: HalfDuplexReadback,
1362 ) -> Result<Self, ConfigError> { 1362 ) -> Result<Self, ConfigError> {
@@ -1390,9 +1390,9 @@ impl<'d> Uart<'d, Blocking> {
1390 /// on the line must be managed by software (for instance by using a centralized arbiter). 1390 /// on the line must be managed by software (for instance by using a centralized arbiter).
1391 #[cfg(not(any(usart_v1, usart_v2)))] 1391 #[cfg(not(any(usart_v1, usart_v2)))]
1392 #[doc(alias("HDSEL"))] 1392 #[doc(alias("HDSEL"))]
1393 pub fn new_blocking_half_duplex_on_rx<T: Instance>( 1393 pub fn new_blocking_half_duplex_on_rx<T: Instance, #[cfg(afio)] A>(
1394 peri: Peri<'d, T>, 1394 peri: Peri<'d, T>,
1395 rx: Peri<'d, impl RxPin<T>>, 1395 rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
1396 mut config: Config, 1396 mut config: Config,
1397 readback: HalfDuplexReadback, 1397 readback: HalfDuplexReadback,
1398 ) -> Result<Self, ConfigError> { 1398 ) -> Result<Self, ConfigError> {
@@ -2055,12 +2055,12 @@ pub trait Instance: SealedInstance + PeripheralType + 'static + Send {
2055 type Interrupt: interrupt::typelevel::Interrupt; 2055 type Interrupt: interrupt::typelevel::Interrupt;
2056} 2056}
2057 2057
2058pin_trait!(RxPin, Instance); 2058pin_trait!(RxPin, Instance, @A);
2059pin_trait!(TxPin, Instance); 2059pin_trait!(TxPin, Instance, @A);
2060pin_trait!(CtsPin, Instance); 2060pin_trait!(CtsPin, Instance, @A);
2061pin_trait!(RtsPin, Instance); 2061pin_trait!(RtsPin, Instance, @A);
2062pin_trait!(CkPin, Instance); 2062pin_trait!(CkPin, Instance, @A);
2063pin_trait!(DePin, Instance); 2063pin_trait!(DePin, Instance, @A);
2064 2064
2065dma_trait!(TxDma, Instance); 2065dma_trait!(TxDma, Instance);
2066dma_trait!(RxDma, Instance); 2066dma_trait!(RxDma, Instance);
diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs
index 1c3b99b93..5ce81b131 100644
--- a/embassy-stm32/src/usb/otg.rs
+++ b/embassy-stm32/src/usb/otg.rs
@@ -34,7 +34,7 @@ macro_rules! config_ulpi_pins {
34 ($($pin:ident),*) => { 34 ($($pin:ident),*) => {
35 critical_section::with(|_| { 35 critical_section::with(|_| {
36 $( 36 $(
37 $pin.set_as_af($pin.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); 37 set_as_af!($pin, AfType::output(OutputType::PushPull, Speed::VeryHigh));
38 )* 38 )*
39 }) 39 })
40 }; 40 };
@@ -68,8 +68,8 @@ impl<'d, T: Instance> Driver<'d, T> {
68 ep_out_buffer: &'d mut [u8], 68 ep_out_buffer: &'d mut [u8],
69 config: Config, 69 config: Config,
70 ) -> Self { 70 ) -> Self {
71 dp.set_as_af(dp.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); 71 set_as_af!(dp, AfType::output(OutputType::PushPull, Speed::VeryHigh));
72 dm.set_as_af(dm.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); 72 set_as_af!(dm, AfType::output(OutputType::PushPull, Speed::VeryHigh));
73 73
74 let regs = T::regs(); 74 let regs = T::regs();
75 75
@@ -107,8 +107,8 @@ impl<'d, T: Instance> Driver<'d, T> {
107 // For STM32U5 High speed pins need to be left in analog mode 107 // For STM32U5 High speed pins need to be left in analog mode
108 #[cfg(not(any(all(stm32u5, peri_usb_otg_hs), all(stm32wba, peri_usb_otg_hs))))] 108 #[cfg(not(any(all(stm32u5, peri_usb_otg_hs), all(stm32wba, peri_usb_otg_hs))))]
109 { 109 {
110 _dp.set_as_af(_dp.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); 110 set_as_af!(_dp, AfType::output(OutputType::PushPull, Speed::VeryHigh));
111 _dm.set_as_af(_dm.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); 111 set_as_af!(_dm, AfType::output(OutputType::PushPull, Speed::VeryHigh));
112 } 112 }
113 113
114 let instance = OtgInstance { 114 let instance = OtgInstance {
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs
index 54596aeae..9e08d99b3 100644
--- a/embassy-stm32/src/usb/usb.rs
+++ b/embassy-stm32/src/usb/usb.rs
@@ -298,7 +298,7 @@ impl<'d, T: Instance> Driver<'d, T> {
298 ) -> Self { 298 ) -> Self {
299 { 299 {
300 use crate::gpio::{AfType, OutputType, Speed}; 300 use crate::gpio::{AfType, OutputType, Speed};
301 sof.set_as_af(sof.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); 301 set_as_af!(sof, AfType::output(OutputType::PushPull, Speed::VeryHigh));
302 } 302 }
303 303
304 Self::new(_usb, _irq, dp, dm) 304 Self::new(_usb, _irq, dp, dm)
@@ -329,8 +329,8 @@ impl<'d, T: Instance> Driver<'d, T> {
329 #[cfg(not(stm32l1))] 329 #[cfg(not(stm32l1))]
330 { 330 {
331 use crate::gpio::{AfType, OutputType, Speed}; 331 use crate::gpio::{AfType, OutputType, Speed};
332 dp.set_as_af(dp.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); 332 set_as_af!(dp, AfType::output(OutputType::PushPull, Speed::VeryHigh));
333 dm.set_as_af(dm.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); 333 set_as_af!(dm, AfType::output(OutputType::PushPull, Speed::VeryHigh));
334 } 334 }
335 #[cfg(stm32l1)] 335 #[cfg(stm32l1)]
336 let _ = (dp, dm); // suppress "unused" warnings. 336 let _ = (dp, dm); // suppress "unused" warnings.
diff --git a/examples/stm32f1/src/bin/input_capture.rs b/examples/stm32f1/src/bin/input_capture.rs
index d747a43c2..b5b26938d 100644
--- a/examples/stm32f1/src/bin/input_capture.rs
+++ b/examples/stm32f1/src/bin/input_capture.rs
@@ -3,7 +3,7 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::gpio::{Level, Output, Pull, Speed}; 6use embassy_stm32::gpio::{AfioRemap, Level, Output, Pull, Speed};
7use embassy_stm32::time::khz; 7use embassy_stm32::time::khz;
8use embassy_stm32::timer::input_capture::{CapturePin, InputCapture}; 8use embassy_stm32::timer::input_capture::{CapturePin, InputCapture};
9use embassy_stm32::timer::{self, Channel}; 9use embassy_stm32::timer::{self, Channel};
@@ -40,7 +40,8 @@ async fn main(spawner: Spawner) {
40 spawner.spawn(unwrap!(blinky(p.PC13))); 40 spawner.spawn(unwrap!(blinky(p.PC13)));
41 41
42 let ch3 = CapturePin::new(p.PA2, Pull::None); 42 let ch3 = CapturePin::new(p.PA2, Pull::None);
43 let mut ic = InputCapture::new(p.TIM2, None, None, Some(ch3), None, Irqs, khz(1000), Default::default()); 43 let mut ic =
44 InputCapture::new::<AfioRemap<0>>(p.TIM2, None, None, Some(ch3), None, Irqs, khz(1000), Default::default());
44 45
45 loop { 46 loop {
46 info!("wait for rising edge"); 47 info!("wait for rising edge");
diff --git a/examples/stm32f1/src/bin/pwm_input.rs b/examples/stm32f1/src/bin/pwm_input.rs
index 63b899767..9ae747018 100644
--- a/examples/stm32f1/src/bin/pwm_input.rs
+++ b/examples/stm32f1/src/bin/pwm_input.rs
@@ -3,7 +3,7 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::gpio::{Level, Output, Pull, Speed}; 6use embassy_stm32::gpio::{AfioRemap, Level, Output, Pull, Speed};
7use embassy_stm32::time::khz; 7use embassy_stm32::time::khz;
8use embassy_stm32::timer::pwm_input::PwmInput; 8use embassy_stm32::timer::pwm_input::PwmInput;
9use embassy_stm32::{bind_interrupts, peripherals, timer, Peri}; 9use embassy_stm32::{bind_interrupts, peripherals, timer, Peri};
@@ -38,7 +38,7 @@ async fn main(spawner: Spawner) {
38 38
39 spawner.spawn(unwrap!(blinky(p.PC13))); 39 spawner.spawn(unwrap!(blinky(p.PC13)));
40 40
41 let mut pwm_input = PwmInput::new_ch1(p.TIM2, p.PA0, Pull::None, khz(10)); 41 let mut pwm_input = PwmInput::new_ch1::<AfioRemap<0>>(p.TIM2, p.PA0, Pull::None, khz(10));
42 pwm_input.enable(); 42 pwm_input.enable();
43 43
44 loop { 44 loop {
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml
index aeca67659..891ec93fd 100644
--- a/tests/stm32/Cargo.toml
+++ b/tests/stm32/Cargo.toml
@@ -9,7 +9,9 @@ publish = false
9[features] 9[features]
10stm32c031c6 = ["embassy-stm32/stm32c031c6", "cm0", "not-gpdma"] 10stm32c031c6 = ["embassy-stm32/stm32c031c6", "cm0", "not-gpdma"]
11stm32c071rb = ["embassy-stm32/stm32c071rb", "cm0", "not-gpdma"] 11stm32c071rb = ["embassy-stm32/stm32c071rb", "cm0", "not-gpdma"]
12stm32f103c8 = ["embassy-stm32/stm32f103c8", "spi-v1", "not-gpdma"] 12stm32f100rd = ["embassy-stm32/stm32f100rd", "spi-v1", "not-gpdma", "afio", "afio-value-line"]
13stm32f103c8 = ["embassy-stm32/stm32f103c8", "spi-v1", "not-gpdma", "afio"]
14stm32f107vc = ["embassy-stm32/stm32f107vc", "spi-v1", "not-gpdma", "afio", "afio-connectivity-line"]
13stm32f207zg = ["embassy-stm32/stm32f207zg", "spi-v1", "chrono", "not-gpdma", "eth", "rng"] 15stm32f207zg = ["embassy-stm32/stm32f207zg", "spi-v1", "chrono", "not-gpdma", "eth", "rng"]
14stm32f303ze = ["embassy-stm32/stm32f303ze", "chrono", "not-gpdma"] 16stm32f303ze = ["embassy-stm32/stm32f303ze", "chrono", "not-gpdma"]
15stm32f429zi = ["embassy-stm32/stm32f429zi", "spi-v1", "chrono", "eth", "stop", "can", "not-gpdma", "dac", "rng"] 17stm32f429zi = ["embassy-stm32/stm32f429zi", "spi-v1", "chrono", "eth", "stop", "can", "not-gpdma", "dac", "rng"]
@@ -59,6 +61,9 @@ cordic = ["dep:num-traits"]
59dual-bank = ["embassy-stm32/dual-bank"] 61dual-bank = ["embassy-stm32/dual-bank"]
60single-bank = ["embassy-stm32/single-bank"] 62single-bank = ["embassy-stm32/single-bank"]
61eeprom = [] 63eeprom = []
64afio = []
65afio-connectivity-line = []
66afio-value-line = []
62 67
63cm0 = ["portable-atomic/unsafe-assume-single-core"] 68cm0 = ["portable-atomic/unsafe-assume-single-core"]
64 69
@@ -99,6 +104,11 @@ num-traits = { version="0.2", default-features = false,features = ["libm"], opti
99# BEGIN TESTS 104# BEGIN TESTS
100# Generated by gen_test.py. DO NOT EDIT. 105# Generated by gen_test.py. DO NOT EDIT.
101[[bin]] 106[[bin]]
107name = "afio"
108path = "src/bin/afio.rs"
109required-features = [ "afio",]
110
111[[bin]]
102name = "can" 112name = "can"
103path = "src/bin/can.rs" 113path = "src/bin/can.rs"
104required-features = [ "can",] 114required-features = [ "can",]
diff --git a/tests/stm32/src/bin/afio.rs b/tests/stm32/src/bin/afio.rs
new file mode 100644
index 000000000..cc44dc59c
--- /dev/null
+++ b/tests/stm32/src/bin/afio.rs
@@ -0,0 +1,1156 @@
1// required-features: afio
2#![no_std]
3#![no_main]
4#[path = "../common.rs"]
5mod common;
6
7use common::*;
8use embassy_executor::Spawner;
9use embassy_stm32::gpio::{AfioRemap, OutputType, Pull};
10use embassy_stm32::pac::AFIO;
11use embassy_stm32::time::khz;
12use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin};
13use embassy_stm32::timer::input_capture::{CapturePin, InputCapture};
14use embassy_stm32::timer::pwm_input::PwmInput;
15use embassy_stm32::timer::qei::{Qei, QeiPin};
16use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm};
17use embassy_stm32::usart::{Uart, UartRx, UartTx};
18use embassy_stm32::{bind_interrupts, Peripherals};
19
20#[cfg(not(feature = "afio-connectivity-line"))]
21bind_interrupts!(struct Irqs {
22 USART3 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART3>;
23 TIM1_CC => embassy_stm32::timer::CaptureCompareInterruptHandler<embassy_stm32::peripherals::TIM1>;
24});
25
26#[cfg(feature = "afio-connectivity-line")]
27bind_interrupts!(struct Irqs {
28 CAN1_RX0 => embassy_stm32::can::Rx0InterruptHandler<embassy_stm32::peripherals::CAN1>;
29 CAN1_RX1 => embassy_stm32::can::Rx1InterruptHandler<embassy_stm32::peripherals::CAN1>;
30 CAN1_SCE => embassy_stm32::can::SceInterruptHandler<embassy_stm32::peripherals::CAN1>;
31 CAN1_TX => embassy_stm32::can::TxInterruptHandler<embassy_stm32::peripherals::CAN1>;
32
33 CAN2_RX0 => embassy_stm32::can::Rx0InterruptHandler<embassy_stm32::peripherals::CAN2>;
34 CAN2_RX1 => embassy_stm32::can::Rx1InterruptHandler<embassy_stm32::peripherals::CAN2>;
35 CAN2_SCE => embassy_stm32::can::SceInterruptHandler<embassy_stm32::peripherals::CAN2>;
36 CAN2_TX => embassy_stm32::can::TxInterruptHandler<embassy_stm32::peripherals::CAN2>;
37
38 ETH => embassy_stm32::eth::InterruptHandler;
39 USART3 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART3>;
40 TIM1_CC => embassy_stm32::timer::CaptureCompareInterruptHandler<embassy_stm32::peripherals::TIM1>;
41});
42
43#[embassy_executor::main]
44async fn main(_spawner: Spawner) {
45 let mut p = init();
46 info!("Hello World!");
47
48 // USART3
49 {
50 // no remap RX/TX/RTS/CTS
51 afio_registers_set_remap();
52 Uart::new_blocking_with_rtscts(
53 p.USART3.reborrow(),
54 p.PB11.reborrow(),
55 p.PB10.reborrow(),
56 p.PB14.reborrow(),
57 p.PB13.reborrow(),
58 Default::default(),
59 )
60 .unwrap();
61 defmt::assert_eq!(AFIO.mapr().read().usart3_remap(), 0);
62 }
63 {
64 // no remap RX/TX
65 afio_registers_set_remap();
66 Uart::new_blocking(
67 p.USART3.reborrow(),
68 p.PB11.reborrow(),
69 p.PB10.reborrow(),
70 Default::default(),
71 )
72 .unwrap();
73 defmt::assert_eq!(AFIO.mapr().read().usart3_remap(), 0);
74 }
75 {
76 // no remap TX
77 afio_registers_set_remap();
78 Uart::new_blocking_half_duplex(
79 p.USART3.reborrow(),
80 p.PB10.reborrow(),
81 Default::default(),
82 embassy_stm32::usart::HalfDuplexReadback::NoReadback,
83 )
84 .unwrap();
85 defmt::assert_eq!(AFIO.mapr().read().usart3_remap(), 0);
86 }
87 {
88 // no remap TX async
89 afio_registers_set_remap();
90 UartTx::new(
91 p.USART3.reborrow(),
92 p.PB10.reborrow(),
93 p.DMA1_CH2.reborrow(),
94 Default::default(),
95 )
96 .unwrap();
97 defmt::assert_eq!(AFIO.mapr().read().usart3_remap(), 0);
98 }
99 {
100 // no remap TX/CTS async
101 afio_registers_set_remap();
102 UartTx::new_with_cts(
103 p.USART3.reborrow(),
104 p.PB10.reborrow(),
105 p.PB13.reborrow(),
106 p.DMA1_CH2.reborrow(),
107 Default::default(),
108 )
109 .unwrap();
110 defmt::assert_eq!(AFIO.mapr().read().usart3_remap(), 0);
111 }
112 {
113 // no remap RX async
114 afio_registers_set_remap();
115 UartRx::new(
116 p.USART3.reborrow(),
117 Irqs,
118 p.PB11.reborrow(),
119 p.DMA1_CH3.reborrow(),
120 Default::default(),
121 )
122 .unwrap();
123 defmt::assert_eq!(AFIO.mapr().read().usart3_remap(), 0);
124 }
125 {
126 // no remap RX async
127 afio_registers_set_remap();
128 UartRx::new_with_rts(
129 p.USART3.reborrow(),
130 Irqs,
131 p.PB11.reborrow(),
132 p.PB14.reborrow(),
133 p.DMA1_CH3.reborrow(),
134 Default::default(),
135 )
136 .unwrap();
137 defmt::assert_eq!(AFIO.mapr().read().usart3_remap(), 0);
138 }
139 {
140 // no remap RX/TX async
141 afio_registers_set_remap();
142 Uart::new(
143 p.USART3.reborrow(),
144 p.PB11.reborrow(),
145 p.PB10.reborrow(),
146 Irqs,
147 p.DMA1_CH2.reborrow(),
148 p.DMA1_CH3.reborrow(),
149 Default::default(),
150 )
151 .unwrap();
152 defmt::assert_eq!(AFIO.mapr().read().usart3_remap(), 0);
153 }
154 {
155 // no remap RX/TX/RTS/CTS async
156 afio_registers_set_remap();
157 Uart::new_with_rtscts(
158 p.USART3.reborrow(),
159 p.PB11.reborrow(),
160 p.PB10.reborrow(),
161 Irqs,
162 p.PB14.reborrow(),
163 p.PB13.reborrow(),
164 p.DMA1_CH2.reborrow(),
165 p.DMA1_CH3.reborrow(),
166 Default::default(),
167 )
168 .unwrap();
169 defmt::assert_eq!(AFIO.mapr().read().usart3_remap(), 0);
170 }
171
172 // TIM1
173 {
174 // no remap
175 afio_registers_set_remap();
176 SimplePwm::new::<AfioRemap<0>>(
177 p.TIM1.reborrow(),
178 Some(PwmPin::new(p.PA8.reborrow(), OutputType::PushPull)),
179 Some(PwmPin::new(p.PA9.reborrow(), OutputType::PushPull)),
180 Some(PwmPin::new(p.PA10.reborrow(), OutputType::PushPull)),
181 Some(PwmPin::new(p.PA11.reborrow(), OutputType::PushPull)),
182 khz(10),
183 Default::default(),
184 );
185 defmt::assert_eq!(AFIO.mapr().read().tim1_remap(), 0);
186 }
187 {
188 // no remap
189 afio_registers_set_remap();
190 SimplePwm::new::<AfioRemap<0>>(
191 p.TIM1.reborrow(),
192 Some(PwmPin::new(p.PA8.reborrow(), OutputType::PushPull)),
193 None,
194 None,
195 None,
196 khz(10),
197 Default::default(),
198 );
199 defmt::assert_eq!(AFIO.mapr().read().tim1_remap(), 0);
200 }
201 {
202 // partial remap
203 reset_afio_registers();
204 ComplementaryPwm::new::<AfioRemap<1>>(
205 p.TIM1.reborrow(),
206 Some(PwmPin::new(p.PA8.reborrow(), OutputType::PushPull)),
207 None,
208 None,
209 None,
210 None,
211 None,
212 None,
213 None,
214 khz(10),
215 Default::default(),
216 );
217 defmt::assert_eq!(AFIO.mapr().read().tim1_remap(), 1);
218 }
219 {
220 // partial remap
221 reset_afio_registers();
222 ComplementaryPwm::new::<AfioRemap<1>>(
223 p.TIM1.reborrow(),
224 Some(PwmPin::new(p.PA8.reborrow(), OutputType::PushPull)),
225 Some(ComplementaryPwmPin::new(p.PA7.reborrow(), OutputType::PushPull)),
226 Some(PwmPin::new(p.PA9.reborrow(), OutputType::PushPull)),
227 Some(ComplementaryPwmPin::new(p.PB0.reborrow(), OutputType::PushPull)),
228 Some(PwmPin::new(p.PA10.reborrow(), OutputType::PushPull)),
229 None, // pin does not exist on medium-density devices
230 Some(PwmPin::new(p.PA11.reborrow(), OutputType::PushPull)),
231 None, // signal does not exist
232 khz(10),
233 Default::default(),
234 );
235 defmt::assert_eq!(AFIO.mapr().read().tim1_remap(), 1);
236 }
237 {
238 // partial remap
239 reset_afio_registers();
240 InputCapture::new::<AfioRemap<1>>(
241 p.TIM1.reborrow(),
242 Some(CapturePin::new(p.PA8.reborrow(), Pull::Down)),
243 None,
244 None,
245 None,
246 Irqs,
247 khz(10),
248 Default::default(),
249 );
250 defmt::assert_eq!(AFIO.mapr().read().tim1_remap(), 1);
251 }
252 {
253 // partial remap
254 reset_afio_registers();
255 PwmInput::new_ch1::<AfioRemap<1>>(p.TIM1.reborrow(), p.PA8.reborrow(), Pull::Down, khz(10));
256 defmt::assert_eq!(AFIO.mapr().read().tim1_remap(), 1);
257 }
258 {
259 // partial remap
260 reset_afio_registers();
261 Qei::new::<AfioRemap<1>>(
262 p.TIM1.reborrow(),
263 QeiPin::new(p.PA8.reborrow()),
264 QeiPin::new(p.PA9.reborrow()),
265 );
266 defmt::assert_eq!(AFIO.mapr().read().tim1_remap(), 1);
267 }
268
269 // TIM2
270 {
271 // no remap
272 afio_registers_set_remap();
273 SimplePwm::new::<AfioRemap<0>>(
274 p.TIM2.reborrow(),
275 Some(PwmPin::new(p.PA0.reborrow(), OutputType::PushPull)),
276 Some(PwmPin::new(p.PA1.reborrow(), OutputType::PushPull)),
277 Some(PwmPin::new(p.PA2.reborrow(), OutputType::PushPull)),
278 Some(PwmPin::new(p.PA3.reborrow(), OutputType::PushPull)),
279 khz(10),
280 Default::default(),
281 );
282 defmt::assert_eq!(AFIO.mapr().read().tim2_remap(), 0);
283 }
284 {
285 // partial remap 1
286 reset_afio_registers();
287 SimplePwm::new::<AfioRemap<1>>(
288 p.TIM2.reborrow(),
289 Some(PwmPin::new(p.PA15.reborrow(), OutputType::PushPull)),
290 Some(PwmPin::new(p.PB3.reborrow(), OutputType::PushPull)),
291 Some(PwmPin::new(p.PA2.reborrow(), OutputType::PushPull)),
292 Some(PwmPin::new(p.PA3.reborrow(), OutputType::PushPull)),
293 khz(10),
294 Default::default(),
295 );
296 defmt::assert_eq!(AFIO.mapr().read().tim2_remap(), 1);
297 }
298 {
299 // partial remap 2
300 reset_afio_registers();
301 SimplePwm::new::<AfioRemap<2>>(
302 p.TIM2.reborrow(),
303 Some(PwmPin::new(p.PA0.reborrow(), OutputType::PushPull)),
304 Some(PwmPin::new(p.PA1.reborrow(), OutputType::PushPull)),
305 Some(PwmPin::new(p.PB10.reborrow(), OutputType::PushPull)),
306 Some(PwmPin::new(p.PB11.reborrow(), OutputType::PushPull)),
307 khz(10),
308 Default::default(),
309 );
310 defmt::assert_eq!(AFIO.mapr().read().tim2_remap(), 2);
311 }
312 {
313 // full remap
314 reset_afio_registers();
315 SimplePwm::new::<AfioRemap<3>>(
316 p.TIM2.reborrow(),
317 Some(PwmPin::new(p.PA15.reborrow(), OutputType::PushPull)),
318 Some(PwmPin::new(p.PB3.reborrow(), OutputType::PushPull)),
319 Some(PwmPin::new(p.PB10.reborrow(), OutputType::PushPull)),
320 Some(PwmPin::new(p.PB11.reborrow(), OutputType::PushPull)),
321 khz(10),
322 Default::default(),
323 );
324 defmt::assert_eq!(AFIO.mapr().read().tim2_remap(), 3);
325 }
326
327 connectivity_line::run(&mut p);
328 value_line::run(&mut p);
329
330 info!("Test OK");
331 cortex_m::asm::bkpt();
332}
333
334#[cfg(feature = "afio-connectivity-line")]
335mod connectivity_line {
336 use embassy_stm32::can::Can;
337 use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue};
338 use embassy_stm32::i2s::I2S;
339 use embassy_stm32::spi::Spi;
340
341 use super::*;
342
343 pub fn run(p: &mut Peripherals) {
344 // USART3
345 {
346 // partial remap RX/TX/RTS/CTS
347 reset_afio_registers();
348 Uart::new_blocking_with_rtscts(
349 p.USART3.reborrow(),
350 p.PC11.reborrow(),
351 p.PC10.reborrow(),
352 p.PB14.reborrow(),
353 p.PB13.reborrow(),
354 Default::default(),
355 )
356 .unwrap();
357 defmt::assert_eq!(AFIO.mapr().read().usart3_remap(), 1);
358 }
359 {
360 // partial remap RX/TX
361 reset_afio_registers();
362 Uart::new_blocking(
363 p.USART3.reborrow(),
364 p.PC11.reborrow(),
365 p.PC10.reborrow(),
366 Default::default(),
367 )
368 .unwrap();
369 defmt::assert_eq!(AFIO.mapr().read().usart3_remap(), 1);
370 }
371 {
372 // partial remap TX
373 reset_afio_registers();
374 Uart::new_blocking_half_duplex(
375 p.USART3.reborrow(),
376 p.PC10.reborrow(),
377 Default::default(),
378 embassy_stm32::usart::HalfDuplexReadback::NoReadback,
379 )
380 .unwrap();
381 defmt::assert_eq!(AFIO.mapr().read().usart3_remap(), 1);
382 }
383 {
384 // partial remap TX async
385 reset_afio_registers();
386 UartTx::new(
387 p.USART3.reborrow(),
388 p.PC10.reborrow(),
389 p.DMA1_CH2.reborrow(),
390 Default::default(),
391 )
392 .unwrap();
393 defmt::assert_eq!(AFIO.mapr().read().usart3_remap(), 1);
394 }
395 {
396 // partial remap TX/CTS async
397 reset_afio_registers();
398 UartTx::new_with_cts(
399 p.USART3.reborrow(),
400 p.PC10.reborrow(),
401 p.PB13.reborrow(),
402 p.DMA1_CH2.reborrow(),
403 Default::default(),
404 )
405 .unwrap();
406 defmt::assert_eq!(AFIO.mapr().read().usart3_remap(), 1);
407 }
408 {
409 // partial remap RX async
410 reset_afio_registers();
411 UartRx::new(
412 p.USART3.reborrow(),
413 Irqs,
414 p.PC11.reborrow(),
415 p.DMA1_CH3.reborrow(),
416 Default::default(),
417 )
418 .unwrap();
419 defmt::assert_eq!(AFIO.mapr().read().usart3_remap(), 1);
420 }
421 {
422 // partial remap RX async
423 reset_afio_registers();
424 UartRx::new_with_rts(
425 p.USART3.reborrow(),
426 Irqs,
427 p.PC11.reborrow(),
428 p.PB14.reborrow(),
429 p.DMA1_CH3.reborrow(),
430 Default::default(),
431 )
432 .unwrap();
433 defmt::assert_eq!(AFIO.mapr().read().usart3_remap(), 1);
434 }
435 {
436 // partial remap RX/TX async
437 reset_afio_registers();
438 Uart::new(
439 p.USART3.reborrow(),
440 p.PC11.reborrow(),
441 p.PC10.reborrow(),
442 Irqs,
443 p.DMA1_CH2.reborrow(),
444 p.DMA1_CH3.reborrow(),
445 Default::default(),
446 )
447 .unwrap();
448 defmt::assert_eq!(AFIO.mapr().read().usart3_remap(), 1);
449 }
450 {
451 // partial remap RX/TX/RTS/CTS async
452 reset_afio_registers();
453 Uart::new_with_rtscts(
454 p.USART3.reborrow(),
455 p.PC11.reborrow(),
456 p.PC10.reborrow(),
457 Irqs,
458 p.PB14.reborrow(),
459 p.PB13.reborrow(),
460 p.DMA1_CH2.reborrow(),
461 p.DMA1_CH3.reborrow(),
462 Default::default(),
463 )
464 .unwrap();
465 defmt::assert_eq!(AFIO.mapr().read().usart3_remap(), 1);
466 }
467 {
468 // full remap RX/TX/RTS/CTS
469 reset_afio_registers();
470 Uart::new_blocking_with_rtscts(
471 p.USART3.reborrow(),
472 p.PD9.reborrow(),
473 p.PD8.reborrow(),
474 p.PD12.reborrow(),
475 p.PD11.reborrow(),
476 Default::default(),
477 )
478 .unwrap();
479 defmt::assert_eq!(AFIO.mapr().read().usart3_remap(), 3);
480 }
481 {
482 // full remap RX/TX
483 reset_afio_registers();
484 Uart::new_blocking(
485 p.USART3.reborrow(),
486 p.PD9.reborrow(),
487 p.PD8.reborrow(),
488 Default::default(),
489 )
490 .unwrap();
491 defmt::assert_eq!(AFIO.mapr().read().usart3_remap(), 3);
492 }
493 {
494 // full remap TX
495 reset_afio_registers();
496 Uart::new_blocking_half_duplex(
497 p.USART3.reborrow(),
498 p.PD8.reborrow(),
499 Default::default(),
500 embassy_stm32::usart::HalfDuplexReadback::NoReadback,
501 )
502 .unwrap();
503 defmt::assert_eq!(AFIO.mapr().read().usart3_remap(), 3);
504 }
505 {
506 // full remap TX async
507 reset_afio_registers();
508 UartTx::new(
509 p.USART3.reborrow(),
510 p.PD8.reborrow(),
511 p.DMA1_CH2.reborrow(),
512 Default::default(),
513 )
514 .unwrap();
515 defmt::assert_eq!(AFIO.mapr().read().usart3_remap(), 3);
516 }
517 {
518 // full remap TX/CTS async
519 reset_afio_registers();
520 UartTx::new_with_cts(
521 p.USART3.reborrow(),
522 p.PD8.reborrow(),
523 p.PD11.reborrow(),
524 p.DMA1_CH2.reborrow(),
525 Default::default(),
526 )
527 .unwrap();
528 defmt::assert_eq!(AFIO.mapr().read().usart3_remap(), 3);
529 }
530 {
531 // full remap RX async
532 reset_afio_registers();
533 UartRx::new(
534 p.USART3.reborrow(),
535 Irqs,
536 p.PD9.reborrow(),
537 p.DMA1_CH3.reborrow(),
538 Default::default(),
539 )
540 .unwrap();
541 defmt::assert_eq!(AFIO.mapr().read().usart3_remap(), 3);
542 }
543 {
544 // full remap RX async
545 reset_afio_registers();
546 UartRx::new_with_rts(
547 p.USART3.reborrow(),
548 Irqs,
549 p.PD9.reborrow(),
550 p.PD12.reborrow(),
551 p.DMA1_CH3.reborrow(),
552 Default::default(),
553 )
554 .unwrap();
555 defmt::assert_eq!(AFIO.mapr().read().usart3_remap(), 3);
556 }
557 {
558 // full remap RX/TX async
559 reset_afio_registers();
560 Uart::new(
561 p.USART3.reborrow(),
562 p.PD9.reborrow(),
563 p.PD8.reborrow(),
564 Irqs,
565 p.DMA1_CH2.reborrow(),
566 p.DMA1_CH3.reborrow(),
567 Default::default(),
568 )
569 .unwrap();
570 defmt::assert_eq!(AFIO.mapr().read().usart3_remap(), 3);
571 }
572 {
573 // full remap RX/TX/RTS/CTS async
574 reset_afio_registers();
575 Uart::new_with_rtscts(
576 p.USART3.reborrow(),
577 p.PD9.reborrow(),
578 p.PD8.reborrow(),
579 Irqs,
580 p.PD12.reborrow(),
581 p.PD11.reborrow(),
582 p.DMA1_CH2.reborrow(),
583 p.DMA1_CH3.reborrow(),
584 Default::default(),
585 )
586 .unwrap();
587 defmt::assert_eq!(AFIO.mapr().read().usart3_remap(), 3);
588 }
589
590 // SPI3
591 {
592 // no remap SCK/MISO/MOSI
593 afio_registers_set_remap();
594 Spi::new_blocking(
595 p.SPI3.reborrow(),
596 p.PB3.reborrow(),
597 p.PB5.reborrow(),
598 p.PB4.reborrow(),
599 Default::default(),
600 );
601 defmt::assert_eq!(AFIO.mapr().read().spi3_remap(), false);
602 }
603 {
604 // no remap SCK/MOSI
605 afio_registers_set_remap();
606 Spi::new_blocking_txonly(
607 p.SPI3.reborrow(),
608 p.PB3.reborrow(),
609 p.PB5.reborrow(),
610 Default::default(),
611 );
612 defmt::assert_eq!(AFIO.mapr().read().spi3_remap(), false);
613 }
614 {
615 // no remap MOSI
616 afio_registers_set_remap();
617 Spi::new_blocking_txonly_nosck(p.SPI3.reborrow(), p.PB5.reborrow(), Default::default());
618 defmt::assert_eq!(AFIO.mapr().read().spi3_remap(), false);
619 }
620 {
621 // no remap SCK/MISO
622 afio_registers_set_remap();
623 Spi::new_blocking_rxonly(
624 p.SPI3.reborrow(),
625 p.PB3.reborrow(),
626 p.PB4.reborrow(),
627 Default::default(),
628 );
629 defmt::assert_eq!(AFIO.mapr().read().spi3_remap(), false);
630 }
631 {
632 // remap SCK/MISO/MOSI
633 reset_afio_registers();
634 Spi::new_blocking(
635 p.SPI3.reborrow(),
636 p.PC10.reborrow(),
637 p.PC12.reborrow(),
638 p.PC11.reborrow(),
639 Default::default(),
640 );
641
642 defmt::assert_eq!(AFIO.mapr().read().spi3_remap(), true);
643 }
644 {
645 // remap SCK/MOSI
646 reset_afio_registers();
647 Spi::new_blocking_txonly(
648 p.SPI3.reborrow(),
649 p.PC10.reborrow(),
650 p.PC12.reborrow(),
651 Default::default(),
652 );
653 defmt::assert_eq!(AFIO.mapr().read().spi3_remap(), true);
654 }
655 {
656 // remap MOSI
657 reset_afio_registers();
658 Spi::new_blocking_txonly_nosck(p.SPI3.reborrow(), p.PB5.reborrow(), Default::default());
659 defmt::assert_eq!(AFIO.mapr().read().spi3_remap(), true);
660 }
661 {
662 // remap SCK/MISO
663 reset_afio_registers();
664 Spi::new_blocking_rxonly(
665 p.SPI3.reborrow(),
666 p.PC10.reborrow(),
667 p.PC11.reborrow(),
668 Default::default(),
669 );
670 defmt::assert_eq!(AFIO.mapr().read().spi3_remap(), true);
671 }
672
673 // I2S3
674 {
675 // no remap SD/WS/CK/MCK
676 afio_registers_set_remap();
677 I2S::new_txonly(
678 p.SPI3.reborrow(),
679 p.PB5.reborrow(),
680 p.PA15.reborrow(),
681 p.PB3.reborrow(),
682 p.PC7.reborrow(),
683 p.DMA2_CH2.reborrow(),
684 &mut [0u16; 0],
685 Default::default(),
686 );
687 defmt::assert_eq!(AFIO.mapr().read().spi3_remap(), false);
688 }
689 {
690 // no remap SD/WS/CK
691 afio_registers_set_remap();
692 I2S::new_txonly_nomck(
693 p.SPI3.reborrow(),
694 p.PB5.reborrow(),
695 p.PA15.reborrow(),
696 p.PB3.reborrow(),
697 p.DMA2_CH2.reborrow(),
698 &mut [0u16; 0],
699 Default::default(),
700 );
701 defmt::assert_eq!(AFIO.mapr().read().spi3_remap(), false);
702 }
703 {
704 // no remap SD/WS/CK/MCK
705 afio_registers_set_remap();
706 I2S::new_rxonly(
707 p.SPI3.reborrow(),
708 p.PB4.reborrow(),
709 p.PA15.reborrow(),
710 p.PB3.reborrow(),
711 p.PC7.reborrow(),
712 p.DMA2_CH1.reborrow(),
713 &mut [0u16; 0],
714 Default::default(),
715 );
716 defmt::assert_eq!(AFIO.mapr().read().spi3_remap(), true);
717 }
718 {
719 // remap SD/WS/CK/MCK
720 reset_afio_registers();
721 I2S::new_txonly(
722 p.SPI3.reborrow(),
723 p.PC12.reborrow(),
724 p.PA4.reborrow(),
725 p.PC10.reborrow(),
726 p.PC7.reborrow(),
727 p.DMA2_CH2.reborrow(),
728 &mut [0u16; 0],
729 Default::default(),
730 );
731 defmt::assert_eq!(AFIO.mapr().read().spi3_remap(), true);
732 }
733 {
734 // remap SD/WS/CK
735 reset_afio_registers();
736 I2S::new_txonly_nomck(
737 p.SPI3.reborrow(),
738 p.PC12.reborrow(),
739 p.PA4.reborrow(),
740 p.PC10.reborrow(),
741 p.DMA2_CH2.reborrow(),
742 &mut [0u16; 0],
743 Default::default(),
744 );
745 defmt::assert_eq!(AFIO.mapr().read().spi3_remap(), true);
746 }
747 {
748 // remap SD/WS/CK/MCK
749 reset_afio_registers();
750 I2S::new_rxonly(
751 p.SPI3.reborrow(),
752 p.PC11.reborrow(),
753 p.PA4.reborrow(),
754 p.PC10.reborrow(),
755 p.PC7.reborrow(),
756 p.DMA2_CH1.reborrow(),
757 &mut [0u16; 0],
758 Default::default(),
759 );
760 defmt::assert_eq!(AFIO.mapr().read().spi3_remap(), true);
761 }
762
763 // CAN2
764 {
765 // no remap
766 afio_registers_set_remap();
767 Can::new(p.CAN2.reborrow(), p.PB12.reborrow(), p.PB13.reborrow(), Irqs);
768 defmt::assert_eq!(AFIO.mapr().read().can2_remap(), false);
769 }
770 {
771 // remap
772 reset_afio_registers();
773 Can::new(p.CAN2.reborrow(), p.PB5.reborrow(), p.PB6.reborrow(), Irqs);
774 defmt::assert_eq!(AFIO.mapr().read().can2_remap(), true);
775 }
776
777 // Ethernet
778 {
779 // no remap RMII
780 afio_registers_set_remap();
781 Ethernet::new(
782 &mut PacketQueue::<1, 1>::new(),
783 p.ETH.reborrow(),
784 Irqs,
785 p.PA1.reborrow(),
786 p.PA2.reborrow(),
787 p.PC1.reborrow(),
788 p.PA7.reborrow(),
789 p.PC4.reborrow(),
790 p.PC5.reborrow(),
791 p.PB12.reborrow(),
792 p.PB13.reborrow(),
793 p.PB11.reborrow(),
794 GenericPhy::new_auto(),
795 Default::default(),
796 );
797 defmt::assert_eq!(AFIO.mapr().read().eth_remap(), false);
798 }
799 {
800 // no remap MII
801 afio_registers_set_remap();
802 Ethernet::new_mii(
803 &mut PacketQueue::<1, 1>::new(),
804 p.ETH.reborrow(),
805 Irqs,
806 p.PA1.reborrow(),
807 p.PC3.reborrow(),
808 p.PA2.reborrow(),
809 p.PC1.reborrow(),
810 p.PA7.reborrow(),
811 p.PC4.reborrow(),
812 p.PC5.reborrow(),
813 p.PB0.reborrow(),
814 p.PB1.reborrow(),
815 p.PB12.reborrow(),
816 p.PB13.reborrow(),
817 p.PC2.reborrow(),
818 p.PB8.reborrow(),
819 p.PB11.reborrow(),
820 GenericPhy::new_auto(),
821 Default::default(),
822 );
823 defmt::assert_eq!(AFIO.mapr().read().eth_remap(), false);
824 }
825 {
826 // remap RMII
827 reset_afio_registers();
828 Ethernet::new(
829 &mut PacketQueue::<1, 1>::new(),
830 p.ETH.reborrow(),
831 Irqs,
832 p.PA1.reborrow(),
833 p.PA2.reborrow(),
834 p.PC1.reborrow(),
835 p.PD8.reborrow(),
836 p.PD9.reborrow(),
837 p.PD10.reborrow(),
838 p.PB12.reborrow(),
839 p.PB13.reborrow(),
840 p.PB11.reborrow(),
841 GenericPhy::new_auto(),
842 Default::default(),
843 );
844 defmt::assert_eq!(AFIO.mapr().read().eth_remap(), true);
845 }
846 {
847 // remap MII
848 reset_afio_registers();
849 Ethernet::new_mii(
850 &mut PacketQueue::<1, 1>::new(),
851 p.ETH.reborrow(),
852 Irqs,
853 p.PA1.reborrow(),
854 p.PC3.reborrow(),
855 p.PA2.reborrow(),
856 p.PC1.reborrow(),
857 p.PD8.reborrow(),
858 p.PD9.reborrow(),
859 p.PD10.reborrow(),
860 p.PD11.reborrow(),
861 p.PD12.reborrow(),
862 p.PB12.reborrow(),
863 p.PB13.reborrow(),
864 p.PC2.reborrow(),
865 p.PB8.reborrow(),
866 p.PB11.reborrow(),
867 GenericPhy::new_auto(),
868 Default::default(),
869 );
870 defmt::assert_eq!(AFIO.mapr().read().eth_remap(), true);
871 }
872
873 // CAN1
874 {
875 // no remap
876 afio_registers_set_remap();
877 Can::new(p.CAN1.reborrow(), p.PA11.reborrow(), p.PA12.reborrow(), Irqs);
878 defmt::assert_eq!(AFIO.mapr().read().can1_remap(), 0);
879 }
880 {
881 // partial remap
882 reset_afio_registers();
883 Can::new(p.CAN1.reborrow(), p.PB8.reborrow(), p.PB9.reborrow(), Irqs);
884 defmt::assert_eq!(AFIO.mapr().read().can1_remap(), 2);
885 }
886 {
887 // full remap
888 reset_afio_registers();
889 Can::new(p.CAN1.reborrow(), p.PD0.reborrow(), p.PD1.reborrow(), Irqs);
890 defmt::assert_eq!(AFIO.mapr().read().can1_remap(), 3);
891 }
892
893 // USART2
894 {
895 // no remap RX/TX/RTS/CTS
896 afio_registers_set_remap();
897 Uart::new_blocking_with_rtscts(
898 p.USART2.reborrow(),
899 p.PA3.reborrow(),
900 p.PA2.reborrow(),
901 p.PA1.reborrow(),
902 p.PA0.reborrow(),
903 Default::default(),
904 )
905 .unwrap();
906 defmt::assert_eq!(AFIO.mapr().read().usart2_remap(), false);
907 }
908 {
909 // no remap RX/TX
910 afio_registers_set_remap();
911 Uart::new_blocking(
912 p.USART2.reborrow(),
913 p.PA3.reborrow(),
914 p.PA2.reborrow(),
915 Default::default(),
916 )
917 .unwrap();
918 defmt::assert_eq!(AFIO.mapr().read().usart2_remap(), false);
919 }
920 {
921 // no remap TX
922 afio_registers_set_remap();
923 Uart::new_blocking_half_duplex(
924 p.USART2.reborrow(),
925 p.PA2.reborrow(),
926 Default::default(),
927 embassy_stm32::usart::HalfDuplexReadback::NoReadback,
928 )
929 .unwrap();
930 defmt::assert_eq!(AFIO.mapr().read().usart2_remap(), false);
931 }
932 {
933 // full remap RX/TX/RTS/CTS
934 reset_afio_registers();
935 Uart::new_blocking_with_rtscts(
936 p.USART2.reborrow(),
937 p.PD6.reborrow(),
938 p.PD5.reborrow(),
939 p.PD4.reborrow(),
940 p.PD3.reborrow(),
941 Default::default(),
942 )
943 .unwrap();
944 defmt::assert_eq!(AFIO.mapr().read().usart2_remap(), false);
945 }
946 {
947 // full remap RX/TX
948 reset_afio_registers();
949 Uart::new_blocking(
950 p.USART2.reborrow(),
951 p.PD6.reborrow(),
952 p.PD5.reborrow(),
953 Default::default(),
954 )
955 .unwrap();
956 defmt::assert_eq!(AFIO.mapr().read().usart2_remap(), false);
957 }
958 {
959 // full remap TX
960 reset_afio_registers();
961 Uart::new_blocking_half_duplex(
962 p.USART2.reborrow(),
963 p.PD5.reborrow(),
964 Default::default(),
965 embassy_stm32::usart::HalfDuplexReadback::NoReadback,
966 )
967 .unwrap();
968 defmt::assert_eq!(AFIO.mapr().read().usart2_remap(), true);
969 }
970
971 // USART1
972 {
973 // no remap RX/TX/RTS/CTS
974 afio_registers_set_remap();
975 Uart::new_blocking_with_rtscts(
976 p.USART1.reborrow(),
977 p.PA10.reborrow(),
978 p.PA9.reborrow(),
979 p.PA12.reborrow(),
980 p.PA11.reborrow(),
981 Default::default(),
982 )
983 .unwrap();
984 defmt::assert_eq!(AFIO.mapr().read().usart1_remap(), false);
985 }
986 {
987 // no remap RX/TX
988 afio_registers_set_remap();
989 Uart::new_blocking(
990 p.USART1.reborrow(),
991 p.PA10.reborrow(),
992 p.PA9.reborrow(),
993 Default::default(),
994 )
995 .unwrap();
996 defmt::assert_eq!(AFIO.mapr().read().usart1_remap(), false);
997 }
998 {
999 // no remap TX
1000 afio_registers_set_remap();
1001 Uart::new_blocking_half_duplex(
1002 p.USART1.reborrow(),
1003 p.PA9.reborrow(),
1004 Default::default(),
1005 embassy_stm32::usart::HalfDuplexReadback::NoReadback,
1006 )
1007 .unwrap();
1008 defmt::assert_eq!(AFIO.mapr().read().usart1_remap(), false);
1009 }
1010 {
1011 // remap RX/TX/RTS/CTS
1012 reset_afio_registers();
1013 Uart::new_blocking_with_rtscts(
1014 p.USART1.reborrow(),
1015 p.PB7.reborrow(),
1016 p.PB6.reborrow(),
1017 p.PA12.reborrow(),
1018 p.PA11.reborrow(),
1019 Default::default(),
1020 )
1021 .unwrap();
1022 defmt::assert_eq!(AFIO.mapr().read().usart1_remap(), true);
1023 }
1024 {
1025 // remap RX/TX
1026 reset_afio_registers();
1027 Uart::new_blocking(
1028 p.USART1.reborrow(),
1029 p.PB7.reborrow(),
1030 p.PB6.reborrow(),
1031 Default::default(),
1032 )
1033 .unwrap();
1034 defmt::assert_eq!(AFIO.mapr().read().usart1_remap(), true);
1035 }
1036 {
1037 // remap TX
1038 reset_afio_registers();
1039 Uart::new_blocking_half_duplex(
1040 p.USART1.reborrow(),
1041 p.PB6.reborrow(),
1042 Default::default(),
1043 embassy_stm32::usart::HalfDuplexReadback::NoReadback,
1044 )
1045 .unwrap();
1046 defmt::assert_eq!(AFIO.mapr().read().usart1_remap(), true);
1047 }
1048
1049 // TIM1
1050 {
1051 // full remap
1052 reset_afio_registers();
1053 SimplePwm::new(
1054 p.TIM1.reborrow(),
1055 Some(PwmPin::new(p.PE9.reborrow(), OutputType::PushPull)),
1056 Some(PwmPin::new(p.PE11.reborrow(), OutputType::PushPull)),
1057 None,
1058 None,
1059 khz(10),
1060 Default::default(),
1061 );
1062 defmt::assert_eq!(AFIO.mapr().read().tim1_remap(), 3);
1063 }
1064 }
1065}
1066
1067#[cfg(feature = "afio-value-line")]
1068mod value_line {
1069 use super::*;
1070
1071 pub fn run(p: &mut Peripherals) {
1072 // TIM13
1073 {
1074 // no remap
1075 reset_afio_registers();
1076 SimplePwm::new(
1077 p.TIM13.reborrow(),
1078 Some(PwmPin::new(p.PC8.reborrow(), OutputType::PushPull)),
1079 None,
1080 None,
1081 None,
1082 khz(10),
1083 Default::default(),
1084 );
1085 defmt::assert_eq!(AFIO.mapr2().read().tim13_remap(), false);
1086 }
1087 {
1088 // remap
1089 reset_afio_registers();
1090 SimplePwm::new(
1091 p.TIM13.reborrow(),
1092 Some(PwmPin::new(p.PB0.reborrow(), OutputType::PushPull)),
1093 None,
1094 None,
1095 None,
1096 khz(10),
1097 Default::default(),
1098 );
1099 defmt::assert_eq!(AFIO.mapr2().read().tim13_remap(), true);
1100 }
1101 }
1102}
1103
1104#[cfg(not(feature = "afio-connectivity-line"))]
1105mod connectivity_line {
1106 use super::*;
1107
1108 pub fn run(_: &mut Peripherals) {}
1109}
1110
1111#[cfg(not(feature = "afio-value-line"))]
1112mod value_line {
1113 use super::*;
1114
1115 pub fn run(_: &mut Peripherals) {}
1116}
1117
1118fn reset_afio_registers() {
1119 set_afio_registers(false, 0);
1120}
1121
1122fn afio_registers_set_remap() {
1123 set_afio_registers(true, 1);
1124}
1125
1126fn set_afio_registers(bool_val: bool, num_val: u8) {
1127 AFIO.mapr().modify(|w| {
1128 w.set_swj_cfg(embassy_stm32::pac::afio::vals::SwjCfg::NO_OP);
1129 w.set_can1_remap(num_val);
1130 w.set_can2_remap(bool_val);
1131 w.set_eth_remap(bool_val);
1132 w.set_i2c1_remap(bool_val);
1133 w.set_spi1_remap(bool_val);
1134 w.set_spi3_remap(bool_val);
1135 w.set_tim1_remap(num_val);
1136 w.set_tim2_remap(num_val);
1137 w.set_tim3_remap(num_val);
1138 w.set_tim4_remap(bool_val);
1139 w.set_usart1_remap(bool_val);
1140 w.set_usart2_remap(bool_val);
1141 w.set_usart3_remap(num_val);
1142 });
1143
1144 AFIO.mapr2().modify(|w| {
1145 w.set_cec_remap(bool_val);
1146 w.set_tim9_remap(bool_val);
1147 w.set_tim10_remap(bool_val);
1148 w.set_tim11_remap(bool_val);
1149 w.set_tim12_remap(bool_val);
1150 w.set_tim13_remap(bool_val);
1151 w.set_tim14_remap(bool_val);
1152 w.set_tim15_remap(bool_val);
1153 w.set_tim16_remap(bool_val);
1154 w.set_tim17_remap(bool_val);
1155 });
1156}
diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs
index cb63b3374..f800769ab 100644
--- a/tests/stm32/src/common.rs
+++ b/tests/stm32/src/common.rs
@@ -103,7 +103,7 @@ define_peris!(
103 SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH3, SPI_RX_DMA = DMA1_CH2, 103 SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH3, SPI_RX_DMA = DMA1_CH2,
104 @irq UART = {USART1 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART1>;}, 104 @irq UART = {USART1 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART1>;},
105); 105);
106#[cfg(feature = "stm32f103c8")] 106#[cfg(any(feature = "stm32f100rd", feature = "stm32f103c8", feature = "stm32f107vc"))]
107define_peris!( 107define_peris!(
108 UART = USART1, UART_TX = PA9, UART_RX = PA10, UART_TX_DMA = DMA1_CH4, UART_RX_DMA = DMA1_CH5, 108 UART = USART1, UART_TX = PA9, UART_RX = PA10, UART_TX_DMA = DMA1_CH4, UART_RX_DMA = DMA1_CH5,
109 SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH3, SPI_RX_DMA = DMA1_CH2, 109 SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH3, SPI_RX_DMA = DMA1_CH2,