Skip to content

Commit e00a01c

Browse files
committed
drivers: migrate to new_pin! / set_as_af! macros (fixes CAN remap bug)
Adds the `new_pin!` and `set_as_af!` macros to macros.rs (mirroring embassy-stm32 verbatim) and rewrites every driver `new*()` call site to use them. This collapses the previous pattern tx.set_as_af_output(AFType::OutputPushPull, Speed::High); #[cfg(afio)] tx.afio_remap(); // ...later... Some(tx.into()) into a single new_pin!(tx, AfType::output(OutputType::PushPull, Speed::High)) The 96 scattered `#[cfg(afio)] pin.afio_remap();` calls go away because the macros own the cfg dispatch. Drivers are direction- agnostic — input pins go through `new_pin!(pin, AfType::input(pull))`, output pins through `AfType::output(...)`. This also fixes a correctness bug: the CAN driver's `new_inner` configured pins via raw `pin.set_mode_cnf(...)` calls, which the earlier driver migration regex didn't match, so the `#[cfg(afio)] pin.afio_remap()` injection silently skipped CAN. On V3 chips a user typing `Remap<2>` for CAN1 pins would compile but the PCFR1.CAN1_RM bits would never get written — runtime CAN1 stayed on the default group. Routing CAN through the same `set_as_af!` macro restores the typesafe contract. Driver-by-driver: - USART: 14 sites - SPI: 8 sites - I2C: 1 site (with cfg(gpio_x0) open-drain fallback) - CAN: 2 sites in `new_inner` (was the bug) - timer simple_pwm + complementary_pwm: 1 macro each USART's `new_half_duplex` / `new_blocking_half_duplex` now select push-pull vs open-drain via a `#[cfg(not(gpio_x0))] let af = ...` pair before the `new_pin!` call, matching the family-conditional behaviour the original code had. All 11 example families (ch32v003 ch32v006 ch32v103 ch32v203 ch32v208 ch32v305 ch32v307 ch32l103 ch32x035 ch641 ch643) build clean with `cargo check`.
1 parent 6a1767e commit e00a01c

7 files changed

Lines changed: 102 additions & 224 deletions

File tree

src/can/can.rs

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use crate::can::registers::Registers;
1111
use crate::can::util;
1212
use crate::internal::drop::OnDrop;
1313
use crate::mode::{Async, Blocking, Mode, NonBlocking};
14+
use crate::gpio::{AfType, OutputType, Pull, Speed};
1415
use crate::{interrupt, pac, peripherals, Peri, RccPeripheral, Timeout};
1516

1617
/// Receive interrupt handler.
@@ -263,18 +264,11 @@ impl<'d, T: Instance, M: Mode> Can<'d, T, M> {
263264
};
264265
T::enable_and_reset(); // Enable CAN peripheral
265266

266-
rx.set_mode_cnf(
267-
pac::gpio::vals::Mode::INPUT,
268-
pac::gpio::vals::Cnf::PULL_IN__AF_PUSH_PULL_OUT,
269-
);
270-
271-
tx.set_mode_cnf(
272-
pac::gpio::vals::Mode::OUTPUT_50MHZ,
273-
pac::gpio::vals::Cnf::PULL_IN__AF_PUSH_PULL_OUT,
274-
);
275-
276-
// //here should remap functionality be added
277-
// T::remap(0b10);
267+
// RX is input-with-pull-up; TX is AF push-pull at 50MHz.
268+
// `set_as_af!` writes mode/cnf and (under cfg(afio)) the PCFR remap
269+
// bit, picking up the group encoded in the pin's marker type.
270+
set_as_af!(rx, AfType::input(Pull::Up));
271+
set_as_af!(tx, AfType::output(OutputType::PushPull, Speed::High));
278272

