Skip to content

Commit 980c658

Browse files
bors[bot]burrbull
andauthored
Merge #426
426: OutputPort r=therealprof a=burrbull ~~This is draft of [`OutputPort<u8>`](rust-embedded/embedded-hal#134 Co-authored-by: Andrey Zgarbul <[email protected]>
2 parents 47bf264 + 5a22740 commit 980c658

File tree

5 files changed

+129
-1
lines changed

5 files changed

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

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)