Skip to content

Commit 545318b

Browse files
committed
OutputPort
1 parent 47bf264 commit 545318b

File tree

5 files changed

+135
-1
lines changed

5 files changed

+135
-1
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1111

1212
- Update readme, clippy fixes
1313

14+
- `OutPortX` (X = 2..8) and `OutPortArray` structures which can handle several pins at once [#426]
15+
16+
### Added
17+
18+
[#426]: https://github.com/stm32-rs/stm32f4xx-hal/pull/426
19+
1420
## [v0.14.0] - 2022-12-12
1521

1622
### Changed

src/gpio.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ mod dynamic;
7070
pub use dynamic::{Dynamic, DynamicPin};
7171
mod hal_02;
7272
mod hal_1;
73+
pub mod outport;
7374

7475
pub use embedded_hal::digital::v2::PinState;
7576

src/gpio/outport.rs

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
use super::*;
2+
3+
pub trait OutPort {
4+
type Target;
5+
fn outport(self) -> Self::Target;
6+
}
7+
8+
macro_rules! out_port {
9+
( $name:ident => $n:literal, ( $($i:literal),+ ), ( $($N:ident),+ ), ( $($d:ident),* )) => {
10+
pub struct $name<const P: char $(, const $N: u8)+> {
11+
$(pub $d: Pin<P, $N, Output<PushPull>>,)+
12+
}
13+
14+
impl<const P: char $(, const $N: u8)+> OutPort for ($(Pin<P, $N, Output<PushPull>>),+) {
15+
type Target = $name<P $(, $N)+>;
16+
fn outport(self) -> Self::Target {
17+
let ($($d),+) = self;
18+
Self::Target { $($d),+ }
19+
}
20+
}
21+
22+
#[allow(clippy::too_many_arguments)]
23+
impl<const P: char $(, const $N: u8)+> $name<P $(, $N)+> {
24+
pub const fn new(
25+
$($d: Pin<P, $N, Output<PushPull>>,)+
26+
) -> Self {
27+
Self { $($d),+ }
28+
}
29+
const fn mask() -> u32 {
30+
0 $( | (1 << { $N }))+
31+
}
32+
const fn value_for_write_bsrr(val: u32) -> u32 {
33+
0 $( | (1 << (if val & (1 << $i) != 0 { $N } else { $N + 16 })))+
34+
}
35+
36+
#[doc=concat!("Set/reset pins according to `", $n, "` lower bits")]
37+
#[inline(never)]
38+
pub fn write(&mut self, word: u32) {
39+
unsafe {
40+
(*Gpio::<P>::ptr())
41+
.bsrr
42+
.write(|w| w.bits(Self::value_for_write_bsrr(word)))
43+
}
44+
}
45+
46+
/// Sets all pins to `PinState::High`
47+
pub fn all_high(&mut self) {
48+
unsafe {
49+
(*Gpio::<P>::ptr())
50+
.bsrr
51+
.write(|w| w.bits(Self::mask()))
52+
}
53+
}
54+
55+
/// Sets all pins to `PinState::Low`
56+
pub fn all_low(&mut self) {
57+
unsafe {
58+
(*Gpio::<P>::ptr())
59+
.bsrr
60+
.write(|w| w.bits(Self::mask() << 16))
61+
}
62+
}
63+
}
64+
}
65+
}
66+
67+
out_port!(OutPort2 => 2, (0, 1), (N0, N1), (d0, d1));
68+
out_port!(OutPort3 => 3, (0, 1, 2), (N0, N1, N2), (d0, d1, d2));
69+
out_port!(OutPort4 => 4, (0, 1, 2, 3), (N0, N1, N2, N3), (d0, d1, d2, d3));
70+
out_port!(OutPort5 => 5, (0, 1, 2, 3, 4), (N0, N1, N2, N3, N4), (d0, d1, d2, d3, d4));
71+
out_port!(OutPort6 => 6, (0, 1, 2, 3, 4, 5), (N0, N1, N2, N3, N4, N5), (d0, d1, d2, d3, d4, d5));
72+
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));
73+
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));
74+
75+
pub struct OutPortArray<const P: char, const SIZE: usize>(pub [PEPin<P, Output<PushPull>>; SIZE]);
76+
77+
impl<const P: char, const SIZE: usize> OutPort for [PEPin<P, Output<PushPull>>; SIZE] {
78+
type Target = OutPortArray<P, SIZE>;
79+
fn outport(self) -> Self::Target {
80+
OutPortArray(self)
81+
}
82+
}
83+
84+
impl<const P: char, const SIZE: usize> OutPortArray<P, SIZE> {
85+
fn mask(&self) -> u32 {
86+
let mut msk = 0;
87+
let mut iter = self.0.iter();
88+
while let Some(pin) = iter.next() {
89+
msk |= 1 << pin.i;
90+
}
91+
msk
92+
}
93+
fn value_for_write_bsrr(&self, val: u32) -> u32 {
94+
let mut msk = 0;
95+
let mut iter = 0..SIZE;
96+
while let Some(pin) = iter.next() {
97+
let n = self.0[pin].i;
98+
msk |= 1 << (1 << (if val & (1 << pin) != 0 { n } else { n + 16 }));
99+
}
100+
msk
101+
}
102+
103+
/// Set/reset pins according to `SIZE` lower bits
104+
#[inline(never)]
105+
pub fn write(&mut self, word: u32) {
106+
unsafe {
107+
(*Gpio::<P>::ptr())
108+
.bsrr
109+
.write(|w| w.bits(self.value_for_write_bsrr(word)))
110+
}
111+
}
112+
113+
/// Sets all pins to `PinState::High`
114+
pub fn all_high(&mut self) {
115+
unsafe { (*Gpio::<P>::ptr()).bsrr.write(|w| w.bits(self.mask())) }
116+
}
117+
118+
/// Sets all pins to `PinState::Low`
119+
pub fn all_low(&mut self) {
120+
unsafe {
121+
(*Gpio::<P>::ptr())
122+
.bsrr
123+
.write(|w| w.bits(self.mask() << 16))
124+
}
125+
}
126+
}

src/gpio/partially_erased.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ pub type PEPin<const P: char, MODE> = PartiallyErasedPin<P, MODE>;
77
/// - `MODE` is one of the pin modes (see [Modes](crate::gpio#modes) section).
88
/// - `P` is port name: `A` for GPIOA, `B` for GPIOB, etc.
99
pub struct PartiallyErasedPin<const P: char, MODE> {
10-
i: u8,
10+
pub(crate) i: u8,
1111
_mode: PhantomData<MODE>,
1212
}
1313

src/prelude.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ pub use fugit::RateExtU32 as _fugit_RateExtU32;
6060
pub use crate::can::CanExt as _stm32f4xx_hal_can_CanExt;
6161
#[cfg(all(feature = "device-selected", feature = "dac"))]
6262
pub use crate::dac::DacExt as _stm32f4xx_hal_dac_DacExt;
63+
pub use crate::gpio::outport::OutPort as _;
6364
pub use crate::gpio::ExtiPin as _stm32f4xx_hal_gpio_ExtiPin;
6465
pub use crate::gpio::GpioExt as _stm32f4xx_hal_gpio_GpioExt;
6566
pub use crate::i2c::I2cExt as _stm32f4xx_hal_i2c_I2cExt;

0 commit comments

Comments
 (0)