mirror of
https://github.com/slint-ui/slint.git
synced 2025-09-29 21:34:50 +00:00

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.
115 lines
3.1 KiB
Rust
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
|
|
}
|
|
}
|