Skip to content

Commit

Permalink
Serial: Replace Pins trait with TxPin / RxPin
Browse files Browse the repository at this point in the history
The previous approach with the `Pins` trait assumed that an USART
peripheral can only be used with specific pin pairs. However, pins can
be mixed, so you could use USART1 with PA9 and PB7.

So instead of the `Pins` trait, there are now separate `TxPin` and
`RxPin` traits. They are implemented for all pins of all U(S)ART
peripherals of the stm32l0xx family.

Pin mappings verified against datasheets of stm32l071kb, stm32l072vz
and stm32l083vz.
  • Loading branch information
dbrgn committed Jan 13, 2020
1 parent fb1f6a6 commit 1b0837a
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 68 deletions.
3 changes: 2 additions & 1 deletion examples/rtc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ fn main() -> ! {

let serial = dp.USART2
.usart(
(gpioa.pa2, gpioa.pa3),
gpioa.pa2,
gpioa.pa3,
serial::Config::default()
.baudrate(115_200.bps()),
&mut rcc,
Expand Down
14 changes: 4 additions & 10 deletions examples/serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,14 @@ fn main() -> ! {
// the RCC register.
let gpioa = dp.GPIOA.split(&mut rcc);

#[cfg(feature = "stm32l0x1")]
let tx_pin = gpioa.pa9;
#[cfg(feature = "stm32l0x1")]
let rx_pin = gpioa.pa10;

#[cfg(any(feature = "stm32l0x2", feature = "stm32l0x3"))]
let tx_pin = gpioa.pa14;
#[cfg(any(feature = "stm32l0x2", feature = "stm32l0x3"))]
let rx_pin = gpioa.pa15;
// Choose TX / RX pins
let tx_pin = gpioa.pa2;
let rx_pin = gpioa.pa3;

// Configure the serial peripheral.
let serial = dp
.USART2
.usart((tx_pin, rx_pin), serial::Config::default(), &mut rcc)
.usart(tx_pin, rx_pin, serial::Config::default(), &mut rcc)
.unwrap();

let (mut tx, mut rx) = serial.split();
Expand Down
3 changes: 2 additions & 1 deletion examples/serial_dma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ fn main() -> ! {
let (mut tx, mut rx) = dp
.USART2
.usart(
(gpioa.pa2, gpioa.pa3),
gpioa.pa2,
gpioa.pa3,
serial::Config::default().baudrate(115_200.bps()),
&mut rcc,
)
Expand Down
17 changes: 9 additions & 8 deletions examples/serial_dma_async.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,15 @@ fn main() -> ! {
let gpioa = dp.GPIOA.split(&mut rcc);

let (tx, rx) = dp
.USART2
.usart(
(gpioa.pa2, gpioa.pa3),
serial::Config::default().baudrate(115_200.bps()),
&mut rcc,
)
.unwrap()
.split();
.USART2
.usart(
gpioa.pa2,
gpioa.pa3,
serial::Config::default().baudrate(115_200.bps()),
&mut rcc,
)
.unwrap()
.split();

// we only have two elements for each queue, so U2 is fine (size is max 2)
let mut rx_buffers: Queue<Pin<DmaBuffer>, U2> = Queue::new();
Expand Down
115 changes: 67 additions & 48 deletions src/serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,14 @@ use core::fmt;
use core::marker::PhantomData;
use core::ptr;

use crate::gpio::gpioa::*;
use crate::gpio::{gpioa::*, gpiob::*, gpioc::*, gpiod::*, gpioe::*};
use crate::gpio::AltMode;
use crate::hal;
use crate::hal::prelude::*;
pub use crate::pac::USART2;
pub use crate::pac::{LPUART1, USART1, USART2, USART4, USART5};
use crate::rcc::Rcc;
use nb::block;

#[cfg(feature = "stm32l0x1")]
pub use crate::pac::LPUART1;

#[cfg(any(feature = "stm32l0x2", feature = "stm32l0x3"))]
use core::{
ops::{Deref, DerefMut},
Expand All @@ -23,14 +20,7 @@ use core::{
use as_slice::{AsMutSlice, AsSlice};

#[cfg(any(feature = "stm32l0x2", feature = "stm32l0x3"))]
pub use crate::{
dma,
gpio::gpiob::*,
gpio::gpioc::*,
gpio::gpiod::*,
gpio::gpioe::*,
pac::{LPUART1, USART1, USART4, USART5},
};
pub use crate::dma;

#[cfg(any(feature = "stm32l0x2", feature = "stm32l0x3"))]
use dma::Buffer;
Expand Down Expand Up @@ -152,44 +142,69 @@ impl Default for Config {
}
}

pub trait Pins<USART> {
/// Trait to mark serial pins with transmit capability.
pub trait TxPin<USART> {
fn setup(&self);
}

/// Trait to mark serial pins with receive capability.
pub trait RxPin<USART> {
fn setup(&self);
}

/// Macro to implement `TxPin` / `RxPin` for a certain pin, using a certain
/// alternative function and for a certain serial peripheral.
macro_rules! impl_pins {
($($instance:ty, $tx:ident, $rx:ident, $alt:ident;)*) => {
($($pin:ident, $alt:ident, $instance:ty, $trait:ident;)*) => {
$(
impl<Tx, Rx> Pins<$instance> for ($tx<Tx>, $rx<Rx>) {
impl<MODE> $trait<$instance> for $pin<MODE> {
fn setup(&self) {
self.0.set_alt_mode(AltMode::$alt);
self.1.set_alt_mode(AltMode::$alt);
self.set_alt_mode(AltMode::$alt);
}
}
)*
}
}

#[cfg(feature = "stm32l0x1")]
impl_pins!(
LPUART1, PA2, PA3, AF6;
USART2, PA9, PA10, AF4;
);

#[cfg(any(feature = "stm32l0x2", feature = "stm32l0x3"))]
impl_pins!(
LPUART1, PA2, PA3, AF6;
LPUART1, PB10, PB11, AF4;
LPUART1, PB11, PB10, AF7;
USART1, PA9, PA10, AF4;
USART1, PB6, PB7, AF0;
USART2, PA2, PA3, AF4;
USART2, PA14, PA15, AF4;
USART2, PD5, PD6, AF0;
USART4, PA0, PA1, AF6;
USART4, PC10, PC11, AF6;
USART4, PE8, PE9, AF6;
USART5, PB3, PB4, AF6;
USART5, PE10, PE11, AF6;
PA0, AF6, USART4, TxPin;
PA1, AF6, USART4, RxPin;
PA2, AF4, USART2, TxPin;
PA2, AF6, LPUART1, TxPin;
PA3, AF4, USART2, RxPin;
PA3, AF6, LPUART1, RxPin;
PA9, AF4, USART1, TxPin;
PA10, AF4, USART1, RxPin;
PA13, AF6, LPUART1, RxPin;
PA14, AF4, USART2, TxPin;
PA14, AF6, LPUART1, TxPin;
PA15, AF4, USART2, RxPin;
PB3, AF6, USART5, TxPin;
PB4, AF6, USART5, RxPin;
PB6, AF0, USART1, TxPin;
PB7, AF0, USART1, RxPin;
PB10, AF4, LPUART1, TxPin;
PB10, AF7, LPUART1, RxPin;
PB11, AF4, LPUART1, RxPin;
PB11, AF7, LPUART1, TxPin;
PC0, AF6, LPUART1, RxPin;
PC1, AF6, LPUART1, TxPin;
PC4, AF2, LPUART1, TxPin;
PC5, AF2, LPUART1, RxPin;
PC10, AF0, LPUART1, TxPin;
PC10, AF6, USART4, TxPin;
PC11, AF0, LPUART1, RxPin;
PC11, AF6, USART4, RxPin;
PC12, AF2, USART5, TxPin;
PD2, AF6, USART5, RxPin;
PD5, AF0, USART2, TxPin;
PD6, AF0, USART2, RxPin;
PD8, AF0, LPUART1, TxPin;
PD9, AF0, LPUART1, RxPin;
PE8, AF6, USART4, TxPin;
PE9, AF6, USART4, RxPin;
PE10, AF6, USART5, TxPin;
PE11, AF6, USART5, RxPin;
);

/// Serial abstraction
Expand All @@ -214,30 +229,34 @@ macro_rules! usart {
$USARTX:ident: ($usartX:ident, $apbXenr:ident, $usartXen:ident, $pclkX:ident, $SerialExt:ident),
)+) => {
$(
pub trait $SerialExt<PINS> {
fn usart(self, pins: PINS, config: Config, rcc: &mut Rcc) -> Result<Serial<$USARTX>, InvalidConfig>;
pub trait $SerialExt<TX, RX> {
fn usart(self, tx: TX, rx: RX, config: Config, rcc: &mut Rcc) -> Result<Serial<$USARTX>, InvalidConfig>;
}

impl<PINS> $SerialExt<PINS> for $USARTX
impl<TX, RX> $SerialExt<TX, RX> for $USARTX
where
PINS: Pins<$USARTX>,
TX: TxPin<$USARTX>,
RX: RxPin<$USARTX>,
{
fn usart(self, pins: PINS, config: Config, rcc: &mut Rcc) -> Result<Serial<$USARTX>, InvalidConfig> {
Serial::$usartX(self, pins, config, rcc)
fn usart(self, tx: TX, rx: RX, config: Config, rcc: &mut Rcc) -> Result<Serial<$USARTX>, InvalidConfig> {
Serial::$usartX(self, tx, rx, config, rcc)
}
}

impl Serial<$USARTX> {
pub fn $usartX<PINS>(
pub fn $usartX<TX, RX>(
usart: $USARTX,
pins: PINS,
tx: TX,
rx: RX,
config: Config,
rcc: &mut Rcc,
) -> Result<Self, InvalidConfig>
where
PINS: Pins<$USARTX>,
TX: TxPin<$USARTX>,
RX: RxPin<$USARTX>,
{
pins.setup();
tx.setup();
rx.setup();

// Enable clock for USART
rcc.rb.$apbXenr.modify(|_, w| w.$usartXen().set_bit());
Expand Down

0 comments on commit 1b0837a

Please sign in to comment.