Skip to content

Serial Pins design discussion #67

Closed
@dbrgn

Description

@dbrgn

Right now the Pins trait looks like this:

pub trait Pins<USART> {
    fn setup(&self);
}

It is then implemented for pin pairs using a macro:

macro_rules! impl_pins {
    ($($instance:ty, $tx:ident, $rx:ident, $alt:ident;)*) => {
        $(
            impl<Tx, Rx> Pins<$instance> for ($tx<Tx>, $rx<Rx>) {
                fn setup(&self) {
                    self.0.set_alt_mode(AltMode::$alt);
                    self.1.set_alt_mode(AltMode::$alt);
                }
            }
        )*
    }
}

impl_pins!(
    USART1,  PA9,  PA10, AF4;
    USART1,  PB6,  PB7,  AF0;
    USART2,  PA2,  PA3,  AF4;
    USART2,  PA14, PA15, AF4;
    USART2,  PD5,  PD6,  AF0;
    // ..
);

The problem with this is, that it assumes that a single pin pair can be used for an USART peripheral. However, pins can be mixed, so I could use USART1 with PA9 and PB7.

One approach would be to generate Pins implementations for all permutations (which can go into dozens or even hundreds of impls), but that's a workaround for a design problem in my opinion: Different pins can act as Tx and as Rx for an USART independently. (You could even use multiple Tx pins for the same USART if you wanted...)

My suggestion would be to drop the Pins<USART> trait, and to add TxPin<USART> and RxPin<USART> traits instead.

Here's a quick way to play around with this idea without having to adjust the serial trait:

pub trait TxPin<USART> {
    fn setup(&self);
}

pub trait RxPin<USART> {
    fn setup(&self);
}

impl<USART, TX, RX> Pins<USART> for (TX, RX) where TX: TxPin<USART>, RX: RxPin<USART> {
    fn setup(&self) {
        self.0.setup();
        self.1.setup();
    }
}

impl<Mode> TxPin<USART1> for PA9<Mode> { fn setup(&self) { self.set_alt_mode(AltMode::AF4); } }
impl<Mode> RxPin<USART1> for PA10<Mode> { fn setup(&self) { self.set_alt_mode(AltMode::AF4); } }
impl<Mode> TxPin<USART1> for PB6<Mode> { fn setup(&self) { self.set_alt_mode(AltMode::AF0); } }
impl<Mode> RxPin<USART1> for PB7<Mode> { fn setup(&self) { self.set_alt_mode(AltMode::AF0); } }

What do you think about this? I can create a PR with a concrete implementation if you want.

If dropping the Pins directly is not an option, we could also deprecate it and implement the Serial trait for both Pins and RxPin / TxPin.

cc @rnestler

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions