slint/internal/backends/mcu/pico_st7789/display_interface_spi.rs
Olivier Goffart 5494e4ec28 mcu pico: fix the screen artifacts by re-implementing display-interface-spi
The display-interface-spi crate the not flush the internal fifo between the write
and the changes of the CS and DC pins, which result of changing these pins before
the screen recieve all the data over the spi and causes artifacts on the screen.

So re-implement the logic in our crate and use `transfer` instead of `write`
which flushes the fifo correctly.
2022-06-16 21:36:15 +02:00

115 lines
3.1 KiB
Rust

// Copyright © SixtyFPS GmbH <info@slint-ui.com>
// 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: hal::blocking::spi::Transfer<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, DC, CS> {
spi: SPI,
dc: DC,
cs: CS,
}
impl<SPI, DC, CS> SPIInterface<SPI, DC, CS>
where
SPI: hal::blocking::spi::Transfer<u8>,
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<SPI, DC, CS> WriteOnlyDataCommand for SPIInterface<SPI, DC, CS>
where
SPI: hal::blocking::spi::Transfer<u8>,
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
}
}