epd_waveshare/epd5in83b_v2/
mod.rs

1//! A simple Driver for the Waveshare 5.83" (B) v2 E-Ink Display via SPI
2//!
3//! # References
4//!
5//! - [Datasheet](https://www.waveshare.com/5.83inch-e-Paper-B.htm)
6//! - [Waveshare C driver](https://github.com/waveshare/e-Paper/blob/master/RaspberryPi_JetsonNano/c/lib/e-Paper/EPD_5in83b_V2.c)
7//! - [Waveshare Python driver](https://github.com/waveshare/e-Paper/blob/master/RaspberryPi_JetsonNano/python/lib/waveshare_epd/epd5in83b_V2.py)
8
9use embedded_hal::{
10    delay::DelayNs,
11    digital::{InputPin, OutputPin},
12    spi::SpiDevice,
13};
14
15use crate::color::Color;
16use crate::interface::DisplayInterface;
17use crate::prelude::{TriColor, WaveshareDisplay, WaveshareThreeColorDisplay};
18use crate::traits::{InternalWiAdditions, RefreshLut};
19
20pub(crate) mod command;
21use self::command::Command;
22use crate::buffer_len;
23
24/// Full size buffer for use with the 5in83b v2 EPD
25#[cfg(feature = "graphics")]
26pub type Display5in83 = crate::graphics::Display<
27    WIDTH,
28    HEIGHT,
29    false,
30    { buffer_len(WIDTH as usize, HEIGHT as usize * 2) },
31    TriColor,
32>;
33
34/// Width of the display
35pub const WIDTH: u32 = 648;
36/// Height of the display
37pub const HEIGHT: u32 = 480;
38/// Default Background Color
39pub const DEFAULT_BACKGROUND_COLOR: Color = Color::White;
40const IS_BUSY_LOW: bool = true;
41const NUM_DISPLAY_BITS: u32 = WIDTH / 8 * HEIGHT;
42const SINGLE_BYTE_WRITE: bool = true;
43
44/// Epd7in5 driver
45///
46pub struct Epd5in83<SPI, BUSY, DC, RST, DELAY> {
47    /// Connection Interface
48    interface: DisplayInterface<SPI, BUSY, DC, RST, DELAY, SINGLE_BYTE_WRITE>,
49    /// Background Color
50    color: Color,
51}
52
53impl<SPI, BUSY, DC, RST, DELAY> InternalWiAdditions<SPI, BUSY, DC, RST, DELAY>
54    for Epd5in83<SPI, BUSY, DC, RST, DELAY>
55where
56    SPI: SpiDevice,
57    BUSY: InputPin,
58    DC: OutputPin,
59    RST: OutputPin,
60    DELAY: DelayNs,
61{
62    fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
63        // Reset the device
64        self.interface.reset(delay, 10_000, 10_000);
65
66        // Start the booster
67        self.cmd_with_data(spi, Command::BoosterSoftStart, &[0x17, 0x17, 0x1e, 0x17])?;
68
69        // Set the power settings: VGH=20V,VGL=-20V,VDH=15V,VDL=-15V
70        self.cmd_with_data(spi, Command::PowerSetting, &[0x07, 0x07, 0x3F, 0x3F])?;
71
72        // Power on
73        self.command(spi, Command::PowerOn)?;
74        delay.delay_us(5000);
75        self.wait_until_idle(spi, delay)?;
76
77        // Set the panel settings: BWROTP
78        self.cmd_with_data(spi, Command::PanelSetting, &[0x0F])?;
79
80        // Set the real resolution
81        self.send_resolution(spi)?;
82
83        // Disable dual SPI
84        self.cmd_with_data(spi, Command::DualSPI, &[0x00])?;
85
86        // Set Vcom and data interval
87        self.cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x11, 0x07])?;
88
89        // Set S2G and G2S non-overlap periods to 12 (default)
90        self.cmd_with_data(spi, Command::TconSetting, &[0x22])?;
91
92        self.wait_until_idle(spi, delay)?;
93        Ok(())
94    }
95}
96
97impl<SPI, BUSY, DC, RST, DELAY> WaveshareThreeColorDisplay<SPI, BUSY, DC, RST, DELAY>
98    for Epd5in83<SPI, BUSY, DC, RST, DELAY>
99where
100    SPI: SpiDevice,
101    BUSY: InputPin,
102    DC: OutputPin,
103    RST: OutputPin,
104    DELAY: DelayNs,
105{
106    fn update_color_frame(
107        &mut self,
108        spi: &mut SPI,
109        delay: &mut DELAY,
110        black: &[u8],
111        chromatic: &[u8],
112    ) -> Result<(), SPI::Error> {
113        self.update_achromatic_frame(spi, delay, black)?;
114        self.update_chromatic_frame(spi, delay, chromatic)?;
115        Ok(())
116    }
117
118    fn update_achromatic_frame(
119        &mut self,
120        spi: &mut SPI,
121        delay: &mut DELAY,
122        black: &[u8],
123    ) -> Result<(), SPI::Error> {
124        self.wait_until_idle(spi, delay)?;
125        self.cmd_with_data(spi, Command::DataStartTransmission1, black)?;
126        Ok(())
127    }
128
129    fn update_chromatic_frame(
130        &mut self,
131        spi: &mut SPI,
132        delay: &mut DELAY,
133        chromatic: &[u8],
134    ) -> Result<(), SPI::Error> {
135        self.wait_until_idle(spi, delay)?;
136        self.cmd_with_data(spi, Command::DataStartTransmission2, chromatic)?;
137        Ok(())
138    }
139}
140
141impl<SPI, BUSY, DC, RST, DELAY> WaveshareDisplay<SPI, BUSY, DC, RST, DELAY>
142    for Epd5in83<SPI, BUSY, DC, RST, DELAY>
143where
144    SPI: SpiDevice,
145    BUSY: InputPin,
146    DC: OutputPin,
147    RST: OutputPin,
148    DELAY: DelayNs,
149{
150    type DisplayColor = Color;
151    fn new(
152        spi: &mut SPI,
153        busy: BUSY,
154        dc: DC,
155        rst: RST,
156        delay: &mut DELAY,
157        delay_us: Option<u32>,
158    ) -> Result<Self, SPI::Error> {
159        let interface = DisplayInterface::new(busy, dc, rst, delay_us);
160        let color = DEFAULT_BACKGROUND_COLOR;
161
162        let mut epd = Epd5in83 { interface, color };
163
164        epd.init(spi, delay)?;
165
166        Ok(epd)
167    }
168
169    fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
170        self.wait_until_idle(spi, delay)?;
171        self.command(spi, Command::PowerOff)?;
172        self.wait_until_idle(spi, delay)?;
173        self.cmd_with_data(spi, Command::DeepSleep, &[0xA5])?;
174        Ok(())
175    }
176
177    fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
178        self.init(spi, delay)
179    }
180
181    fn set_background_color(&mut self, color: Color) {
182        self.color = color;
183    }
184
185    fn background_color(&self) -> &Color {
186        &self.color
187    }
188
189    fn width(&self) -> u32 {
190        WIDTH
191    }
192
193    fn height(&self) -> u32 {
194        HEIGHT
195    }
196
197    fn update_frame(
198        &mut self,
199        spi: &mut SPI,
200        buffer: &[u8],
201        delay: &mut DELAY,
202    ) -> Result<(), SPI::Error> {
203        self.wait_until_idle(spi, delay)?;
204        self.update_achromatic_frame(spi, delay, buffer)?;
205        let color = self.color.get_byte_value();
206        self.command(spi, Command::DataStartTransmission2)?;
207        self.interface.data_x_times(spi, color, NUM_DISPLAY_BITS)?;
208        Ok(())
209    }
210
211    fn update_partial_frame(
212        &mut self,
213        spi: &mut SPI,
214        delay: &mut DELAY,
215        buffer: &[u8],
216        x: u32,
217        y: u32,
218        width: u32,
219        height: u32,
220    ) -> Result<(), SPI::Error> {
221        self.wait_until_idle(spi, delay)?;
222        if buffer.len() as u32 != width / 8 * height {
223            //TODO panic or error
224        }
225
226        let hrst_upper = (x / 8) as u8 >> 6;
227        let hrst_lower = ((x / 8) << 3) as u8;
228        let hred_upper = ((x + width) / 8) as u8 >> 6;
229        let hred_lower = (((x + width) / 8) << 3) as u8 & 0b111;
230        let vrst_upper = (y >> 8) as u8;
231        let vrst_lower = y as u8;
232        let vred_upper = ((y + height) >> 8) as u8;
233        let vred_lower = (y + height) as u8;
234        let pt_scan = 0x01; // Gates scan both inside and outside of the partial window. (default)
235
236        self.command(spi, Command::PartialIn)?;
237        self.command(spi, Command::PartialWindow)?;
238        self.send_data(
239            spi,
240            &[
241                hrst_upper, hrst_lower, hred_upper, hred_lower, vrst_upper, vrst_lower, vred_upper,
242                vred_lower, pt_scan,
243            ],
244        )?;
245        self.command(spi, Command::DataStartTransmission1)?;
246        self.send_data(spi, buffer)?;
247
248        let color = TriColor::Black.get_byte_value(); //We need it black, so red channel will be rendered transparent
249        self.command(spi, Command::DataStartTransmission2)?;
250        self.interface
251            .data_x_times(spi, color, width * height / 8)?;
252
253        self.command(spi, Command::DisplayRefresh)?;
254        self.wait_until_idle(spi, delay)?;
255
256        self.command(spi, Command::PartialOut)?;
257        Ok(())
258    }
259
260    fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
261        self.command(spi, Command::DisplayRefresh)?;
262        self.wait_until_idle(spi, delay)?;
263        Ok(())
264    }
265
266    fn update_and_display_frame(
267        &mut self,
268        spi: &mut SPI,
269        buffer: &[u8],
270        delay: &mut DELAY,
271    ) -> Result<(), SPI::Error> {
272        self.update_frame(spi, buffer, delay)?;
273        self.display_frame(spi, delay)?;
274        Ok(())
275    }
276
277    fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
278        self.wait_until_idle(spi, delay)?;
279
280        // The Waveshare controllers all implement clear using 0x33
281        self.command(spi, Command::DataStartTransmission1)?;
282        self.interface.data_x_times(spi, 0xFF, NUM_DISPLAY_BITS)?;
283
284        self.command(spi, Command::DataStartTransmission2)?;
285        self.interface.data_x_times(spi, 0x00, NUM_DISPLAY_BITS)?;
286
287        Ok(())
288    }
289
290    fn set_lut(
291        &mut self,
292        _spi: &mut SPI,
293        _delay: &mut DELAY,
294        _refresh_rate: Option<RefreshLut>,
295    ) -> Result<(), SPI::Error> {
296        unimplemented!();
297    }
298
299    fn wait_until_idle(&mut self, _spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
300        self.interface.wait_until_idle(delay, IS_BUSY_LOW);
301        Ok(())
302    }
303}
304
305impl<SPI, BUSY, DC, RST, DELAY> Epd5in83<SPI, BUSY, DC, RST, DELAY>
306where
307    SPI: SpiDevice,
308    BUSY: InputPin,
309    DC: OutputPin,
310    RST: OutputPin,
311    DELAY: DelayNs,
312{
313    fn command(&mut self, spi: &mut SPI, command: Command) -> Result<(), SPI::Error> {
314        self.interface.cmd(spi, command)
315    }
316
317    fn send_data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> {
318        self.interface.data(spi, data)
319    }
320
321    fn cmd_with_data(
322        &mut self,
323        spi: &mut SPI,
324        command: Command,
325        data: &[u8],
326    ) -> Result<(), SPI::Error> {
327        self.interface.cmd_with_data(spi, command, data)
328    }
329
330    fn send_resolution(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
331        let w = self.width();
332        let h = self.height();
333
334        self.command(spi, Command::TconResolution)?;
335        self.send_data(spi, &[(w >> 8) as u8])?;
336        self.send_data(spi, &[w as u8])?;
337        self.send_data(spi, &[(h >> 8) as u8])?;
338        self.send_data(spi, &[h as u8])
339    }
340}
341
342#[cfg(test)]
343mod tests {
344    use super::*;
345
346    #[test]
347    fn epd_size() {
348        assert_eq!(WIDTH, 648);
349        assert_eq!(HEIGHT, 480);
350        assert_eq!(DEFAULT_BACKGROUND_COLOR, Color::White);
351    }
352}