279273
unsafe {
280274
use crate::interrupt::typelevel::Interrupt;

src/i2c.rs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use embassy_sync::waitqueue::AtomicWaker;
99
use embedded_hal::i2c::Operation;
1010

1111
use crate::dma::ChannelAndRequest;
12-
use crate::gpio::{AFType, Speed};
12+
use crate::gpio::{AfType, OutputType, Speed};
1313
use crate::internal::drop::OnDrop;
1414
use crate::mode::{Async, Blocking, Mode};
1515
// use crate::interrupt::Interrupt;
@@ -154,17 +154,15 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
154154
T::enable_and_reset();
155155

156156

157+
// gpio_x0 doesn't expose an open-drain AF variant; SCL/SDA fall back
158+
// to push-pull and rely on external pull-ups (already required for I2C).
157159
#[cfg(not(gpio_x0))]
158-
let af_type = AFType::OutputOpenDrain;
160+
let af = AfType::output(OutputType::OpenDrain, Speed::High);
159161
#[cfg(gpio_x0)]
160-
let af_type = AFType::OutputPushPull;
161-
162-
scl.set_as_af_output(af_type, Speed::High);
163-
#[cfg(afio)]
164-
scl.afio_remap();
165-
sda.set_as_af_output(af_type, Speed::High);
166-
#[cfg(afio)]
167-
sda.afio_remap();
162+
let af = AfType::output(OutputType::PushPull, Speed::High);
163+
164+
set_as_af!(scl, af);
165+
set_as_af!(sda, af);
168166

169167
unsafe { T::EventInterrupt::enable() };
170168
unsafe { T::ErrorInterrupt::enable() };

src/macros.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,44 @@ macro_rules! if_afio {
106106
};
107107
}
108108

