From 545318bdf47ecb6b3fccd30cda8aa34832763776 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Mon, 5 Jul 2021 19:53:40 +0300 Subject: [PATCH 1/2] OutputPort --- CHANGELOG.md | 6 ++ src/gpio.rs | 1 + src/gpio/outport.rs | 126 +++++++++++++++++++++++++++++++++++ src/gpio/partially_erased.rs | 2 +- src/prelude.rs | 1 + 5 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 src/gpio/outport.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ac4b3fd..a353e8b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Update readme, clippy fixes +- `OutPortX` (X = 2..8) and `OutPortArray` structures which can handle several pins at once [#426] + +### Added + +[#426]: https://github.com/stm32-rs/stm32f4xx-hal/pull/426 + ## [v0.14.0] - 2022-12-12 ### Changed diff --git a/src/gpio.rs b/src/gpio.rs index 6dc226f0..917b3669 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -70,6 +70,7 @@ mod dynamic; pub use dynamic::{Dynamic, DynamicPin}; mod hal_02; mod hal_1; +pub mod outport; pub use embedded_hal::digital::v2::PinState; diff --git a/src/gpio/outport.rs b/src/gpio/outport.rs new file mode 100644 index 00000000..378f5644 --- /dev/null +++ b/src/gpio/outport.rs @@ -0,0 +1,126 @@ +use super::*; + +pub trait OutPort { + type Target; + fn outport(self) -> Self::Target; +} + +macro_rules! out_port { + ( $name:ident => $n:literal, ( $($i:literal),+ ), ( $($N:ident),+ ), ( $($d:ident),* )) => { + pub struct $name { + $(pub $d: Pin>,)+ + } + + impl OutPort for ($(Pin>),+) { + type Target = $name

; + fn outport(self) -> Self::Target { + let ($($d),+) = self; + Self::Target { $($d),+ } + } + } + + #[allow(clippy::too_many_arguments)] + impl $name

{ + pub const fn new( + $($d: Pin>,)+ + ) -> Self { + Self { $($d),+ } + } + const fn mask() -> u32 { + 0 $( | (1 << { $N }))+ + } + const fn value_for_write_bsrr(val: u32) -> u32 { + 0 $( | (1 << (if val & (1 << $i) != 0 { $N } else { $N + 16 })))+ + } + + #[doc=concat!("Set/reset pins according to `", $n, "` lower bits")] + #[inline(never)] + pub fn write(&mut self, word: u32) { + unsafe { + (*Gpio::

::ptr()) + .bsrr + .write(|w| w.bits(Self::value_for_write_bsrr(word))) + } + } + + /// Sets all pins to `PinState::High` + pub fn all_high(&mut self) { + unsafe { + (*Gpio::

::ptr()) + .bsrr + .write(|w| w.bits(Self::mask())) + } + } + + /// Sets all pins to `PinState::Low` + pub fn all_low(&mut self) { + unsafe { + (*Gpio::

::ptr()) + .bsrr + .write(|w| w.bits(Self::mask() << 16)) + } + } + } + } +} + +out_port!(OutPort2 => 2, (0, 1), (N0, N1), (d0, d1)); +out_port!(OutPort3 => 3, (0, 1, 2), (N0, N1, N2), (d0, d1, d2)); +out_port!(OutPort4 => 4, (0, 1, 2, 3), (N0, N1, N2, N3), (d0, d1, d2, d3)); +out_port!(OutPort5 => 5, (0, 1, 2, 3, 4), (N0, N1, N2, N3, N4), (d0, d1, d2, d3, d4)); +out_port!(OutPort6 => 6, (0, 1, 2, 3, 4, 5), (N0, N1, N2, N3, N4, N5), (d0, d1, d2, d3, d4, d5)); +out_port!(OutPort7 => 7, (0, 1, 2, 3, 4, 5, 6), (N0, N1, N2, N3, N4, N5, N6), (d0, d1, d2, d3, d4, d5, d6)); +out_port!(OutPort8 => 8, (0, 1, 2, 3, 4, 5, 6, 7), (N0, N1, N2, N3, N4, N5, N6, N7), (d0, d1, d2, d3, d4, d5, d6, d7)); + +pub struct OutPortArray(pub [PEPin>; SIZE]); + +impl OutPort for [PEPin>; SIZE] { + type Target = OutPortArray; + fn outport(self) -> Self::Target { + OutPortArray(self) + } +} + +impl OutPortArray { + fn mask(&self) -> u32 { + let mut msk = 0; + let mut iter = self.0.iter(); + while let Some(pin) = iter.next() { + msk |= 1 << pin.i; + } + msk + } + fn value_for_write_bsrr(&self, val: u32) -> u32 { + let mut msk = 0; + let mut iter = 0..SIZE; + while let Some(pin) = iter.next() { + let n = self.0[pin].i; + msk |= 1 << (1 << (if val & (1 << pin) != 0 { n } else { n + 16 })); + } + msk + } + + /// Set/reset pins according to `SIZE` lower bits + #[inline(never)] + pub fn write(&mut self, word: u32) { + unsafe { + (*Gpio::

::ptr()) + .bsrr + .write(|w| w.bits(self.value_for_write_bsrr(word))) + } + } + + /// Sets all pins to `PinState::High` + pub fn all_high(&mut self) { + unsafe { (*Gpio::

