Skip to content

Commit b682a2a

Browse files
committed
parallel-gpio: Add and use OutputBus trait
1 parent cfdaae3 commit b682a2a

File tree

2 files changed

+118
-149
lines changed

2 files changed

+118
-149
lines changed

CHANGELOG.md

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

1212
- New `DisplayError` variant `RSError` to use with problems with the display's reset signal
1313
- New `DisplayError` variant `OutOfBoundsError` to use when writing to a non-existing pixel outside the display's bounds
14+
- parallel-gpio: New `OutputBus` trait
15+
- parallel-gpio: Added `Generic8BitBus`, an implementation of `OutputBus`
1416

1517
### Changed
1618

1719
- Return `DCError` instead of `BusWriteError` on errors (de-)asserting the DC signal in 8-bit GPIO interfaces
20+
- **Breaking** parallel-gpio: `PGPIO8BitInterface` now uses any 8-bit impementation of `OutputBus` instead of 8 individual pins
1821

1922
## [v0.4.0] - 2020-05-25
2023

parallel-gpio/src/lib.rs

Lines changed: 115 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -6,182 +6,148 @@ use embedded_hal::digital::v2::OutputPin;
66

77
pub use display_interface::{DataFormat, DisplayError, WriteOnlyDataCommand};
88

9+
/// This trait represents the data pins of a parallel bus.
10+
///
11+
/// See [Generic8BitBus] for a generic implementation.
12+
pub trait OutputBus {
13+
/// [u8] for 8-bit busses, [u16] for 16-bit busses, etc.
14+
type Word: Copy;
15+
16+
fn set_value(&mut self, value: Self::Word) -> Result<(), DisplayError>;
17+
}
18+
19+
macro_rules! generic_bus {
20+
($GenericxBitBus:ident { type Word = $Word:ident; Pins {$($PX:ident => $x:tt,)*}}) => {
21+
/// A generic implementation of [OutputBus] using [OutputPin]s
22+
pub struct $GenericxBitBus<$($PX, )*> {
23+
pins: ($($PX, )*),
24+
last: $Word,
25+
}
26+
27+
impl<$($PX, )*> $GenericxBitBus<$($PX, )*>
28+
where
29+
$($PX: OutputPin, )*
30+
{
31+
/// Creates a new instance and initializes the bus to `0`.
32+
///
33+
/// The first pin in the tuple is the least significant bit.
34+
pub fn new(pins: ($($PX, )*)) -> Result<Self, DisplayError> {
35+
let mut bus = Self { pins, last: $Word::MAX };
36+
37+
// By setting `last` to all ones, we ensure that this will update all the pins
38+
bus.set_value(0)?;
39+
40+
Ok(bus)
41+
}
42+
43+
/// Consumes the bus and returns the pins. This does not change the state of the pins.
44+
pub fn release(self) -> ($($PX, )*) {
45+
self.pins
46+
}
47+
}
48+
49+
impl<$($PX, )*> OutputBus
50+
for $GenericxBitBus<$($PX, )*>
51+
where
52+
$($PX: OutputPin, )*
53+
{
54+
type Word = $Word;
55+
56+
fn set_value(&mut self, value: Self::Word) -> Result<(), DisplayError> {
57+
let changed = value ^ self.last;
58+
59+
// It's quite common for multiple consecutive values to be identical, e.g. when filling or
60+
// clearing the screen, so let's optimize for that case
61+
if changed != 0 {
62+
$(
63+
let mask = 1 << $x;
64+
if changed & mask != 0 {
65+
if value & mask != 0 {
66+
self.pins.$x.set_high()
67+
} else {
68+
self.pins.$x.set_low()
69+
}
70+
.map_err(|_| DisplayError::BusWriteError)?;
71+
}
72+
)*
73+
74+
self.last = value;
75+
}
76+
77+
Ok(())
78+
}
79+
}
80+
81+
impl<$($PX, )*> core::convert::TryFrom<($($PX, )*)>
82+
for $GenericxBitBus<$($PX, )*>
83+
where
84+
$($PX: OutputPin, )*
85+
{
86+
type Error = DisplayError;
87+
88+
fn try_from(pins: ($($PX, )*)) -> Result<Self, Self::Error> {
89+
Self::new(pins)
90+
}
91+
}
92+
};
93+
}
94+
95+
generic_bus! {
96+
Generic8BitBus {
97+
type Word = u8;
98+
Pins {
99+
P0 => 0,
100+
P1 => 1,
101+
P2 => 2,
102+
P3 => 3,
103+
P4 => 4,
104+
P5 => 5,
105+
P6 => 6,
106+
P7 => 7,
107+
}
108+
}
109+
}
110+
9111
/// Parallel 8 Bit communication interface
10112
///
11113
/// This interface implements an 8-Bit "8080" style write-only display interface using any
12-
/// `embedded_hal` `digital::v2::OutputPin` implementation.
13-
///
14-
/// For the 8-Bit implementation you need to provide 8 types implementing `OutputPin` which
15-
/// ressemble the bits 0 through 7 (which bit 0 being the LSB and 7 the MSB) as well as one
114+
/// 8-bit [OutputBus] implementation as well as one
16115
/// `OutputPin` for the data/command selection and one `OutputPin` for the write-enable flag.
17116
///
18117
/// All pins are supposed to be high-active, high for the D/C pin meaning "data" and the
19118
/// write-enable being pulled low before the setting of the bits and supposed to be sampled at a
20119
/// low to high edge.
21-
pub struct PGPIO8BitInterface<P0, P1, P2, P3, P4, P5, P6, P7, DC, WR> {
22-
p0: P0,
23-
p1: P1,
24-
p2: P2,
25-
p3: P3,
26-
p4: P4,
27-
p5: P5,
28-
p6: P6,
29-
p7: P7,
120+
pub struct PGPIO8BitInterface<BUS, DC, WR> {
121+
bus: BUS,
30122
dc: DC,
31123
wr: WR,
32-
last: u8,
33124
}
34125

35-
impl<P0, P1, P2, P3, P4, P5, P6, P7, DC, WR>
36-
PGPIO8BitInterface<P0, P1, P2, P3, P4, P5, P6, P7, DC, WR>
126+
impl<BUS, DC, WR> PGPIO8BitInterface<BUS, DC, WR>
37127
where
38-
P0: OutputPin,
39-
P1: OutputPin,
40-
P2: OutputPin,
41-
P3: OutputPin,
42-
P4: OutputPin,
43-
P5: OutputPin,
44-
P6: OutputPin,
45-
P7: OutputPin,
128+
BUS: OutputBus<Word = u8>,
46129
DC: OutputPin,
47130
WR: OutputPin,
48131
{
49132
/// Create new parallel GPIO interface for communication with a display driver
50-
#[allow(clippy::too_many_arguments)]
51-
pub fn new(
52-
p0: P0,
53-
p1: P1,
54-
p2: P2,
55-
p3: P3,
56-
p4: P4,
57-
p5: P5,
58-
p6: P6,
59-
p7: P7,
60-
dc: DC,
61-
wr: WR,
62-
) -> Self {
63-
Self {
64-
p0,
65-
p1,
66-
p2,
67-
p3,
68-
p4,
69-
p5,
70-
p6,
71-
p7,
72-
dc,
73-
wr,
74-
last: 0,
75-
}
133+
pub fn new(bus: BUS, dc: DC, wr: WR) -> Self {
134+
Self { bus, dc, wr }
76135
}
77136

78137
/// Consume the display interface and return
79-
/// the GPIO pins used by it
80-
pub fn release(self) -> (P0, P1, P2, P3, P4, P5, P6, P7, DC, WR) {
81-
(
82-
self.p0, self.p1, self.p2, self.p3, self.p4, self.p5, self.p6, self.p7, self.dc,
83-
self.wr,
84-
)
138+
/// the bus and GPIO pins used by it
139+
pub fn release(self) -> (BUS, DC, WR) {
140+
(self.bus, self.dc, self.wr)
85141
}
86142

87143
fn set_value(self: &mut Self, value: u8) -> Result<(), DisplayError> {
88-
let changed = value ^ self.last;
89-
90-
// It's quite common for multiple consecutive values to be identical, e.g. when filling or
91-
// clearing the screen, so let's optimize for that case
92-
if changed == 0 {
93-
return Ok(());
94-
}
95-
96-
self.last = value;
97-
98-
if changed & 1 != 0 {
99-
if value & 1 != 0 {
100-
self.p0.set_high()
101-
} else {
102-
self.p0.set_low()
103-
}
104-
.map_err(|_| DisplayError::BusWriteError)?
105-
};
106-
107-
if changed & 2 != 0 {
108-
if value & 2 != 0 {
109-
self.p1.set_high()
110-
} else {
111-
self.p1.set_low()
112-
}
113-
.map_err(|_| DisplayError::BusWriteError)?
114-
};
115-
116-
if changed & 4 != 0 {
117-
if value & 4 != 0 {
118-
self.p2.set_high()
119-
} else {
120-
self.p2.set_low()
121-
}
122-
.map_err(|_| DisplayError::BusWriteError)?
123-
};
124-
125-
if changed & 8 != 0 {
126-
if value & 8 != 0 {
127-
self.p3.set_high()
128-
} else {
129-
self.p3.set_low()
130-
}
131-
.map_err(|_| DisplayError::BusWriteError)?
132-
};
133-
134-
if changed & 16 != 0 {
135-
if value & 16 != 0 {
136-
self.p4.set_high()
137-
} else {
138-
self.p4.set_low()
139-
}
140-
.map_err(|_| DisplayError::BusWriteError)?
141-
};
142-
143-
if changed & 32 != 0 {
144-
if value & 32 != 0 {
145-
self.p5.set_high()
146-
} else {
147-
self.p5.set_low()
148-
}
149-
.map_err(|_| DisplayError::BusWriteError)?
150-
};
151-
152-
if changed & 64 != 0 {
153-
if value & 64 != 0 {
154-
self.p6.set_high()
155-
} else {
156-
self.p6.set_low()
157-
}
158-
.map_err(|_| DisplayError::BusWriteError)?
159-
};
160-
161-
if changed & 128 != 0 {
162-
if value & 128 != 0 {
163-
self.p7.set_high()
164-
} else {
165-
self.p7.set_low()
166-
}
167-
.map_err(|_| DisplayError::BusWriteError)?
168-
};
169-
170-
Ok(())
144+
self.bus.set_value(value)
171145
}
172146
}
173147

174-
impl<P0, P1, P2, P3, P4, P5, P6, P7, DC, WR> WriteOnlyDataCommand
175-
for PGPIO8BitInterface<P0, P1, P2, P3, P4, P5, P6, P7, DC, WR>
148+
impl<BUS, DC, WR> WriteOnlyDataCommand for PGPIO8BitInterface<BUS, DC, WR>
176149
where
177-
P0: OutputPin,
178-
P1: OutputPin,
179-
P2: OutputPin,
180-
P3: OutputPin,
181-
P4: OutputPin,
182-
P5: OutputPin,
183-
P6: OutputPin,
184-
P7: OutputPin,
150+
BUS: OutputBus<Word = u8>,
185151
DC: OutputPin,
186152
WR: OutputPin,
187153
{

0 commit comments

Comments
 (0)