109+
/// Configure a pin for AF use and consume it into the `Option<Peri<'d, AnyPin>>`
110+
/// shape drivers store internally. Hides the cfg(afio)/cfg(not(afio)) split:
111+
/// - cfg(afio): writes AFIO PCFR via `pin.afio_remap()` then mode/cnf via `set_as_af`
112+
/// - cfg(not(afio)) (future H4): reads `pin.af_num()` and writes the AF mux registers
113+
///
114+
/// Mirrors embassy-stm32's `new_pin!` (returns `Some(...)` so the driver can
115+
/// drop it into an `Option<Peri<'d, AnyPin>>` field directly).
116+
macro_rules! new_pin {
117+
($name:ident, $af_type:expr) => {{
118+
use crate::gpio::SealedPin as _;
119+
let pin = $name;
120+
#[cfg(afio)]
121+
pin.afio_remap();
122+
pin.set_as_af(
123+
#[cfg(not(afio))]
124+
pin.af_num(),
125+
$af_type,
126+
);
127+
Some(pin.into())
128+
}};
129+
}
130+
131+
/// Like `new_pin!` but doesn't consume the pin — for the rare driver site
132+
/// that needs to keep its own typed `Peri<'d, PinX>` handle (e.g. for
133+
/// later reconfiguration). Mirrors embassy-stm32's `set_as_af!`.
134+
macro_rules! set_as_af {
135+
($pin:expr, $af_type:expr) => {{
136+
use crate::gpio::SealedPin as _;
137+
#[cfg(afio)]
138+
$pin.afio_remap();
139+
$pin.set_as_af(
140+
#[cfg(not(afio))]
141+
$pin.af_num(),
142+
$af_type,
143+
);
144+
}};
145+
}
146+
109147
#[allow(unused)]
110148
macro_rules! dma_trait_impl {
111149
// DMA/GPDMA, without DMAMUX

src/spi.rs

Lines changed: 15 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use pac::spi::vals::BaudRate;
2222
use pac::spi::Spi as Regs;
2323

2424
use crate::dma::{slice_ptr_parts, word, ChannelAndRequest};
25-
use crate::gpio::{AFType, AnyPin, Pull, Speed};
25+
use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin, Speed};
2626
use crate::mode::{Async, Blocking, Mode as PeriMode};
2727
use crate::time::Hertz;
2828
use crate::{pac, peripherals, Peri};
@@ -303,21 +303,11 @@ impl<'d, T: Instance> Spi<'d, T, Blocking> {
303303
config: Config,
304304
) -> Self {
305305

306-
sck.set_as_af_output(AFType::OutputPushPull, Speed::High);
307-
#[cfg(afio)]
308-
sck.afio_remap();
309-
mosi.set_as_af_output(AFType::OutputPushPull, Speed::High);
310-
#[cfg(afio)]
311-
mosi.afio_remap();
312-
miso.set_as_input(Pull::None);
313-
#[cfg(afio)]
314-
miso.afio_remap();
315-
316306
Self::new_inner(
317307
peri,
318-
Some(sck.into()),
319-
Some(mosi.into()),
320-
Some(miso.into()),
308+
new_pin!(sck, AfType::output(OutputType::PushPull, Speed::High)),
309+
new_pin!(mosi, AfType::output(OutputType::PushPull, Speed::High)),
310+
new_pin!(miso, AfType::input(Pull::None)),
321311
None,
322312
None,
323313
config,
@@ -332,14 +322,7 @@ impl<'d, T: Instance> Spi<'d, T, Blocking> {
332322
config: Config,
333323
) -> Self {
334324

335-
sck.set_as_af_output(AFType::OutputPushPull, Speed::High);
336-
#[cfg(afio)]
337-
sck.afio_remap();
338-
miso.set_as_input(Pull::None);
339-
#[cfg(afio)]
340-
miso.afio_remap();
341-
342-
Self::new_inner(peri, Some(sck.into()), None, Some(miso.into()), None, None, config)
325+
Self::new_inner(peri, new_pin!(sck, AfType::output(OutputType::PushPull, Speed::High)), None, new_pin!(miso, AfType::input(Pull::None)), None, None, config)
343326
}
344327

345328
/// Create a new SPI driver, in TX-only mode (only MOSI pin, no MISO).
@@ -350,14 +333,7 @@ impl<'d, T: Instance> Spi<'d, T, Blocking> {
350333
config: Config,
351334
) -> Self {
352335

353-
sck.set_as_af_output(AFType::OutputPushPull, Speed::High);
354-
#[cfg(afio)]
355-
sck.afio_remap();
356-
mosi.set_as_af_output(AFType::OutputPushPull, Speed::High);
357-
#[cfg(afio)]
358-
mosi.afio_remap();
359-
360-
Self::new_inner(peri, Some(sck.into()), Some(mosi.into()), None, None, None, config)
336+
Self::new_inner(peri, new_pin!(sck, AfType::output(OutputType::PushPull, Speed::High)), new_pin!(mosi, AfType::output(OutputType::PushPull, Speed::High)), None, None, None, config)
361337
}
362338

363339
/// Create a new SPI driver, in TX-only mode, without SCK pin.
@@ -369,11 +345,7 @@ impl<'d, T: Instance> Spi<'d, T, Blocking> {
369345
config: Config,
370346
) -> Self {
371347

372-
mosi.set_as_af_output(AFType::OutputPushPull, Speed::High);
373-
#[cfg(afio)]
374-
mosi.afio_remap();
375-
376-
Self::new_inner(peri, None, Some(mosi.into()), None, None, None, config)
348+
Self::new_inner(peri, None, new_pin!(mosi, AfType::output(OutputType::PushPull, Speed::High)), None, None, None, config)
377349
}
378350
}
379351

@@ -389,21 +361,11 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
389361
config: Config,
390362
) -> Self {
391363

392-
sck.set_as_af_output(AFType::OutputPushPull, Speed::High);
393-
#[cfg(afio)]
394-
sck.afio_remap();
395-
mosi.set_as_af_output(AFType::OutputPushPull, Speed::High);
396-
#[cfg(afio)]
397-
mosi.afio_remap();
398-
miso.set_as_input(Pull::None);
399-
#[cfg(afio)]
400-
miso.afio_remap();
401-
402364
Self::new_inner(
403365
peri,
404-
Some(sck.into()),
405-
Some(mosi.into()),
406-
Some(miso.into()),
366+
new_pin!(sck, AfType::output(OutputType::PushPull, Speed::High)),
367+
new_pin!(mosi, AfType::output(OutputType::PushPull, Speed::High)),
368+
new_pin!(miso, AfType::input(Pull::None)),
407369
new_dma!(tx_dma),
408370
new_dma!(rx_dma),
409371
config,
@@ -419,18 +381,11 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
419381
config: Config,
420382
) -> Self {
421383

422-
sck.set_as_af_output(AFType::OutputPushPull, Speed::High);
423-
#[cfg(afio)]
424-
sck.afio_remap();
425-
miso.set_as_input(Pull::None);
426-
#[cfg(afio)]
427-
miso.afio_remap();
428-
429384
Self::new_inner(
430385
peri,
431-
Some(sck.into()),
386+
new_pin!(sck, AfType::output(OutputType::PushPull, Speed::High)),
432387
None,
433-
Some(miso.into()),
388+
new_pin!(miso, AfType::input(Pull::None)),
434389
None,
435390
new_dma!(rx_dma),
436391
config,
@@ -446,17 +401,10 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
446401
config: Config,
447402
) -> Self {
448403

449-
sck.set_as_af_output(AFType::OutputPushPull, Speed::High);
450-
#[cfg(afio)]
451-
sck.afio_remap();
452-
mosi.set_as_af_output(AFType::OutputPushPull, Speed::High);
453-
#[cfg(afio)]
454-
mosi.afio_remap();
455-
456404
Self::new_inner(
457405
peri,
458-
Some(sck.into()),
459-
Some(mosi.into()),
406+
new_pin!(sck, AfType::output(OutputType::PushPull, Speed::High)),
407+
new_pin!(mosi, AfType::output(OutputType::PushPull, Speed::High)),
460408
None,
461409
new_dma!(tx_dma),
462410
None,
@@ -474,11 +422,7 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
474422
config: Config,
475423
) -> Self {
476424

477-
mosi.set_as_af_output(AFType::OutputPushPull, Speed::High);
478-
#[cfg(afio)]
479-
mosi.afio_remap();
480-
481-
Self::new_inner(peri, None, Some(mosi.into()), None, new_dma!(tx_dma), None, config)
425+
Self::new_inner(peri, None, new_pin!(mosi, AfType::output(OutputType::PushPull, Speed::High)), None, new_dma!(tx_dma), None, config)
482426
}
483427

484428
/// SPI write, using DMA.

src/timer/complementary_pwm.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use core::marker::PhantomData;
55
use super::low_level::{CountingMode, OutputPolarity, Timer};
66
use super::simple_pwm::{Ch1, Ch2, Ch3, Ch4, PwmPin};
77
use super::{AdvancedInstance, Channel, Channel1ComplementaryPin, Channel2ComplementaryPin, Channel3ComplementaryPin};
8-
use crate::gpio::{AFType, AnyPin};
8+
use crate::gpio::{AfType, AnyPin, OutputType, Speed};
99
use crate::pac::timer::vals::Ckd;
1010
use crate::time::Hertz;
1111
use crate::timer::low_level::OutputCompareMode;
@@ -28,9 +28,7 @@ macro_rules! complementary_channel_impl {
2828
) -> Self {
2929
critical_section::with(|_| {
3030
pin.set_low();
31-
pin.set_as_af_output(AFType::OutputPushPull, Default::default());
32-
#[cfg(afio)]
33-
pin.afio_remap();
31+
set_as_af!(pin, AfType::output(OutputType::PushPull, Speed::High));
3432
});
3533
ComplementaryPwmPin {
3634
_pin: pin.into(),

src/timer/simple_pwm.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use core::marker::PhantomData;
44

55
use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer};
66
use super::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance16bit};
7-
use crate::gpio::{AFType, AnyPin};
7+
use crate::gpio::{AfType, AnyPin, OutputType, Speed};
88
use crate::time::Hertz;
99
use crate::Peri;
1010

@@ -33,9 +33,7 @@ macro_rules! channel_impl {
3333
pin: Peri<'d, if_afio!(impl $pin_trait<T, A>)>,
3434
) -> Self {
3535
critical_section::with(|_| {
36-
pin.set_as_af_output(AFType::OutputPushPull, Default::default());
37-
#[cfg(afio)]
38-
pin.afio_remap();
36+
set_as_af!(pin, AfType::output(OutputType::PushPull, Speed::High));
3937
});
4038
PwmPin {
4139
_pin: pin.into(),

0 commit comments

Comments
 (0)