Skip to main content

epd_datafuri/interface/
mod.rs

1//! Display interface using SPI
2use display_interface::DisplayError;
3use embedded_hal::{
4    delay::DelayNs,
5    digital::{InputPin, OutputPin},
6    spi::SpiDevice,
7};
8
9const RESET_DELAY_MS: u8 = 10;
10
11/// SPI connection interface for EPD displays.
12///
13/// Busy pin polarity varies by controller: SSD1680 is active-high (HIGH = busy),
14/// IL0373 is active-low (LOW = busy). Use `wait_until_idle` or
15/// `wait_until_idle_active_low` accordingly.
16pub struct SpiDisplayInterface<SPI, BSY, DC, RST> {
17    /// SPI device
18    spi: SPI,
19    /// Busy status pin (polarity is controller-dependent)
20    busy: BSY,
21    /// Data/Command Control Pin (High for data, Low for command)
22    dc: DC,
23    /// Reset pin
24    rst: RST,
25}
26
27impl<SPI, BSY, DC, RST> SpiDisplayInterface<SPI, BSY, DC, RST> {
28    /// Create and initialize display
29    pub fn new(spi: SPI, busy: BSY, dc: DC, rst: RST) -> Self {
30        SpiDisplayInterface { spi, busy, dc, rst }
31    }
32}
33
34impl<SPI, BSY, DC, RST> SpiDisplayInterface<SPI, BSY, DC, RST>
35where
36    SPI: SpiDevice,
37    RST: OutputPin,
38    DC: OutputPin,
39    BSY: InputPin,
40{
41    /// Basic function for sending commands
42    pub(crate) fn cmd(&mut self, command: u8) -> Result<(), DisplayError> {
43        log::trace!("cmd 0x{:02X}", command);
44
45        // low for commands
46        self.dc.set_low().map_err(|_| DisplayError::DCError)?;
47
48        // Transfer the command over spi
49        self.spi
50            .write(&[command])
51            .map_err(|_| DisplayError::BusWriteError)
52    }
53
54    /// Basic function for sending an array of u8-values of data over spi
55    pub(crate) fn data(&mut self, data: &[u8]) -> Result<(), DisplayError> {
56        // high for data
57        self.dc.set_high().map_err(|_| DisplayError::DCError)?;
58
59        // Transfer data (u8-array) over spi
60        self.spi
61            .write(data)
62            .map_err(|_| DisplayError::BusWriteError)
63    }
64
65    /// Basic function for sending a command and the data belonging to it.
66    pub(crate) fn cmd_with_data(&mut self, command: u8, data: &[u8]) -> Result<(), DisplayError> {
67        log::trace!("cmd 0x{:02X}, data {:02X?}", command, data);
68        self.cmd(command)?;
69        self.data(data)
70    }
71
72    /// Basic function for sending the same byte of data (one u8) multiple times over spi
73    /// Useful for setting one color for the whole frame
74    pub(crate) fn data_x_times(&mut self, val: u8, repetitions: u32) -> Result<(), DisplayError> {
75        log::trace!("writing data 0x{:02X} x {}", val, repetitions);
76        // high for data
77        let _ = self.dc.set_high();
78        // Transfer data (u8) over spi
79        for _ in 0..repetitions {
80            self.spi
81                .write(&[val])
82                .map_err(|_| DisplayError::BusWriteError)?;
83        }
84        Ok(())
85    }
86
87    /// Waits until device isn't busy anymore (busy == HIGH).
88    ///
89    /// Used by SSD1680-based displays where the busy pin is active-high (HIGH = busy).
90    pub(crate) fn wait_until_idle(&mut self, delay: &mut impl DelayNs) {
91        log::trace!("Waiting until display is idle");
92        while self.busy.is_high().unwrap_or(true) {
93            delay.delay_ms(1)
94        }
95    }
96
97    /// Waits until device isn't busy anymore (busy == LOW).
98    ///
99    /// Used by IL0373-based displays where the busy pin is active-low (LOW = busy, HIGH = ready).
100    pub(crate) fn wait_until_idle_active_low(&mut self, delay: &mut impl DelayNs) {
101        log::trace!("Waiting until display is idle (active-low busy)");
102        while self.busy.is_low().unwrap_or(true) {
103            delay.delay_ms(1)
104        }
105    }
106
107    /// Resets the device.
108    pub(crate) fn hard_reset(&mut self, delay: &mut impl DelayNs) -> Result<(), DisplayError> {
109        log::trace!("Resetting display");
110        self.rst.set_low().map_err(|_| DisplayError::RSError)?;
111        delay.delay_ms(RESET_DELAY_MS.into());
112        self.rst.set_high().map_err(|_| DisplayError::RSError)?;
113        delay.delay_ms(RESET_DELAY_MS.into());
114        Ok(())
115    }
116}