display_interface_parallel_gpio/
lib.rs

1//! Generic parallel GPIO interface for display drivers
2#![no_std]
3
4use embedded_hal::digital::OutputPin;
5
6pub use display_interface::{DataFormat, DisplayError, WriteOnlyDataCommand};
7
8type Result<T = ()> = core::result::Result<T, DisplayError>;
9
10/// This trait represents the data pins of a parallel bus.
11///
12/// See [Generic8BitBus] and [Generic16BitBus] for generic implementations.
13pub trait OutputBus {
14    /// [u8] for 8-bit buses, [u16] for 16-bit buses, etc.
15    type Word: Copy;
16
17    fn set_value(&mut self, value: Self::Word) -> Result;
18}
19
20macro_rules! generic_bus {
21    ($GenericxBitBus:ident { type Word = $Word:ident; Pins {$($PX:ident => $x:tt,)*}}) => {
22        /// A generic implementation of [OutputBus] using [OutputPin]s
23        pub struct $GenericxBitBus<$($PX, )*> {
24            pins: ($($PX, )*),
25            last: Option<$Word>,
26        }
27
28        impl<$($PX, )*> $GenericxBitBus<$($PX, )*>
29        where
30            $($PX: OutputPin, )*
31        {
32            /// Creates a new bus. This does not change the state of the pins.
33            ///
34            /// The first pin in the tuple is the least significant bit.
35            pub fn new(pins: ($($PX, )*)) -> Self {
36                Self { pins, last: None }
37            }
38
39            /// Consumes the bus and returns the pins. This does not change the state of the pins.
40            pub fn release(self) -> ($($PX, )*) {
41                self.pins
42            }
43        }
44
45        impl<$($PX, )*> OutputBus
46            for $GenericxBitBus<$($PX, )*>
47        where
48            $($PX: OutputPin, )*
49        {
50            type Word = $Word;
51
52            fn set_value(&mut self, value: Self::Word) -> Result {
53                if self.last == Some(value) {
54                    // It's quite common for multiple consecutive values to be identical, e.g. when filling or
55                    // clearing the screen, so let's optimize for that case
56                    return Ok(())
57                }
58
59                // Sets self.last to None.
60                // We will update it to Some(value) *after* all the pins are succesfully set.
61                let last = self.last.take();
62
63                let changed = match last {
64                    Some(old_value) => value ^ old_value,
65                    None => !0, // all ones, this ensures that we will update all the pins
66                };
67
68                $(
69                    let mask = 1 << $x;
70                    if changed & mask != 0 {
71                        if value & mask != 0 {
72                            self.pins.$x.set_high()
73                        } else {
74                            self.pins.$x.set_low()
75                        }
76                        .map_err(|_| DisplayError::BusWriteError)?;
77                    }
78                )*
79
80                self.last = Some(value);
81                Ok(())
82            }
83        }
84
85        impl<$($PX, )*> From<($($PX, )*)>
86            for $GenericxBitBus<$($PX, )*>
87        where
88            $($PX: OutputPin, )*
89        {
90            fn from(pins: ($($PX, )*)) -> Self {
91                Self::new(pins)
92            }
93        }
94    };
95}
96
97generic_bus! {
98    Generic8BitBus {
99        type Word = u8;
100        Pins {
101            P0 => 0,
102            P1 => 1,
103            P2 => 2,
104            P3 => 3,
105            P4 => 4,
106            P5 => 5,
107            P6 => 6,
108            P7 => 7,
109        }
110    }
111}
112
113generic_bus! {
114    Generic16BitBus {
115        type Word = u16;
116        Pins {
117            P0 => 0,
118            P1 => 1,
119            P2 => 2,
120            P3 => 3,
121            P4 => 4,
122            P5 => 5,
123            P6 => 6,
124            P7 => 7,
125            P8 => 8,
126            P9 => 9,
127            P10 => 10,
128            P11 => 11,
129            P12 => 12,
130            P13 => 13,
131            P14 => 14,
132            P15 => 15,
133        }
134    }
135}
136
137/// Parallel 8 Bit communication interface
138///
139/// This interface implements an 8-Bit "8080" style write-only display interface using any
140/// 8-bit [OutputBus] implementation as well as one
141/// `OutputPin` for the data/command selection and one `OutputPin` for the write-enable flag.
142///
143/// All pins are supposed to be high-active, high for the D/C pin meaning "data" and the
144/// write-enable being pulled low before the setting of the bits and supposed to be sampled at a
145/// low to high edge.
146pub struct PGPIO8BitInterface<BUS, DC, WR> {
147    bus: BUS,
148    dc: DC,
149    wr: WR,
150}
151
152impl<BUS, DC, WR> PGPIO8BitInterface<BUS, DC, WR>
153where
154    BUS: OutputBus<Word = u8>,
155    DC: OutputPin,
156    WR: OutputPin,
157{
158    /// Create new parallel GPIO interface for communication with a display driver
159    pub fn new(bus: BUS, dc: DC, wr: WR) -> Self {
160        Self { bus, dc, wr }
161    }
162
163    /// Consume the display interface and return
164    /// the bus and GPIO pins used by it
165    pub fn release(self) -> (BUS, DC, WR) {
166        (self.bus, self.dc, self.wr)
167    }
168
169    fn write_iter(&mut self, iter: impl Iterator<Item = u8>) -> Result {
170        for value in iter {
171            self.wr.set_low().map_err(|_| DisplayError::BusWriteError)?;
172            self.bus.set_value(value)?;
173            self.wr
174                .set_high()
175                .map_err(|_| DisplayError::BusWriteError)?;
176        }
177
178        Ok(())
179    }
180
181    fn write_pairs(&mut self, iter: impl Iterator<Item = [u8; 2]>) -> Result {
182        use core::iter::once;
183        self.write_iter(iter.flat_map(|[first, second]| once(first).chain(once(second))))
184    }
185
186    fn write_data(&mut self, data: DataFormat<'_>) -> Result {
187        match data {
188            DataFormat::U8(slice) => self.write_iter(slice.iter().copied()),
189            DataFormat::U8Iter(iter) => self.write_iter(iter),
190            DataFormat::U16(slice) => self.write_pairs(slice.iter().copied().map(u16::to_ne_bytes)),
191            DataFormat::U16BE(slice) => {
192                self.write_pairs(slice.iter().copied().map(u16::to_be_bytes))
193            }
194            DataFormat::U16LE(slice) => {
195                self.write_pairs(slice.iter().copied().map(u16::to_le_bytes))
196            }
197            DataFormat::U16BEIter(iter) => self.write_pairs(iter.map(u16::to_be_bytes)),
198            DataFormat::U16LEIter(iter) => self.write_pairs(iter.map(u16::to_le_bytes)),
199            _ => Err(DisplayError::DataFormatNotImplemented),
200        }
201    }
202}
203
204impl<BUS, DC, WR> WriteOnlyDataCommand for PGPIO8BitInterface<BUS, DC, WR>
205where
206    BUS: OutputBus<Word = u8>,
207    DC: OutputPin,
208    WR: OutputPin,
209{
210    fn send_commands(&mut self, cmds: DataFormat<'_>) -> Result {
211        self.dc.set_low().map_err(|_| DisplayError::DCError)?;
212        self.write_data(cmds)
213    }
214
215    fn send_data(&mut self, buf: DataFormat<'_>) -> Result {
216        self.dc.set_high().map_err(|_| DisplayError::DCError)?;
217        self.write_data(buf)
218    }
219}
220
221/// Parallel 16 Bit communication interface
222///
223/// This interface implements a 16-Bit "8080" style write-only display interface using any
224/// 16-bit [OutputBus] implementation as well as one
225/// `OutputPin` for the data/command selection and one `OutputPin` for the write-enable flag.
226///
227/// All pins are supposed to be high-active, high for the D/C pin meaning "data" and the
228/// write-enable being pulled low before the setting of the bits and supposed to be sampled at a
229/// low to high edge.
230pub struct PGPIO16BitInterface<BUS, DC, WR> {
231    bus: BUS,
232    dc: DC,
233    wr: WR,
234}
235
236impl<BUS, DC, WR> PGPIO16BitInterface<BUS, DC, WR>
237where
238    BUS: OutputBus<Word = u16>,
239    DC: OutputPin,
240    WR: OutputPin,
241{
242    /// Create new parallel GPIO interface for communication with a display driver
243    pub fn new(bus: BUS, dc: DC, wr: WR) -> Self {
244        Self { bus, dc, wr }
245    }
246
247    /// Consume the display interface and return
248    /// the bus and GPIO pins used by it
249    pub fn release(self) -> (BUS, DC, WR) {
250        (self.bus, self.dc, self.wr)
251    }
252
253    fn write_iter(&mut self, iter: impl Iterator<Item = u16>) -> Result {
254        for value in iter {
255            self.wr.set_low().map_err(|_| DisplayError::BusWriteError)?;
256            self.bus.set_value(value)?;
257            self.wr
258                .set_high()
259                .map_err(|_| DisplayError::BusWriteError)?;
260        }
261
262        Ok(())
263    }
264
265    fn write_data(&mut self, data: DataFormat<'_>) -> Result {
266        match data {
267            DataFormat::U8(slice) => self.write_iter(slice.iter().copied().map(u16::from)),
268            DataFormat::U8Iter(iter) => self.write_iter(iter.map(u16::from)),
269            DataFormat::U16(slice) => self.write_iter(slice.iter().copied()),
270            DataFormat::U16BE(slice) => self.write_iter(slice.iter().copied()),
271            DataFormat::U16LE(slice) => self.write_iter(slice.iter().copied()),
272            DataFormat::U16BEIter(iter) => self.write_iter(iter),
273            DataFormat::U16LEIter(iter) => self.write_iter(iter),
274            _ => Err(DisplayError::DataFormatNotImplemented),
275        }
276    }
277}
278
279impl<BUS, DC, WR> WriteOnlyDataCommand for PGPIO16BitInterface<BUS, DC, WR>
280where
281    BUS: OutputBus<Word = u16>,
282    DC: OutputPin,
283    WR: OutputPin,
284{
285    fn send_commands(&mut self, cmds: DataFormat<'_>) -> Result {
286        self.dc.set_low().map_err(|_| DisplayError::DCError)?;
287        self.write_data(cmds)
288    }
289
290    fn send_data(&mut self, buf: DataFormat<'_>) -> Result {
291        self.dc.set_high().map_err(|_| DisplayError::DCError)?;
292        self.write_data(buf)
293    }
294}