From df14c887d66bcd4218530ebd05b7961544a2ecd5 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sun, 6 Oct 2024 13:29:33 +0300 Subject: [PATCH] Serial/SPI/I2C/CAN remap --- CHANGELOG.md | 5 +- examples/serial_config.rs | 18 +--- examples/spi-slave.rs | 4 +- src/can.rs | 91 +++++++++++-------- src/gpio.rs | 8 ++ src/i2c.rs | 79 ++++++++++++----- src/i2c/blocking.rs | 2 +- src/serial.rs | 141 ++++++++++++++++++++--------- src/spi.rs | 180 +++++++++++++++++++++++--------------- 9 files changed, 339 insertions(+), 189 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 54e771c9..411cdfb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Relax pin type generics for `Serial`, `I2c`, `Spi`, `Can`. [#462] Use enums of pin tuples and `Enum::from<(tuple)>` for pin remap before passing to peripheral. - Remove `RemapStruct`s. [#462] [#506] + Remove `RemapStruct`s. [#462] [#506] [#509] - Use independent `Spi` and `SpiSlave` structures instead of `OP` generic [#462] - Take `&Clocks` instead of `Clocks` [#498] - Temporary replace `stm32f1` with `stm32f1-staging` [#503] @@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Check "device selected" in `build.rs` [#502] - Use gpio field enums internally [#506] - Unmacro `dma.rs` [#505] +- Rework USART remap, ### Added @@ -37,6 +38,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Add DAC [#483] - Add an option to allow overclocking [#494] - `new` on gpio mode [#506] +- Add `Serial` `rx`/`tx` constructors [#509] [#416]: https://github.com/stm32-rs/stm32f1xx-hal/pull/416 [#453]: https://github.com/stm32-rs/stm32f1xx-hal/pull/453 @@ -54,6 +56,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). [#503]: https://github.com/stm32-rs/stm32f1xx-hal/pull/503 [#505]: https://github.com/stm32-rs/stm32f1xx-hal/pull/505 [#506]: https://github.com/stm32-rs/stm32f1xx-hal/pull/506 +[#509]: https://github.com/stm32-rs/stm32f1xx-hal/pull/509 ## [v0.10.0] - 2022-12-12 diff --git a/examples/serial_config.rs b/examples/serial_config.rs index 59f01e4b..6f585c8f 100644 --- a/examples/serial_config.rs +++ b/examples/serial_config.rs @@ -1,6 +1,4 @@ -//! Serial interface loopback test -//! -//! You have to short the TX and RX pins to make this program work +//! Serial Config test #![deny(unsafe_code)] #![allow(clippy::empty_loop)] @@ -40,27 +38,22 @@ fn main() -> ! { // USART1 // let tx = gpioa.pa9.into_alternate_push_pull(&mut gpioa.crh); - // let rx = gpioa.pa10; // USART1 // let tx = gpiob.pb6.into_alternate_push_pull(&mut gpiob.crl); - // let rx = gpiob.pb7; // USART2 // let tx = gpioa.pa2.into_alternate_push_pull(&mut gpioa.crl); - // let rx = gpioa.pa3; // USART3 // Configure pb10 as a push_pull output, this will be the tx pin let tx = gpiob.pb10.into_alternate_push_pull(&mut gpiob.crh); - // Take ownership over pb11 - let rx = gpiob.pb11; - // Set up the usart device. Take ownership over the USART register and tx/rx pins. The rest of + // Set up the usart device. Take ownership over the USART register and tx pin. The rest of // the registers are used to enable and configure the device. - let serial = Serial::new( + let mut tx = Serial::tx( p.USART3, - (tx, rx, &mut afio.mapr), + (tx, &mut afio.mapr), serial::Config::default() .baudrate(9600.bps()) .stopbits(serial::StopBits::STOP2) @@ -69,9 +62,6 @@ fn main() -> ! { &clocks, ); - // Split the serial struct into a receiving and a transmitting part - let (mut tx, _rx) = serial.split(); - let sent = b'U'; block!(tx.write_u8(sent)).unwrap(); block!(tx.write_u8(sent)).unwrap(); diff --git a/examples/spi-slave.rs b/examples/spi-slave.rs index 0f7ae712..313ddd9a 100644 --- a/examples/spi-slave.rs +++ b/examples/spi-slave.rs @@ -38,7 +38,7 @@ fn main() -> ! { let mut afio = dp.AFIO.constrain(); let gpioa = dp.GPIOA.split(); - let mut gpiob = dp.GPIOB.split(); + let gpiob = dp.GPIOB.split(); // SPI1 // Convert pins during SPI initialization @@ -53,7 +53,7 @@ fn main() -> ! { // SPI2 // Convert pins before SPI initialization let sck = gpiob.pb13; - let miso = gpiob.pb14.into_alternate_push_pull(&mut gpiob.crh); + let miso = gpiob.pb14; let mosi = gpiob.pb15; let spi2 = dp.SPI2.spi_slave((sck, miso, mosi), MODE); diff --git a/src/can.rs b/src/can.rs index 5ad0c3bc..cf619424 100644 --- a/src/can.rs +++ b/src/can.rs @@ -20,27 +20,39 @@ //! | RX | PB5 | PB12 | use crate::afio::MAPR; -use crate::gpio::{self, Alternate, Cr, Floating, Input, PinMode, PullUp}; +use crate::gpio::{self, Alternate, Cr, Floating, Input, NoPin, PinMode, PullUp, PushPull}; use crate::pac::{self, RCC}; pub trait InMode {} impl InMode for Floating {} impl InMode for PullUp {} +pub struct Pins { + pub tx: TX, + pub rx: RX, +} + +impl From<(TX, RX)> for Pins { + fn from(value: (TX, RX)) -> Self { + Self { + tx: value.0, + rx: value.1, + } + } +} + pub mod can1 { use super::*; remap! { - Pins: [ - #[cfg(not(feature = "connectivity"))] - All, Tx, Rx, PA12, PA11 => { |_, w| unsafe { w.can_remap().bits(0) } }; - #[cfg(feature = "connectivity")] - All, Tx, Rx, PA12, PA11 => { |_, w| unsafe { w.can1_remap().bits(0) } }; - #[cfg(not(feature = "connectivity"))] - Remap, RemapTx, RemapRx, PB9, PB8 => { |_, w| unsafe { w.can_remap().bits(10) } }; - #[cfg(feature = "connectivity")] - Remap, RemapTx, RemapRx, PB9, PB8 => { |_, w| unsafe { w.can1_remap().bits(10) } }; - ] + #[cfg(not(feature = "connectivity"))] + PA12, PA11 => { |_, w| unsafe { w.can_remap().bits(0) } }; + #[cfg(feature = "connectivity")] + PA12, PA11 => { |_, w| unsafe { w.can1_remap().bits(0) } }; + #[cfg(not(feature = "connectivity"))] + PB9, PB8 => { |_, w| unsafe { w.can_remap().bits(10) } }; + #[cfg(feature = "connectivity")] + PB9, PB8 => { |_, w| unsafe { w.can1_remap().bits(10) } }; } } @@ -49,39 +61,39 @@ pub mod can2 { use super::*; remap! { - Pins: [ - All, Tx, Rx, PB6, PB5 => { |_, w| w.can2_remap().bit(false) }; - Remap, RemapTx, RemapRx, PB13, PB12 => { |_, w| w.can2_remap().bit(true) }; - ] + PB6, PB5 => { |_, w| w.can2_remap().bit(false) }; + PB13, PB12 => { |_, w| w.can2_remap().bit(true) }; } } macro_rules! remap { - ($name:ident: [ - $($(#[$attr:meta])* $rname:ident, $txonly:ident, $rxonly:ident, $TX:ident, $RX:ident => { $remapex:expr };)+ - ]) => { - pub enum $name { + ($($(#[$attr:meta])* $TX:ident, $RX:ident => { $remapex:expr };)+) => { + pub enum Tx { $( $(#[$attr])* - $rname { tx: gpio::$TX, rx: gpio::$RX> }, - $(#[$attr])* - $txonly { tx: gpio::$TX }, + $TX(gpio::$TX), + )+ + None(NoPin), + } + pub enum Rx { + $( $(#[$attr])* - $rxonly { rx: gpio::$RX> }, + $RX(gpio::$RX>), )+ + None(NoPin), } $( $(#[$attr])* - impl From<(gpio::$TX, gpio::$RX>, &mut MAPR)> for $name { + impl From<(gpio::$TX, gpio::$RX>, &mut MAPR)> for Pins> { fn from(p: (gpio::$TX, gpio::$RX>, &mut MAPR)) -> Self { p.2.modify_mapr($remapex); - Self::$rname { tx: p.0, rx: p.1 } + Self { tx: Tx::$TX(p.0), rx: Rx::$RX(p.1) } } } $(#[$attr])* - impl From<(gpio::$TX, gpio::$RX, &mut MAPR)> for $name + impl From<(gpio::$TX, gpio::$RX, &mut MAPR)> for Pins> where Input: PinMode, PULL: InMode, @@ -91,21 +103,21 @@ macro_rules! remap { let tx = p.0.into_mode(&mut cr); let rx = p.1.into_mode(&mut cr); p.2.modify_mapr($remapex); - Self::$rname { tx, rx } + Self { tx: Tx::$TX(tx), rx: Rx::$RX(rx) } } } $(#[$attr])* - impl From<(gpio::$TX, &mut MAPR)> for $name { + impl From<(gpio::$TX, &mut MAPR)> for Pins> { fn from(p: (gpio::$TX, &mut MAPR)) -> Self { let tx = p.0.into_mode(&mut Cr); p.1.modify_mapr($remapex); - Self::$txonly { tx } + Self { tx: Tx::$TX(tx), rx: Rx::None(NoPin::new()) } } } $(#[$attr])* - impl From<(gpio::$RX, &mut MAPR)> for $name + impl From<(gpio::$RX, &mut MAPR)> for Pins> where Input: PinMode, PULL: InMode, @@ -113,7 +125,7 @@ macro_rules! remap { fn from(p: (gpio::$RX, &mut MAPR)) -> Self { let rx = p.0.into_mode(&mut Cr); p.1.modify_mapr($remapex); - Self::$rxonly { rx } + Self { tx: Tx::None(NoPin::new()), rx: Rx::$RX(rx) } } } )+ @@ -125,7 +137,7 @@ pub trait CanExt: Sized + Instance { fn can( self, #[cfg(not(feature = "connectivity"))] usb: pac::USB, - pins: impl Into>, + pins: impl Into>>, ) -> Can; fn can_loopback( self, @@ -137,7 +149,7 @@ impl CanExt for CAN { fn can( self, #[cfg(not(feature = "connectivity"))] usb: pac::USB, - pins: impl Into>, + pins: impl Into>>, ) -> Can { Can::new( self, @@ -159,21 +171,24 @@ impl CanExt for CAN { } pub trait Instance: crate::rcc::Enable { - type Pins; + type Tx; + type Rx; } impl Instance for pac::CAN1 { - type Pins = can1::Pins; + type Tx = can1::Tx; + type Rx = can1::Rx; } #[cfg(feature = "connectivity")] impl Instance for pac::CAN2 { - type Pins = can2::Pins; + type Tx = can2::Tx; + type Rx = can2::Rx; } /// Interface to the CAN peripheral. #[allow(unused)] pub struct Can { can: CAN, - pins: Option>, + pins: Option>>, } impl Can { @@ -184,7 +199,7 @@ impl Can { pub fn new( can: CAN, #[cfg(not(feature = "connectivity"))] _usb: pac::USB, - pins: impl Into>, + pins: impl Into>>, ) -> Can { let rcc = unsafe { &(*RCC::ptr()) }; CAN::enable(rcc); diff --git a/src/gpio.rs b/src/gpio.rs index 05be3321..bd1b62af 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -143,6 +143,14 @@ pub trait GpioExt { unsafe fn split_without_reset(self) -> Self::Parts; } +#[derive(Debug, Default)] +pub struct NoPin(PhantomData); +impl NoPin { + pub fn new() -> Self { + Self(PhantomData) + } +} + /// Marker trait for active states. pub trait Active {} diff --git a/src/i2c.rs b/src/i2c.rs index b3cb8b22..4480241a 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -85,15 +85,29 @@ impl From for Mode { } } +pub struct Pins { + pub scl: SCL, + pub sda: SDA, +} + +impl From<(SCL, SDA)> for Pins { + fn from(value: (SCL, SDA)) -> Self { + Self { + scl: value.0, + sda: value.1, + } + } +} + pub mod i2c1 { use crate::afio::MAPR; use super::*; remap! { - Pins: [ - No, PB6, PB7 => MAPR { |_, w| w.i2c1_remap().bit(false) }; - Remap, PB8, PB9 => MAPR { |_, w| w.i2c1_remap().bit(true) }; + [ + PB6, PB7 => MAPR { |_, w| w.i2c1_remap().bit(false) }; + PB8, PB9 => MAPR { |_, w| w.i2c1_remap().bit(true) }; ] } } @@ -101,37 +115,42 @@ pub mod i2c2 { use super::*; remap! { - Pins: [ - No, PB10, PB11; + [ + PB10, PB11; ] } } macro_rules! remap { - ($name:ident: [ - $($rname:ident, $SCL:ident, $SDA:ident $( => $MAPR:ident { $remapex:expr })?;)+ + ([ + $($SCL:ident, $SDA:ident $( => $MAPR:ident { $remapex:expr })?;)+ ]) => { - pub enum $name { + pub enum Scl { $( - $rname { scl: gpio::$SCL>, sda: gpio::$SDA> }, + $SCL(gpio::$SCL>), + )+ + } + pub enum Sda { + $( + $SDA(gpio::$SDA>), )+ } $( - impl From<(gpio::$SCL>, gpio::$SDA> $(, &mut $MAPR)?)> for $name { + impl From<(gpio::$SCL>, gpio::$SDA> $(, &mut $MAPR)?)> for Pins { fn from(p: (gpio::$SCL>, gpio::$SDA> $(, &mut $MAPR)?)) -> Self { $(p.2.modify_mapr($remapex);)? - Self::$rname { scl: p.0, sda: p.1 } + Self { scl: Scl::$SCL(p.0), sda: Sda::$SDA(p.1) } } } - impl From<(gpio::$SCL, gpio::$SDA $(, &mut $MAPR)?)> for $name { + impl From<(gpio::$SCL, gpio::$SDA $(, &mut $MAPR)?)> for Pins { fn from(p: (gpio::$SCL, gpio::$SDA $(, &mut $MAPR)?)) -> Self { let mut cr = Cr; let scl = p.0.into_mode(&mut cr); let sda = p.1.into_mode(&mut cr); $(p.2.modify_mapr($remapex);)? - Self::$rname { scl, sda } + Self { scl: Scl::$SCL(scl), sda: Sda::$SDA(sda) } } } )+ @@ -140,12 +159,17 @@ macro_rules! remap { use remap; pub trait I2cExt: Sized + Instance { - fn i2c(self, pins: impl Into, mode: impl Into, clocks: &Clocks) -> I2c; + fn i2c( + self, + pins: impl Into>, + mode: impl Into, + clocks: &Clocks, + ) -> I2c; #[allow(clippy::too_many_arguments)] fn blocking_i2c( self, - pins: impl Into, + pins: impl Into>, mode: impl Into, clocks: &Clocks, start_timeout_us: u32, @@ -164,7 +188,12 @@ pub trait I2cExt: Sized + Instance { } impl I2cExt for I2C { - fn i2c(self, pins: impl Into, mode: impl Into, clocks: &Clocks) -> I2c { + fn i2c( + self, + pins: impl Into>, + mode: impl Into, + clocks: &Clocks, + ) -> I2c { I2c::new(self, pins, mode, clocks) } } @@ -172,7 +201,7 @@ impl I2cExt for I2C { /// I2C peripheral operating in master mode pub struct I2c { i2c: I2C, - pins: I2C::Pins, + pins: (I2C::Scl, I2C::Sda), mode: Mode, pclk1: Hertz, } @@ -180,21 +209,24 @@ pub struct I2c { pub trait Instance: crate::Sealed + Deref + Enable + Reset + BusClock { - type Pins; + type Scl; + type Sda; } impl Instance for I2C1 { - type Pins = i2c1::Pins; + type Scl = i2c1::Scl; + type Sda = i2c1::Sda; } impl Instance for I2C2 { - type Pins = i2c2::Pins; + type Scl = i2c2::Scl; + type Sda = i2c2::Sda; } impl I2c { /// Creates a generic I2C object pub fn new( i2c: I2C, - pins: impl Into, + pins: impl Into>, mode: impl Into, clocks: &Clocks, ) -> Self { @@ -206,10 +238,11 @@ impl I2c { let pclk1 = I2C::clock(clocks); assert!(mode.get_frequency() <= kHz(400)); + let pins = pins.into(); let mut i2c = I2c { i2c, - pins: pins.into(), + pins: (pins.scl, pins.sda), mode, pclk1, }; @@ -284,7 +317,7 @@ impl I2c { } /// Releases the I2C peripheral and associated pins - pub fn release(self) -> (I2C, I2C::Pins) { + pub fn release(self) -> (I2C, (I2C::Scl, I2C::Sda)) { (self.i2c, self.pins) } } diff --git a/src/i2c/blocking.rs b/src/i2c/blocking.rs index 315adec1..58cda400 100644 --- a/src/i2c/blocking.rs +++ b/src/i2c/blocking.rs @@ -22,7 +22,7 @@ impl BlockingI2c { #[allow(clippy::too_many_arguments)] pub fn new( i2c: I2C, - pins: impl Into, + pins: impl Into>, mode: impl Into, clocks: &Clocks, start_timeout_us: u32, diff --git a/src/serial.rs b/src/serial.rs index 0c840c46..7cc5eaef 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -68,7 +68,7 @@ use embedded_dma::{ReadBuffer, WriteBuffer}; use crate::afio::MAPR; use crate::dma::{dma1, CircBuffer, RxDma, Transfer, TxDma, R, W}; -use crate::gpio::{self, Alternate, Cr, Floating, Input, PinMode, PullUp, PushPull}; +use crate::gpio::{self, Alternate, Cr, Floating, Input, NoPin, PinMode, PullUp, PushPull}; use crate::pac::{RCC, USART1, USART2, USART3}; use crate::rcc::{BusClock, Clocks, Enable, Reset}; use crate::time::{Bps, U32Ext}; @@ -80,16 +80,28 @@ pub trait InMode {} impl InMode for Floating {} impl InMode for PullUp {} +pub struct Pins { + pub tx: TX, + pub rx: RX, +} + +impl From<(TX, RX)> for Pins { + fn from(value: (TX, RX)) -> Self { + Self { + tx: value.0, + rx: value.1, + } + } +} + // USART REMAPPING, see: https://www.st.com/content/ccc/resource/technical/document/reference_manual/59/b9/ba/7f/11/af/43/d5/CD00171190.pdf/files/CD00171190.pdf/jcr:content/translations/en.CD00171190.pdf // Section 9.3.8 pub mod usart1 { use super::*; remap! { - Pins: [ - All, Tx, Rx, PA9, PA10 => { |_, w| w.usart1_remap().bit(false) }; - Remap, RemapTx, RemapRx, PB6, PB7 => { |_, w| w.usart1_remap().bit(true) }; - ] + PA9, PA10 => { |_, w| w.usart1_remap().bit(false) }; + PB6, PB7 => { |_, w| w.usart1_remap().bit(true) }; } } @@ -97,10 +109,8 @@ pub mod usart2 { use super::*; remap! { - Pins: [ - All, Tx, Rx, PA2, PA3 => { |_, w| w.usart2_remap().bit(false) }; - Remap, RemapTx, RemapRx, PD5, PD6 => { |_, w| w.usart2_remap().bit(true) }; - ] + PA2, PA3 => { |_, w| w.usart2_remap().bit(false) }; + PD5, PD6 => { |_, w| w.usart2_remap().bit(true) }; } } @@ -108,35 +118,36 @@ pub mod usart3 { use super::*; remap! { - Pins: [ - RxTx, Tx, Rx, PB10, PB11 => { |_, w| unsafe { w.usart3_remap().bits(0b00)} }; - Remap1, Remap1Tx, Remap1Rx, PC10, PC11 => { |_, w| unsafe { w.usart3_remap().bits(0b01)} }; - Remap2, Remap2Tx, Remap2Rx, PD8, PD9 => { |_, w| unsafe { w.usart3_remap().bits(0b11)} }; - ] + PB10, PB11 => { |_, w| unsafe { w.usart3_remap().bits(0b00)} }; + PC10, PC11 => { |_, w| unsafe { w.usart3_remap().bits(0b01)} }; + PD8, PD9 => { |_, w| unsafe { w.usart3_remap().bits(0b11)} }; } } macro_rules! remap { - ($name:ident: [ - $($rname:ident, $txonly:ident, $rxonly:ident, $TX:ident, $RX:ident => { $remapex:expr };)+ - ]) => { - pub enum $name { + ($($TX:ident, $RX:ident => { $remapex:expr };)+) => { + pub enum Tx { + $( + $TX(gpio::$TX>), + )+ + None(NoPin), + } + pub enum Rx { $( - $rname { tx: gpio::$TX>, rx: gpio::$RX> }, - $txonly { tx: gpio::$TX> }, - $rxonly { rx: gpio::$RX> }, + $RX(gpio::$RX>), )+ + None(NoPin), } $( - impl From<(gpio::$TX>, gpio::$RX>, &mut MAPR)> for $name { + impl From<(gpio::$TX>, gpio::$RX>, &mut MAPR)> for Pins, Rx> { fn from(p: (gpio::$TX>, gpio::$RX>, &mut MAPR)) -> Self { p.2.modify_mapr($remapex); - Self::$rname { tx: p.0, rx: p.1 } + Self { tx: Tx::$TX(p.0), rx: Rx::$RX(p.1) } } } - impl From<(gpio::$TX, gpio::$RX, &mut MAPR)> for $name + impl From<(gpio::$TX, gpio::$RX, &mut MAPR)> for Pins, Rx> where Alternate: PinMode, Input: PinMode, @@ -147,30 +158,35 @@ macro_rules! remap { let tx = p.0.into_mode(&mut cr); let rx = p.1.into_mode(&mut cr); p.2.modify_mapr($remapex); - Self::$rname { tx, rx } + Self { tx: Tx::$TX(tx), rx: Rx::$RX(rx) } } } - impl From<(gpio::$TX, &mut MAPR)> for $name + impl From<(gpio::$TX>, &mut MAPR)> for Pins, Rx> { + fn from(p: (gpio::$TX>, &mut MAPR)) -> Self { + p.1.modify_mapr($remapex); + Self { tx: Tx::$TX(p.0), rx: Rx::None(NoPin::new()) } + } + } + + impl From<(gpio::$TX, &mut MAPR)> for Pins, Rx> where Alternate: PinMode, { fn from(p: (gpio::$TX, &mut MAPR)) -> Self { let tx = p.0.into_mode(&mut Cr); p.1.modify_mapr($remapex); - Self::$txonly { tx } + Self { tx: Tx::$TX(tx), rx: Rx::None(NoPin::new()) } } } - impl From<(gpio::$RX, &mut MAPR)> for $name + impl From<(gpio::$RX>, &mut MAPR)> for Pins, Rx> where - Input: PinMode, PULL: InMode, { - fn from(p: (gpio::$RX, &mut MAPR)) -> Self { - let rx = p.0.into_mode(&mut Cr); + fn from(p: (gpio::$RX>, &mut MAPR)) -> Self { p.1.modify_mapr($remapex); - Self::$rxonly { rx } + Self { tx: Tx::None(NoPin::new()), rx: Rx::$RX(p.0) } } } )+ @@ -181,16 +197,32 @@ use remap; pub trait SerialExt: Sized + Instance { fn serial( self, - pins: impl Into>, + pins: impl Into, Self::Rx>>, config: impl Into, clocks: &Clocks, ) -> Serial; + fn tx( + self, + pins: impl Into, Self::Rx>>, + config: impl Into, + clocks: &Clocks, + ) -> Tx { + self.serial(pins.into(), config, clocks).split().0 + } + fn rx( + self, + pins: impl Into, Self::Rx>>, + config: impl Into, + clocks: &Clocks, + ) -> Rx { + self.serial(pins.into(), config, clocks).split().1 + } } impl SerialExt for USART { fn serial( self, - pins: impl Into>, + pins: impl Into, Self::Rx>>, config: impl Into, clocks: &Clocks, ) -> Serial { @@ -203,7 +235,8 @@ use crate::pac::usart1 as uart_base; pub trait Instance: crate::Sealed + Deref + Enable + Reset + BusClock { - type Pins; + type Tx; + type Rx; #[doc(hidden)] fn ptr() -> *const uart_base::RegisterBlock; @@ -213,7 +246,8 @@ macro_rules! inst { ($($USARTX:ident, $usart:ident;)+) => { $( impl Instance for $USARTX { - type Pins = $usart::Pins; + type Tx = $usart::Tx; + type Rx = $usart::Rx; fn ptr() -> *const uart_base::RegisterBlock { <$USARTX>::ptr() @@ -347,7 +381,8 @@ impl From for Config { pub struct Serial { pub tx: Tx, pub rx: Rx, - pub token: ReleaseToken>, + #[allow(clippy::type_complexity)] + pub token: ReleaseToken, USART::Rx)>, } /// Serial transmitter @@ -366,6 +401,28 @@ pub struct ReleaseToken { pins: PINS, } +impl Serial { + pub fn tx( + usart: USART, + pins: impl Into, USART::Rx>>, + config: impl Into, + clocks: &Clocks, + ) -> Tx { + Self::new(usart, pins.into(), config, clocks).split().0 + } +} + +impl Serial { + pub fn rx( + usart: USART, + pins: impl Into, USART::Rx>>, + config: impl Into, + clocks: &Clocks, + ) -> Rx { + Self::new(usart, pins.into(), config, clocks).split().1 + } +} + impl Serial { /// Configures the serial interface and creates the interface /// struct. @@ -384,7 +441,7 @@ impl Serial { /// corresponding pins. `APBX` is used to reset the USART.) pub fn new( usart: USART, - pins: impl Into>, + pins: impl Into, USART::Rx>>, config: impl Into, clocks: &Clocks, ) -> Self { @@ -414,7 +471,10 @@ impl Serial { rx: Rx { _usart: PhantomData, }, - token: ReleaseToken { usart, pins }, + token: ReleaseToken { + usart, + pins: (pins.tx, pins.rx), + }, } } @@ -448,7 +508,8 @@ impl Serial { /// // Release `Serial` /// let (usart, (tx_pin, rx_pin)) = serial.release(); /// ``` - pub fn release(self) -> (USART, USART::Pins) { + #[allow(clippy::type_complexity)] + pub fn release(self) -> (USART, (USART::Tx, USART::Rx)) { (self.token.usart, self.token.pins) } diff --git a/src/spi.rs b/src/spi.rs index 93c50419..c585f5f0 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -46,7 +46,7 @@ use crate::dma::dma1; #[cfg(feature = "connectivity")] use crate::dma::dma2; use crate::dma::{Receive, RxDma, RxTxDma, Transfer, TransferPayload, Transmit, TxDma, R, W}; -use crate::gpio::{self, Alternate, Cr, Floating, Input, PinMode, PullUp, PushPull}; +use crate::gpio::{self, Alternate, Cr, Floating, Input, NoPin, PinMode, PullUp, PushPull}; use crate::rcc::{BusClock, Clocks, Enable, Reset}; use crate::time::Hertz; @@ -108,14 +108,23 @@ pub trait InMode {} impl InMode for Floating {} impl InMode for PullUp {} +pub struct MasterPins { + pub sck: SCK, + pub mi: MISO, + pub mo: MOSI, +} +pub struct SlavePins { + pub sck: SCK, + pub so: MISO, + pub si: MOSI, +} + pub mod spi1 { use super::*; remap! { - MasterPins, SlavePins: [ - All, Nomosi, Nomiso, PA5, PA6, PA7 => MAPR { |_, w| w.spi1_remap().bit(false) }; - Remap, RemapNomosi, RemapNomiso, PB3, PB4, PB5 => MAPR { |_, w| w.spi1_remap().bit(true) }; - ] + PA5, PA6, PA7 => MAPR { |_, w| w.spi1_remap().bit(false) }; + PB3, PB4, PB5 => MAPR { |_, w| w.spi1_remap().bit(true) }; } } @@ -123,9 +132,7 @@ pub mod spi2 { use super::*; remap! { - MasterPins, SlavePins: [ - All, Nomosi, Nomiso, PB13, PB14, PB15; - ] + PB13, PB14, PB15; } } #[cfg(any(feature = "high", feature = "connectivity"))] @@ -133,56 +140,71 @@ pub mod spi3 { use super::*; remap! { - MasterPins, SlavePins: [ - #[cfg(not(feature = "connectivity"))] - All, Nomosi, Nomiso, PB3, PB4, PB5; - #[cfg(feature = "connectivity")] - All, Nomosi, Nomiso, PB3, PB4, PB5 => MAPR { |_, w| w.spi3_remap().bit(false) }; - #[cfg(feature = "connectivity")] - Remap, RemapNomosi, RemapNomiso, PC10, PC11, PC12 => MAPR { |_, w| w.spi3_remap().bit(true) }; - ] + #[cfg(not(feature = "connectivity"))] + PB3, PB4, PB5; + #[cfg(feature = "connectivity")] + PB3, PB4, PB5 => MAPR { |_, w| w.spi3_remap().bit(false) }; + #[cfg(feature = "connectivity")] + PC10, PC11, PC12 => MAPR { |_, w| w.spi3_remap().bit(true) }; } } macro_rules! remap { - ($master:ident, $slave:ident: [ - $($(#[$attr:meta])* $rname:ident, $nomosi:ident, $nomiso:ident, $SCK:ident, $MISO:ident, $MOSI:ident $( => $MAPR:ident { $remapex:expr })?;)+ - ]) => { - pub enum $master { + ( + $($(#[$attr:meta])* $SCK:ident, $MISO:ident, $MOSI:ident $( => $MAPR:ident { $remapex:expr })?;)+ + ) => { + pub enum Sck { $( $(#[$attr])* - $rname { sck: gpio::$SCK, miso: gpio::$MISO>, mosi: gpio::$MOSI }, - $(#[$attr])* - $nomosi { sck: gpio::$SCK, miso: gpio::$MISO> }, + $SCK(gpio::$SCK), + )+ + None(NoPin), + } + + pub enum Mi { + $( $(#[$attr])* - $nomiso { sck: gpio::$SCK, mosi: gpio::$MOSI }, + $MISO(gpio::$MISO>), )+ + None(NoPin), } - pub enum $slave { + pub enum So { $( $(#[$attr])* - $rname { sck: gpio::$SCK, miso: gpio::$MISO>, mosi: gpio::$MOSI> }, + $MISO(gpio::$MISO>), + )+ + None(NoPin), + } + + pub enum Mo { + $( $(#[$attr])* - $nomosi { sck: gpio::$SCK, miso: gpio::$MISO> }, + $MOSI(gpio::$MOSI), + )+ + None(NoPin), + } + + pub enum Si { + $( $(#[$attr])* - $nomiso { sck: gpio::$SCK, mosi: gpio::$MOSI> }, + $MOSI(gpio::$MOSI>), )+ + None(NoPin), } $( // For master mode - $(#[$attr])* - impl From<(gpio::$SCK, gpio::$MISO>, gpio::$MOSI $(, &mut $MAPR)?)> for $master { + impl From<(gpio::$SCK, gpio::$MISO>, gpio::$MOSI $(, &mut $MAPR)?)> for MasterPins, Mo> { fn from(p: (gpio::$SCK, gpio::$MISO>, gpio::$MOSI $(, &mut $MAPR)?)) -> Self { $(p.3.modify_mapr($remapex);)? - Self::$rname { sck: p.0, miso: p.1, mosi: p.2 } + Self { sck: Sck::$SCK(p.0), mi: Mi::$MISO(p.1), mo: Mo::$MOSI(p.2) } } } $(#[$attr])* - impl From<(gpio::$SCK, gpio::$MISO, gpio::$MOSI $(, &mut $MAPR)?)> for $master + impl From<(gpio::$SCK, gpio::$MISO, gpio::$MOSI $(, &mut $MAPR)?)> for MasterPins, Mo> where Input: PinMode, PULL: InMode, @@ -193,20 +215,20 @@ macro_rules! remap { let miso = p.1.into_mode(&mut cr); let mosi = p.2.into_mode(&mut cr); $(p.3.modify_mapr($remapex);)? - Self::$rname { sck, miso, mosi } + Self { sck: Sck::$SCK(sck), mi: Mi::$MISO(miso), mo: Mo::$MOSI(mosi) } } } $(#[$attr])* - impl From<(gpio::$SCK, gpio::$MISO> $(, &mut $MAPR)?)> for $master { + impl From<(gpio::$SCK, gpio::$MISO> $(, &mut $MAPR)?)> for MasterPins, Mo> { fn from(p: (gpio::$SCK, gpio::$MISO> $(, &mut $MAPR)?)) -> Self { $(p.2.modify_mapr($remapex);)? - Self::$nomosi { sck: p.0, miso: p.1 } + Self { sck: Sck::$SCK(p.0), mi: Mi::$MISO(p.1), mo: Mo::None(NoPin::new()) } } } $(#[$attr])* - impl From<(gpio::$SCK, gpio::$MISO $(, &mut $MAPR)?)> for $master + impl From<(gpio::$SCK, gpio::$MISO $(, &mut $MAPR)?)> for super::MasterPins, Mo> where Input: PinMode, PULL: InMode, @@ -216,33 +238,33 @@ macro_rules! remap { let sck = p.0.into_mode(&mut cr); let miso = p.1.into_mode(&mut cr); $(p.2.modify_mapr($remapex);)? - Self::$nomosi { sck, miso } + Self { sck: Sck::$SCK(sck), mi: Mi::$MISO(miso), mo: Mo::None(NoPin::new()) } } } $(#[$attr])* - impl From<(gpio::$SCK, gpio::$MOSI $(, &mut $MAPR)?)> for $master { + impl From<(gpio::$SCK, gpio::$MOSI $(, &mut $MAPR)?)> for super::MasterPins, Mo> { fn from(p: (gpio::$SCK, gpio::$MOSI $(, &mut $MAPR)?)) -> Self { let mut cr = Cr; let sck = p.0.into_mode(&mut cr); let mosi = p.1.into_mode(&mut cr); $(p.2.modify_mapr($remapex);)? - Self::$nomiso { sck, mosi } + Self { sck: Sck::$SCK(sck), mi: Mi::None(NoPin::new()), mo: Mo::$MOSI(mosi) } } } // For slave mode $(#[$attr])* - impl From<(gpio::$SCK, gpio::$MISO>, gpio::$MOSI> $(, &mut $MAPR)?)> for $slave { - fn from(p: (gpio::$SCK, gpio::$MISO>, gpio::$MOSI> $(, &mut $MAPR)?)) -> Self { + impl From<(gpio::$SCK, gpio::$MISO>, gpio::$MOSI> $(, &mut $MAPR)?)> for SlavePins, Si> { + fn from(p: (gpio::$SCK, gpio::$MISO>, gpio::$MOSI> $(, &mut $MAPR)?)) -> Self { $(p.3.modify_mapr($remapex);)? - Self::$rname { sck: p.0, miso: p.1, mosi: p.2 } + Self { sck: Sck::$SCK(p.0), so: So::$MISO(p.1), si: Si::$MOSI(p.2) } } } $(#[$attr])* - impl From<(gpio::$SCK, gpio::$MISO, gpio::$MOSI $(, &mut $MAPR)?)> for $slave + impl From<(gpio::$SCK, gpio::$MISO, gpio::$MOSI $(, &mut $MAPR)?)> for SlavePins, Si> where Alternate: PinMode, Input: PinMode, @@ -254,12 +276,12 @@ macro_rules! remap { let miso = p.1.into_mode(&mut cr); let mosi = p.2.into_mode(&mut cr); $(p.3.modify_mapr($remapex);)? - Self::$rname { sck, miso, mosi } + Self { sck: Sck::$SCK(sck), so: So::$MISO(miso), si: Si::$MOSI(mosi) } } } $(#[$attr])* - impl From<(gpio::$SCK, gpio::$MISO $(, &mut $MAPR)?)> for $slave + impl From<(gpio::$SCK, gpio::$MISO $(, &mut $MAPR)?)> for SlavePins, Si> where Alternate: PinMode, { @@ -268,12 +290,12 @@ macro_rules! remap { let sck = p.0.into_mode(&mut cr); let miso = p.1.into_mode(&mut cr); $(p.2.modify_mapr($remapex);)? - Self::$nomosi { sck, miso } + Self { sck: Sck::$SCK(sck), so: So::$MISO(miso), si: Si::None(NoPin::new()) } } } $(#[$attr])* - impl From<(gpio::$SCK, gpio::$MOSI $(, &mut $MAPR)?)> for $slave + impl From<(gpio::$SCK, gpio::$MOSI $(, &mut $MAPR)?)> for SlavePins, Si> where Input: PinMode, PULL: InMode, @@ -283,7 +305,7 @@ macro_rules! remap { let sck = p.0.into_mode(&mut cr); let mosi = p.1.into_mode(&mut cr); $(p.2.modify_mapr($remapex);)? - Self::$nomiso { sck, mosi } + Self { sck: Sck::$SCK(sck), so: So::None(NoPin::new()), si: Si::$MOSI(mosi) } } } )+ @@ -294,14 +316,14 @@ use remap; pub trait SpiExt: Sized + Instance { fn spi( self, - pins: impl Into>, + pins: impl Into, Self::Mo>>, mode: Mode, freq: Hertz, clocks: &Clocks, ) -> Spi; fn spi_u16( self, - pins: impl Into>, + pins: impl Into, Self::Mo>>, mode: Mode, freq: Hertz, clocks: &Clocks, @@ -310,12 +332,12 @@ pub trait SpiExt: Sized + Instance { } fn spi_slave( self, - pins: impl Into>, + pins: impl Into, Self::Si>>, mode: Mode, ) -> SpiSlave; fn spi_slave_u16( self, - pins: impl Into>, + pins: impl Into, Self::Si>>, mode: Mode, ) -> SpiSlave { Self::spi_slave(self, pins, mode).frame_size_16bit() @@ -325,7 +347,7 @@ pub trait SpiExt: Sized + Instance { impl SpiExt for SPI { fn spi( self, - pins: impl Into>, + pins: impl Into, Self::Mo>>, mode: Mode, freq: Hertz, clocks: &Clocks, @@ -334,7 +356,7 @@ impl SpiExt for SPI { } fn spi_slave( self, - pins: impl Into>, + pins: impl Into, Self::Si>>, mode: Mode, ) -> SpiSlave { SpiSlave::new(self, pins, mode) @@ -358,13 +380,13 @@ impl SpiInner { /// Spi in Master mode pub struct Spi { inner: SpiInner, - pins: SPI::MasterPins, + pins: (SPI::Sck, SPI::Mi, SPI::Mo), } /// Spi in Slave mode pub struct SpiSlave { inner: SpiInner, - pins: SPI::SlavePins, + pins: (SPI::Sck, SPI::So, SPI::Si), } impl Deref for Spi { @@ -405,22 +427,34 @@ pub enum SpiBitFormat { pub trait Instance: crate::Sealed + Deref + Enable + Reset + BusClock { - type MasterPins; - type SlavePins; + type Sck; + type Mi; + type So; + type Mo; + type Si; } impl Instance for pac::SPI1 { - type MasterPins = spi1::MasterPins; - type SlavePins = spi1::SlavePins; + type Sck = spi1::Sck; + type Mi = spi1::Mi; + type So = spi1::So; + type Mo = spi1::Mo; + type Si = spi1::Si; } impl Instance for pac::SPI2 { - type MasterPins = spi2::MasterPins; - type SlavePins = spi2::SlavePins; + type Sck = spi2::Sck; + type Mi = spi2::Mi; + type So = spi2::So; + type Mo = spi2::Mo; + type Si = spi2::Si; } #[cfg(any(feature = "high", feature = "connectivity"))] impl Instance for pac::SPI3 { - type MasterPins = spi3::MasterPins; - type SlavePins = spi3::SlavePins; + type Sck = spi3::Sck; + type Mi = spi3::Mi; + type So = spi3::So; + type Mo = spi3::Mo; + type Si = spi3::Si; } impl Spi { @@ -433,7 +467,7 @@ impl Spi { */ pub fn new( spi: SPI, - pins: impl Into>, + pins: impl Into, SPI::Mo>>, mode: Mode, freq: Hertz, clocks: &Clocks, @@ -487,11 +521,12 @@ impl Spi { Spi { inner: SpiInner::new(spi), - pins, + pins: (pins.sck, pins.mi, pins.mo), } } - pub fn release(self) -> (SPI, SPI::MasterPins) { + #[allow(clippy::type_complexity)] + pub fn release(self) -> (SPI, (SPI::Sck, SPI::Mi, SPI::Mo)) { (self.inner.spi, self.pins) } } @@ -504,7 +539,11 @@ impl SpiSlave { You can also use `NoMiso` or `NoMosi` if you don't want to use the pins */ - pub fn new(spi: SPI, pins: impl Into>, mode: Mode) -> Self { + pub fn new( + spi: SPI, + pins: impl Into, SPI::Si>>, + mode: Mode, + ) -> Self { // enable or reset SPI let rcc = unsafe { &(*RCC::ptr()) }; SPI::enable(rcc); @@ -540,11 +579,12 @@ impl SpiSlave { SpiSlave { inner: SpiInner::new(spi), - pins, + pins: (pins.sck, pins.so, pins.si), } } - pub fn release(self) -> (SPI, SPI::SlavePins) { + #[allow(clippy::type_complexity)] + pub fn release(self) -> (SPI, (SPI::Sck, SPI::So, SPI::Si)) { (self.inner.spi, self.pins) } }