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..ef0c4bcb --- /dev/null +++ b/src/gpio/outport.rs @@ -0,0 +1,120 @@ +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),+ )) => { + pub struct $name ( + pub ($(Pin>,)+) + ); + + impl OutPort for ($(Pin>),+) { + type Target = $name

; + fn outport(self) -> Self::Target { + $name(self) + } + } + + /// Wrapper for tuple of `Pin`s + impl $name

{ + 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))) + } + } + + /// Set all pins to `PinState::High` + pub fn all_high(&mut self) { + unsafe { + (*Gpio::

::ptr()) + .bsrr + .write(|w| w.bits(Self::mask())) + } + } + + /// Reset 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)); +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] { + type Target = OutPortArray; + fn outport(self) -> Self::Target { + OutPortArray(self) + } +} + +impl OutPortArray { + fn mask(&self) -> u32 { + let mut msk = 0; + for pin in self.0.iter() { + msk |= 1 << pin.i; + } + msk + } + fn value_for_write_bsrr(&self, val: u32) -> u32 { + let mut msk = 0; + for (idx, pin) in self.0.iter().enumerate() { + let n = pin.i; + msk |= 1 << (if val & (1 << idx) != 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))) + } + } + + /// Set all pins to `PinState::High` + pub fn all_high(&mut self) { + unsafe { (*Gpio::

::ptr()).bsrr.write(|w| w.bits(self.mask())) } + } + + /// Reset 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;