::ptr()).bsrr.write(|w| w.bits(self.mask())) } + } + + /// Sets all pins to `PinState::Low` + pub fn all_low(&mut self) { + unsafe { + (*Gpio::

::ptr()) + .bsrr + .write(|w| w.bits(self.mask() << 16)) + } + } +} diff --git a/src/gpio/partially_erased.rs b/src/gpio/partially_erased.rs index b5188af6..66a36863 100644 --- a/src/gpio/partially_erased.rs +++ b/src/gpio/partially_erased.rs @@ -7,7 +7,7 @@ pub type PEPin = PartiallyErasedPin; /// - `MODE` is one of the pin modes (see [Modes](crate::gpio#modes) section). /// - `P` is port name: `A` for GPIOA, `B` for GPIOB, etc. pub struct PartiallyErasedPin { - i: u8, + pub(crate) i: u8, _mode: PhantomData, } diff --git a/src/prelude.rs b/src/prelude.rs index 65525ddc..5b29a6e8 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -60,6 +60,7 @@ pub use fugit::RateExtU32 as _fugit_RateExtU32; pub use crate::can::CanExt as _stm32f4xx_hal_can_CanExt; #[cfg(all(feature = "device-selected", feature = "dac"))] pub use crate::dac::DacExt as _stm32f4xx_hal_dac_DacExt; +pub use crate::gpio::outport::OutPort as _; pub use crate::gpio::ExtiPin as _stm32f4xx_hal_gpio_ExtiPin; pub use crate::gpio::GpioExt as _stm32f4xx_hal_gpio_GpioExt; pub use crate::i2c::I2cExt as _stm32f4xx_hal_i2c_I2cExt; From 5a22740d735f7c7dd4534e0a9c33da308fcf7e2c Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Tue, 20 Dec 2022 16:22:35 +0300 Subject: [PATCH 2/2] wrap tuple --- src/gpio/outport.rs | 52 ++++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 29 deletions(-) diff --git a/src/gpio/outport.rs b/src/gpio/outport.rs index 378f5644..ef0c4bcb 100644 --- a/src/gpio/outport.rs +++ b/src/gpio/outport.rs @@ -1,31 +1,26 @@ use super::*; +/// Convert tuple or array of pins to output port pub trait OutPort { type Target; fn outport(self) -> Self::Target; } macro_rules! out_port { - ( $name:ident => $n:literal, ( $($i:literal),+ ), ( $($N:ident),+ ), ( $($d:ident),* )) => { - pub struct $name { - $(pub $d: Pin>,)+ - } + ( $name:ident => $n:literal, ( $($i:literal),+ ), ( $($N:ident),+ )) => { + pub struct $name ( + pub ($(Pin>,)+) + ); impl OutPort for ($(Pin>),+) { type Target = $name

; fn outport(self) -> Self::Target { - let ($($d),+) = self; - Self::Target { $($d),+ } + $name(self) } } - #[allow(clippy::too_many_arguments)] + /// Wrapper for tuple of `Pin`s impl $name

