// Copyright © SixtyFPS GmbH // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial //! The `display-interface-spi` crate cannot be used because it doesn't "flush" the spi between //! the write and the changes in the CS and DC pin. This results in artifacts being shown on the //! screen //! //! Work-around the problem by using `transfer` instead of write. use embedded_hal as hal; use hal::digital::v2::OutputPin; use display_interface::{DataFormat, DisplayError, WriteOnlyDataCommand}; fn send_u8>( spi: &mut SPI, words: DataFormat<'_>, ) -> Result<(), DisplayError> { match words { DataFormat::U8Iter(iter) => { let mut buf = [0; 32]; let mut i = 0; for v in iter.into_iter() { buf[i] = v; i += 1; if i == buf.len() { spi.transfer(&mut buf).map_err(|_| DisplayError::BusWriteError)?; i = 0; } } if i > 0 { spi.transfer(&mut buf[..i]).map_err(|_| DisplayError::BusWriteError)?; } Ok(()) } DataFormat::U16BEIter(iter) => { for mut v in iter.map(u16::to_be_bytes) { spi.transfer(&mut v).map_err(|_| DisplayError::BusWriteError)?; } Ok(()) } _ => Err(DisplayError::DataFormatNotImplemented), } } /// SPI display interface. /// /// This combines the SPI peripheral and a data/command as well as a chip-select pin pub struct SPIInterface { spi: SPI, dc: DC, cs: CS, } impl SPIInterface where SPI: hal::blocking::spi::Transfer, DC: OutputPin, CS: OutputPin, { /// Create new SPI interface for communication with a display driver pub fn new(spi: SPI, dc: DC, cs: CS) -> Self { Self { spi, dc, cs } } } impl WriteOnlyDataCommand for SPIInterface where SPI: hal::blocking::spi::Transfer, DC: OutputPin, CS: OutputPin, { fn send_commands(&mut self, cmds: DataFormat<'_>) -> Result<(), DisplayError> { // Assert chip select pin self.cs.set_low().map_err(|_| DisplayError::CSError)?; // 1 = data, 0 = command self.dc.set_low().map_err(|_| DisplayError::DCError)?; // Send words over SPI let err = send_u8(&mut self.spi, cmds); // --- // for _ in 0..70 { // self.cs.set_low().map_err(|_| DisplayError::CSError)?; // } // --- // Deassert chip select pin self.cs.set_high().ok(); err } fn send_data(&mut self, buf: DataFormat<'_>) -> Result<(), DisplayError> { // Assert chip select pin self.cs.set_low().map_err(|_| DisplayError::CSError)?; // 1 = data, 0 = command self.dc.set_high().map_err(|_| DisplayError::DCError)?; // Send words over SPI let err = send_u8(&mut self.spi, buf); // Deassert chip select pin self.cs.set_high().ok(); err } }