Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Serial/SPI/I2C/CAN split pin enums #509

Merged
merged 1 commit into from
Oct 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -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

Expand All @@ -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
Expand All @@ -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

Expand Down
18 changes: 4 additions & 14 deletions examples/serial_config.rs
Original file line number Diff line number Diff line change
@@ -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)]
Expand Down Expand Up @@ -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)
Expand All @@ -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();
Expand Down
4 changes: 2 additions & 2 deletions examples/spi-slave.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@

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
Expand All @@ -53,7 +53,7 @@
// 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);
Expand Down Expand Up @@ -84,7 +84,7 @@
spi2.listen(Event::Error);

cortex_m::interrupt::free(|_| unsafe {
SPI2SLAVE.replace(spi2);

Check warning on line 87 in examples/spi-slave.rs

View workflow job for this annotation

GitHub Actions / check (nightly, stm32f103, true)

creating a mutable reference to mutable static is discouraged
});

unsafe {
Expand All @@ -108,7 +108,7 @@
#[interrupt]
unsafe fn SPI2() {
cortex_m::interrupt::free(|_| {
if let Some(spi2) = SPI2SLAVE.as_mut() {

Check warning on line 111 in examples/spi-slave.rs

View workflow job for this annotation

GitHub Actions / check (nightly, stm32f103, true)

creating a mutable reference to mutable static is discouraged
if spi2.is_overrun() {
// mcu processing speed is not enough
asm::bkpt();
Expand Down
91 changes: 53 additions & 38 deletions src/can.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<TX, RX> {
pub tx: TX,
pub rx: RX,
}

impl<TX, RX> From<(TX, RX)> for Pins<TX, RX> {
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) } };
}
}

Expand All @@ -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<PULL> {
($($(#[$attr:meta])* $TX:ident, $RX:ident => { $remapex:expr };)+) => {
pub enum Tx {
$(
$(#[$attr])*
$rname { tx: gpio::$TX<Alternate>, rx: gpio::$RX<Input<PULL>> },
$(#[$attr])*
$txonly { tx: gpio::$TX<Alternate> },
$TX(gpio::$TX<Alternate>),
)+
None(NoPin<PushPull>),
}
pub enum Rx<PULL> {
$(
$(#[$attr])*
$rxonly { rx: gpio::$RX<Input<PULL>> },
$RX(gpio::$RX<Input<PULL>>),
)+
None(NoPin<PULL>),
}

$(
$(#[$attr])*
impl<PULL: InMode> From<(gpio::$TX<Alternate>, gpio::$RX<Input<PULL>>, &mut MAPR)> for $name<PULL> {
impl<PULL: InMode> From<(gpio::$TX<Alternate>, gpio::$RX<Input<PULL>>, &mut MAPR)> for Pins<Tx, Rx<PULL>> {
fn from(p: (gpio::$TX<Alternate>, gpio::$RX<Input<PULL>>, &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<PULL> From<(gpio::$TX, gpio::$RX, &mut MAPR)> for $name<PULL>
impl<PULL> From<(gpio::$TX, gpio::$RX, &mut MAPR)> for Pins<Tx, Rx<PULL>>
where
Input<PULL>: PinMode,
PULL: InMode,
Expand All @@ -91,29 +103,29 @@ 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<Floating> {
impl From<(gpio::$TX, &mut MAPR)> for Pins<Tx, Rx<Floating>> {
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<PULL> From<(gpio::$RX, &mut MAPR)> for $name<PULL>
impl<PULL> From<(gpio::$RX, &mut MAPR)> for Pins<Tx, Rx<PULL>>
where
Input<PULL>: PinMode,
PULL: InMode,
{
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) }
}
}
)+
Expand All @@ -125,7 +137,7 @@ pub trait CanExt: Sized + Instance {
fn can(
self,
#[cfg(not(feature = "connectivity"))] usb: pac::USB,
pins: impl Into<Self::Pins<Floating>>,
pins: impl Into<Pins<Self::Tx, Self::Rx<Floating>>>,
) -> Can<Self, Floating>;
fn can_loopback(
self,
Expand All @@ -137,7 +149,7 @@ impl<CAN: Instance> CanExt for CAN {
fn can(
self,
#[cfg(not(feature = "connectivity"))] usb: pac::USB,
pins: impl Into<Self::Pins<Floating>>,
pins: impl Into<Pins<Self::Tx, Self::Rx<Floating>>>,
) -> Can<Self, Floating> {
Can::new(
self,
Expand All @@ -159,21 +171,24 @@ impl<CAN: Instance> CanExt for CAN {
}

pub trait Instance: crate::rcc::Enable {
type Pins<PULL>;
type Tx;
type Rx<PULL>;
}
impl Instance for pac::CAN1 {
type Pins<PULL> = can1::Pins<PULL>;
type Tx = can1::Tx;
type Rx<PULL> = can1::Rx<PULL>;
}
#[cfg(feature = "connectivity")]
impl Instance for pac::CAN2 {
type Pins<PULL> = can2::Pins<PULL>;
type Tx = can2::Tx;
type Rx<PULL> = can2::Rx<PULL>;
}

/// Interface to the CAN peripheral.
#[allow(unused)]
pub struct Can<CAN: Instance, PULL = Floating> {
can: CAN,
pins: Option<CAN::Pins<PULL>>,
pins: Option<Pins<CAN::Tx, CAN::Rx<PULL>>>,
}

impl<CAN: Instance, PULL> Can<CAN, PULL> {
Expand All @@ -184,7 +199,7 @@ impl<CAN: Instance, PULL> Can<CAN, PULL> {
pub fn new(
can: CAN,
#[cfg(not(feature = "connectivity"))] _usb: pac::USB,
pins: impl Into<CAN::Pins<PULL>>,
pins: impl Into<Pins<CAN::Tx, CAN::Rx<PULL>>>,
) -> Can<CAN, PULL> {
let rcc = unsafe { &(*RCC::ptr()) };
CAN::enable(rcc);
Expand Down
8 changes: 8 additions & 0 deletions src/gpio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,14 @@ pub trait GpioExt {
unsafe fn split_without_reset(self) -> Self::Parts;
}

#[derive(Debug, Default)]
pub struct NoPin<MODE>(PhantomData<MODE>);
impl<MODE> NoPin<MODE> {
pub fn new() -> Self {
Self(PhantomData)
}
}

/// Marker trait for active states.
pub trait Active {}

Expand Down
Loading
Loading