{ - pub const fn new( - $($d: Pin>,)+ - ) -> Self { - Self { $($d),+ } - } const fn mask() -> u32 { 0 $( | (1 << { $N }))+ } @@ -43,7 +38,7 @@ macro_rules! out_port { } } - /// Sets all pins to `PinState::High` + /// Set all pins to `PinState::High` pub fn all_high(&mut self) { unsafe { (*Gpio::

::ptr()) @@ -52,7 +47,7 @@ macro_rules! out_port { } } - /// Sets all pins to `PinState::Low` + /// Reset all pins to `PinState::Low` pub fn all_low(&mut self) { unsafe { (*Gpio::

::ptr()) @@ -64,14 +59,15 @@ macro_rules! out_port { } } -out_port!(OutPort2 => 2, (0, 1), (N0, N1), (d0, d1)); -out_port!(OutPort3 => 3, (0, 1, 2), (N0, N1, N2), (d0, d1, d2)); -out_port!(OutPort4 => 4, (0, 1, 2, 3), (N0, N1, N2, N3), (d0, d1, d2, d3)); -out_port!(OutPort5 => 5, (0, 1, 2, 3, 4), (N0, N1, N2, N3, N4), (d0, d1, d2, d3, d4)); -out_port!(OutPort6 => 6, (0, 1, 2, 3, 4, 5), (N0, N1, N2, N3, N4, N5), (d0, d1, d2, d3, d4, d5)); -out_port!(OutPort7 => 7, (0, 1, 2, 3, 4, 5, 6), (N0, N1, N2, N3, N4, N5, N6), (d0, d1, d2, d3, d4, d5, d6)); -out_port!(OutPort8 => 8, (0, 1, 2, 3, 4, 5, 6, 7), (N0, N1, N2, N3, N4, N5, N6, N7), (d0, d1, d2, d3, d4, d5, d6, d7)); +out_port!(OutPort2 => 2, (0, 1), (N0, N1)); +out_port!(OutPort3 => 3, (0, 1, 2), (N0, N1, N2)); +out_port!(OutPort4 => 4, (0, 1, 2, 3), (N0, N1, N2, N3)); +out_port!(OutPort5 => 5, (0, 1, 2, 3, 4), (N0, N1, N2, N3, N4)); +out_port!(OutPort6 => 6, (0, 1, 2, 3, 4, 5), (N0, N1, N2, N3, N4, N5)); +out_port!(OutPort7 => 7, (0, 1, 2, 3, 4, 5, 6), (N0, N1, N2, N3, N4, N5, N6)); +out_port!(OutPort8 => 8, (0, 1, 2, 3, 4, 5, 6, 7), (N0, N1, N2, N3, N4, N5, N6, N7)); +/// Wrapper for array of `PartiallyErasedPin`s pub struct OutPortArray(pub [PEPin>; SIZE]); impl OutPort for [PEPin>; SIZE] { @@ -84,18 +80,16 @@ impl OutPort for [PEPin>; impl OutPortArray { fn mask(&self) -> u32 { let mut msk = 0; - let mut iter = self.0.iter(); - while let Some(pin) = iter.next() { + for pin in self.0.iter() { msk |= 1 << pin.i; } msk } fn value_for_write_bsrr(&self, val: u32) -> u32 { let mut msk = 0; - let mut iter = 0..SIZE; - while let Some(pin) = iter.next() { - let n = self.0[pin].i; - msk |= 1 << (1 << (if val & (1 << pin) != 0 { n } else { n + 16 })); + for (idx, pin) in self.0.iter().enumerate() { + let n = pin.i; + msk |= 1 << (if val & (1 << idx) != 0 { n } else { n + 16 }); } msk } @@ -110,12 +104,12 @@ impl OutPortArray { } } - /// Sets all pins to `PinState::High` + /// Set all pins to `PinState::High` pub fn all_high(&mut self) { unsafe { (*Gpio::

::ptr()).bsrr.write(|w| w.bits(self.mask())) } } - /// Sets all pins to `PinState::Low` + /// Reset all pins to `PinState::Low` pub fn all_low(&mut self) { unsafe { (*Gpio::

::ptr())