epd_waveshare/epd1in54c/
mod.rs

1//! A simple Driver for the Waveshare 1.54" (C) E-Ink Display via SPI
2
3use embedded_hal::{delay::*, digital::*, spi::SpiDevice};
4
5use crate::interface::DisplayInterface;
6use crate::traits::{
7    InternalWiAdditions, RefreshLut, WaveshareDisplay, WaveshareThreeColorDisplay,
8};
9
10/// Width of epd1in54 in pixels
11pub const WIDTH: u32 = 152;
12/// Height of epd1in54 in pixels
13pub const HEIGHT: u32 = 152;
14/// Default Background Color (white)
15pub const DEFAULT_BACKGROUND_COLOR: Color = Color::White;
16const IS_BUSY_LOW: bool = true;
17const NUM_DISPLAY_BITS: u32 = WIDTH / 8 * HEIGHT;
18const SINGLE_BYTE_WRITE: bool = true;
19
20use crate::color::Color;
21
22pub(crate) mod command;
23use self::command::Command;
24use crate::buffer_len;
25
26/// Full size buffer for use with the 1in54c EPD
27/// TODO this should be a TriColor, but let's keep it as is at first
28#[cfg(feature = "graphics")]
29pub type Display1in54c = crate::graphics::Display<
30    WIDTH,
31    HEIGHT,
32    false,
33    { buffer_len(WIDTH as usize, HEIGHT as usize) },
34    Color,
35>;
36
37/// Epd1in54c driver
38pub struct Epd1in54c<SPI, BUSY, DC, RST, DELAY> {
39    interface: DisplayInterface<SPI, BUSY, DC, RST, DELAY, SINGLE_BYTE_WRITE>,
40    color: Color,
41}
42
43impl<SPI, BUSY, DC, RST, DELAY> InternalWiAdditions<SPI, BUSY, DC, RST, DELAY>
44    for Epd1in54c<SPI, BUSY, DC, RST, DELAY>
45where
46    SPI: SpiDevice,
47    BUSY: InputPin,
48    DC: OutputPin,
49    RST: OutputPin,
50    DELAY: DelayNs,
51{
52    fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
53        // Based on Reference Program Code from:
54        // https://www.waveshare.com/w/upload/a/ac/1.54inch_e-Paper_Module_C_Specification.pdf
55        // and:
56        // https://github.com/waveshare/e-Paper/blob/master/STM32/STM32-F103ZET6/User/e-Paper/EPD_1in54c.c
57        self.interface.reset(delay, 10_000, 2_000);
58
59        // start the booster
60        self.cmd_with_data(spi, Command::BoosterSoftStart, &[0x17, 0x17, 0x17])?;
61
62        // power on
63        self.command(spi, Command::PowerOn)?;
64        delay.delay_us(5000);
65        self.wait_until_idle(spi, delay)?;
66
67        // set the panel settings
68        self.cmd_with_data(spi, Command::PanelSetting, &[0x0f, 0x0d])?;
69
70        // set resolution
71        self.send_resolution(spi)?;
72
73        self.cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x77])?;
74
75        Ok(())
76    }
77}
78
79impl<SPI, BUSY, DC, RST, DELAY> WaveshareThreeColorDisplay<SPI, BUSY, DC, RST, DELAY>
80    for Epd1in54c<SPI, BUSY, DC, RST, DELAY>
81where
82    SPI: SpiDevice,
83    BUSY: InputPin,
84    DC: OutputPin,
85    RST: OutputPin,
86    DELAY: DelayNs,
87{
88    fn update_color_frame(
89        &mut self,
90        spi: &mut SPI,
91        delay: &mut DELAY,
92        black: &[u8],
93        chromatic: &[u8],
94    ) -> Result<(), SPI::Error> {
95        self.update_achromatic_frame(spi, delay, black)?;
96        self.update_chromatic_frame(spi, delay, chromatic)
97    }
98
99    fn update_achromatic_frame(
100        &mut self,
101        spi: &mut SPI,
102        delay: &mut DELAY,
103        black: &[u8],
104    ) -> Result<(), SPI::Error> {
105        self.wait_until_idle(spi, delay)?;
106        self.cmd_with_data(spi, Command::DataStartTransmission1, black)?;
107
108        Ok(())
109    }
110
111    fn update_chromatic_frame(
112        &mut self,
113        spi: &mut SPI,
114        delay: &mut DELAY,
115        chromatic: &[u8],
116    ) -> Result<(), SPI::Error> {
117        self.wait_until_idle(spi, delay)?;
118        self.cmd_with_data(spi, Command::DataStartTransmission2, chromatic)?;
119
120        Ok(())
121    }
122}
123
124impl<SPI, BUSY, DC, RST, DELAY> WaveshareDisplay<SPI, BUSY, DC, RST, DELAY>
125    for Epd1in54c<SPI, BUSY, DC, RST, DELAY>
126where
127    SPI: SpiDevice,
128    BUSY: InputPin,
129    DC: OutputPin,
130    RST: OutputPin,
131    DELAY: DelayNs,
132{
133    type DisplayColor = Color;
134    fn new(
135        spi: &mut SPI,
136        busy: BUSY,
137        dc: DC,
138        rst: RST,
139        delay: &mut DELAY,
140        delay_us: Option<u32>,
141    ) -> Result<Self, SPI::Error> {
142        let interface = DisplayInterface::new(busy, dc, rst, delay_us);
143        let color = DEFAULT_BACKGROUND_COLOR;
144
145        let mut epd = Epd1in54c { interface, color };
146
147        epd.init(spi, delay)?;
148
149        Ok(epd)
150    }
151
152    fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
153        self.wait_until_idle(spi, delay)?;
154
155        self.command(spi, Command::PowerOff)?;
156        self.wait_until_idle(spi, delay)?;
157        self.cmd_with_data(spi, Command::DeepSleep, &[0xa5])?;
158
159        Ok(())
160    }
161
162    fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
163        self.init(spi, delay)
164    }
165
166    fn set_background_color(&mut self, color: Color) {
167        self.color = color;
168    }
169
170    fn background_color(&self) -> &Color {
171        &self.color
172    }
173
174    fn width(&self) -> u32 {
175        WIDTH
176    }
177
178    fn height(&self) -> u32 {
179        HEIGHT
180    }
181
182    fn update_frame(
183        &mut self,
184        spi: &mut SPI,
185        buffer: &[u8],
186        delay: &mut DELAY,
187    ) -> Result<(), SPI::Error> {
188        self.update_achromatic_frame(spi, delay, buffer)?;
189
190        // Clear the chromatic layer
191        let color = self.color.get_byte_value();
192
193        self.command(spi, Command::DataStartTransmission2)?;
194        self.interface.data_x_times(spi, color, NUM_DISPLAY_BITS)?;
195
196        Ok(())
197    }
198
199    #[allow(unused)]
200    fn update_partial_frame(
201        &mut self,
202        spi: &mut SPI,
203        delay: &mut DELAY,
204        buffer: &[u8],
205        x: u32,
206        y: u32,
207        width: u32,
208        height: u32,
209    ) -> Result<(), SPI::Error> {
210        unimplemented!()
211    }
212
213    fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
214        self.command(spi, Command::DisplayRefresh)?;
215        self.wait_until_idle(spi, delay)?;
216
217        Ok(())
218    }
219
220    fn update_and_display_frame(
221        &mut self,
222        spi: &mut SPI,
223        buffer: &[u8],
224        delay: &mut DELAY,
225    ) -> Result<(), SPI::Error> {
226        self.update_frame(spi, buffer, delay)?;
227        self.display_frame(spi, delay)?;
228
229        Ok(())
230    }
231
232    fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
233        self.wait_until_idle(spi, delay)?;
234        let color = DEFAULT_BACKGROUND_COLOR.get_byte_value();
235
236        // Clear the black
237        self.command(spi, Command::DataStartTransmission1)?;
238        self.interface.data_x_times(spi, color, NUM_DISPLAY_BITS)?;
239
240        // Clear the chromatic
241        self.command(spi, Command::DataStartTransmission2)?;
242        self.interface.data_x_times(spi, color, NUM_DISPLAY_BITS)?;
243
244        Ok(())
245    }
246
247    fn set_lut(
248        &mut self,
249        _spi: &mut SPI,
250        _delay: &mut DELAY,
251        _refresh_rate: Option<RefreshLut>,
252    ) -> Result<(), SPI::Error> {
253        Ok(())
254    }
255
256    fn wait_until_idle(&mut self, _spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
257        self.interface.wait_until_idle(delay, IS_BUSY_LOW);
258        Ok(())
259    }
260}
261
262impl<SPI, BUSY, DC, RST, DELAY> Epd1in54c<SPI, BUSY, DC, RST, DELAY>
263where
264    SPI: SpiDevice,
265    BUSY: InputPin,
266    DC: OutputPin,
267    RST: OutputPin,
268    DELAY: DelayNs,
269{
270    fn command(&mut self, spi: &mut SPI, command: Command) -> Result<(), SPI::Error> {
271        self.interface.cmd(spi, command)
272    }
273
274    fn send_data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> {
275        self.interface.data(spi, data)
276    }
277
278    fn cmd_with_data(
279        &mut self,
280        spi: &mut SPI,
281        command: Command,
282        data: &[u8],
283    ) -> Result<(), SPI::Error> {
284        self.interface.cmd_with_data(spi, command, data)
285    }
286
287    fn send_resolution(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
288        let w = self.width();
289        let h = self.height();
290
291        self.command(spi, Command::ResolutionSetting)?;
292
293        // | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
294        // |       HRES[7:3]        |  0 |  0 |  0 |
295        self.send_data(spi, &[(w as u8) & 0b1111_1000])?;
296        // | D7 | D6 | D5 | D4 | D3 | D2 | D1 |      D0 |
297        // |  - |  - |  - |  - |  - |  - |  - | VRES[8] |
298        self.send_data(spi, &[(w >> 8) as u8])?;
299        // | D7 | D6 | D5 | D4 | D3 | D2 | D1 |      D0 |
300        // |                  VRES[7:0]                 |
301        // Specification shows C/D is zero while sending the last byte,
302        // but upstream code does not implement it like that. So for now
303        // we follow upstream code.
304        self.send_data(spi, &[h as u8])
305    }
306}