Skip to content

Commit

Permalink
Merge pull request #149 from GrantM11235/new-interface
Browse files Browse the repository at this point in the history
New interface traits
  • Loading branch information
almindor authored Dec 18, 2024
2 parents 07e088c + e7774c0 commit 2681465
Show file tree
Hide file tree
Showing 31 changed files with 943 additions and 620 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ It consists of

*NOTES*:

* The name of these crates is a bit unfortunate as the drivers work with displays that use the MIPI Display Command Set via any transport supported by [display_interface](https://crates.io/crates/display-interface) but MIPI Display Serial Interface is NOT supported at this time.
* The name of these crates is a bit unfortunate as the drivers work with displays that use the MIPI Display Command Set but MIPI Display Serial Interface is NOT supported at this time.

## License

Expand Down
85 changes: 85 additions & 0 deletions docs/MIGRATION.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,90 @@
# Migration guide for `mipidsi` crate

## v0.8 -> 0.9

### Users

* The `display_interface` dependency has been removed in favor of our own trait and implementations. This gives significantly better performance (#149)

* Replace `display_interface_spi::SPIInterface` with `mipidsi::interface::SpiInterface`. Note that it requires a small/medium sized `&mut [u8]` buffer. 512 bytes works well, your milage may vary.
```rust
// before
use display_interface_spi::SPIInterface;

let di = SPIInterface::new(spi_device, dc);

// after
use mipidsi::interface::SpiInterface;

let mut buffer = [0_u8; 512];
let di = SpiInterface::new(spi_device, dc, &mut buffer);
```

* Replace `display_interface_parallel_gpio::PGPIO{8,16}BitInterface` with `mipidsi::interface::ParallelInterface` and use `Generic{8,16}BitBus` from `mipidsi::interface`
```rust
// before
use display_interface_parallel_gpio::Generic8BitBus;
use display_interface_parallel_gpio::PGPIO8BitInterface;

let bus = Generic8BitBus::new(pins);
let di = PGPIO8BitInterface::new(bus, dc, wr);

// after
use mipidsi::interface::Generic8BitBus;
use mipidsi::interface::ParallelInterface;

let bus = Generic8BitBus::new(pins);
let di = ParallelInterface::new(bus, dc, wr);
```

* If you have a custom impl of the `display_interface_parallel_gpio::OutputBus` trait, replace it with `mipidsi::interface::OutputBus`. This trait is identical except that it uses an associated error type instead of being hardcoded to `display_interface::DisplayError`

* If you are using `stm32f4xx-hal`'s fsmc, you can copy and paste this adapter:
```rust
pub struct FsmcAdapter<S, WORD>(pub Lcd<S, WORD>);

impl<S, WORD> Interface for FsmcAdapter<S, WORD>
where
S: SubBank,
WORD: Word + Copy + From<u8>,
{
type Word = WORD;

type Error = Infallible;

fn send_command(&mut self, command: u8, args: &[u8]) -> Result<(), Self::Error> {
self.0.write_command(command.into());
for &arg in args {
self.0.write_data(arg.into());
}

Ok(())
}

fn send_pixels<const N: usize>(
&mut self,
pixels: impl IntoIterator<Item = [Self::Word; N]>,
) -> Result<(), Self::Error> {
for pixel in pixels {
for word in pixel {
self.0.write_data(word);
}
}

Ok(())
}

fn send_repeated_pixel<const N: usize>(
&mut self,
pixel: [Self::Word; N],
count: u32,
) -> Result<(), Self::Error> {
self.send_pixels((0..count).map(|_| pixel))
}
}
```


## v0.7 -> 0.8

### Users
Expand Down
5 changes: 4 additions & 1 deletion mipidsi/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

### Added

- added `Display::set_pixels_from_buffer` to allow high performance display writes
- added `GC9107` model support

### Changed

- replaced `display_interface` with our own trait and implementations for significantly better performance, see the [migration guide](https://github.com/almindor/mipidsi/blob/master/docs/MIGRATION.mdMIGRATION.md#v08---09) for details

## [v0.8.0] - 2024-05-24

### Added
Expand Down
3 changes: 0 additions & 3 deletions mipidsi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ documentation = "https://docs.rs/mipidsi"
rust-version = "1.75"

[dependencies]
display-interface = "0.5.0"
embedded-graphics-core = "0.4.0"
embedded-hal = "1.0.0"
nb = "1.0.0"
Expand All @@ -23,8 +22,6 @@ version = "0.8.0"

[dev-dependencies]
embedded-graphics = "0.8.0"
display-interface-spi = "0.5.0"
display-interface-parallel-gpio = "0.7.0"

[features]
default = ["batch"]
Expand Down
4 changes: 2 additions & 2 deletions mipidsi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
This crate provides a generic display driver to connect to TFT displays
that implement the [MIPI Display Command Set](https://www.mipi.org/specifications/display-command-set).

Uses [display_interface](https://crates.io/crates/display-interface) to talk to the hardware via transports (currently SPI, I2C and Parallel GPIO).
Uses `interface::Interface` to talk to the hardware via transports (currently SPI and Parallel GPIO).

An optional batching of draws is supported via the `batch` feature (default on)

_NOTES_:

- The name of this crate is a bit unfortunate as this driver works with displays that use the MIPI Display Command Set via any transport supported by [display_interface](https://crates.io/crates/display-interface) but MIPI Display Serial Interface is NOT supported at this time.
- The name of this crate is a bit unfortunate as this driver works with displays that use the MIPI Display Command Set but MIPI Display Serial Interface is NOT supported at this time.

## License

Expand Down
1 change: 0 additions & 1 deletion mipidsi/examples/parallel_ili9341_rp_pico/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ rp-pico = "0.9.0"

embedded-graphics = "0.8.0"
embedded-graphics-core = "0.4.0"
display-interface-parallel-gpio = "0.7.0"
mipidsi = { path = "../../" }

[workspace]
4 changes: 2 additions & 2 deletions mipidsi/examples/parallel_ili9341_rp_pico/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use embedded_graphics::{
};

// Provides the parallel port and display interface builders
use display_interface_parallel_gpio::{Generic8BitBus, PGPIO8BitInterface};
use mipidsi::interface::{Generic8BitBus, ParallelInterface};

// Provides the Display builder
use mipidsi::Builder;
Expand Down Expand Up @@ -96,7 +96,7 @@ fn main() -> ! {
));

// Define the display interface from a generic 8 bit bus, a Data/Command select pin and a write enable pin
let di = PGPIO8BitInterface::new(bus, dc, wr);
let di = ParallelInterface::new(bus, dc, wr);

// Define the display from the display bus, set the color order as Bgr and initialize it with
// the delay struct and the reset pin
Expand Down
8 changes: 6 additions & 2 deletions mipidsi/examples/spi-ili9486-esp32-c3/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@ edition = "2021"
[dependencies]
mipidsi = { path = "../../" }
hal = { package = "esp-hal", version = "0.21", features = ["esp32c3"] }
esp-backtrace = { version = "0.14", features = ["esp32c3", "panic-handler", "exception-handler", "println"] }
esp-backtrace = { version = "0.14", features = [
"esp32c3",
"panic-handler",
"exception-handler",
"println",
] }
esp-println = { version = "0.12", features = ["esp32c3"] }
embedded-graphics = "0.8.0"
display-interface-spi = "0.5.0"
fugit = "0.3.7"
embedded-hal-bus = "0.2.0"

Expand Down
6 changes: 4 additions & 2 deletions mipidsi/examples/spi-ili9486-esp32-c3/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use embedded_graphics::{
};

// Provides the parallel port and display interface builders
use display_interface_spi::SPIInterface;
use mipidsi::interface::SpiInterface;

// Provides the Display builder
use mipidsi::{models::ILI9486Rgb565, Builder};
Expand Down Expand Up @@ -71,8 +71,10 @@ fn main() -> ! {
let cs_output = Output::new(cs, Level::High);
let spi_device = ExclusiveDevice::new_no_delay(spi, cs_output).unwrap();

let mut buffer = [0_u8; 512];

// Define the display interface with no chip select
let di = SPIInterface::new(spi_device, dc);
let di = SpiInterface::new(spi_device, dc, &mut buffer);

// Define the display from the display interface and initialize it
let mut display = Builder::new(ILI9486Rgb565, di)
Expand Down
1 change: 0 additions & 1 deletion mipidsi/examples/spi-st7789-rpi-zero-w/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ edition = "2021"

[dependencies]
mipidsi = { path = "../../" }
display-interface-spi = "0.5.0"
embedded-graphics = "0.8.0"
rppal = { version = "0.17.1", features = ["hal"] }
embedded-hal-bus = "0.2.0"
Expand Down
5 changes: 3 additions & 2 deletions mipidsi/examples/spi-st7789-rpi-zero-w/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ Buttons:
Read the README.md for more information.
*/

use display_interface_spi::SPIInterface;
use embedded_graphics::{
mono_font::{ascii::FONT_10X20, MonoTextStyle},
pixelcolor::Rgb565,
prelude::*,
text::Text,
};
use embedded_hal_bus::spi::ExclusiveDevice;
use mipidsi::interface::SpiInterface;
use mipidsi::{models::ST7789, options::ColorInversion, Builder};
use rppal::gpio::Gpio;
use rppal::hal::Delay;
Expand Down Expand Up @@ -68,7 +68,8 @@ fn main() -> ExitCode {
// SPI Display
let spi = Spi::new(Bus::Spi0, SlaveSelect::Ss1, 60_000_000_u32, Mode::Mode0).unwrap();
let spi_device = ExclusiveDevice::new_no_delay(spi, NoCs).unwrap();
let di = SPIInterface::new(spi_device, dc);
let mut buffer = [0_u8; 512];
let di = SpiInterface::new(spi_device, dc, &mut buffer);
let mut delay = Delay::new();
let mut display = Builder::new(ST7789, di)
.display_size(W as u16, H as u16)
Expand Down
17 changes: 11 additions & 6 deletions mipidsi/src/batch.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,33 @@
//! Original code from: [this repo](https://github.com/lupyuen/piet-embedded/blob/master/piet-embedded-graphics/src/batch.rs)
//! Batch the pixels to be rendered into Pixel Rows and Pixel Blocks (contiguous Pixel Rows).
//! This enables the pixels to be rendered efficiently as Pixel Blocks, which may be transmitted in a single Non-Blocking SPI request.
use crate::{error::Error, models::Model, Display};
use display_interface::WriteOnlyDataCommand;
use crate::{
interface::{Interface, InterfacePixelFormat},
models::Model,
Display,
};
use embedded_graphics_core::prelude::*;
use embedded_hal::digital::OutputPin;

pub trait DrawBatch<DI, M, I>
where
DI: WriteOnlyDataCommand,
DI: Interface,
M: Model,
M::ColorFormat: InterfacePixelFormat<DI::Word>,
I: IntoIterator<Item = Pixel<M::ColorFormat>>,
{
fn draw_batch(&mut self, item_pixels: I) -> Result<(), Error>;
fn draw_batch(&mut self, item_pixels: I) -> Result<(), DI::Error>;
}

impl<DI, M, RST, I> DrawBatch<DI, M, I> for Display<DI, M, RST>
where
DI: WriteOnlyDataCommand,
DI: Interface,
M: Model,
M::ColorFormat: InterfacePixelFormat<DI::Word>,
I: IntoIterator<Item = Pixel<M::ColorFormat>>,
RST: OutputPin,
{
fn draw_batch(&mut self, item_pixels: I) -> Result<(), Error> {
fn draw_batch(&mut self, item_pixels: I) -> Result<(), DI::Error> {
// Get the pixels for the item to be rendered.
let pixels = item_pixels.into_iter();
// Batch the pixels into Pixel Rows.
Expand Down
42 changes: 29 additions & 13 deletions mipidsi/src/builder.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
//! [super::Display] builder module
use display_interface::WriteOnlyDataCommand;
use embedded_hal::digital;
use embedded_hal::{delay::DelayNs, digital::OutputPin};

use crate::{dcs::Dcs, error::InitError, models::Model, Display};
use crate::interface::{Interface, InterfacePixelFormat};
use crate::{dcs::InterfaceExt, models::Model, Display};

use crate::options::{ColorInversion, ColorOrder, ModelOptions, Orientation, RefreshOrder};

Expand All @@ -28,8 +28,9 @@ use crate::options::{ColorInversion, ColorOrder, ModelOptions, Orientation, Refr
/// ```
pub struct Builder<DI, MODEL, RST>
where
DI: WriteOnlyDataCommand,
DI: Interface,
MODEL: Model,
MODEL::ColorFormat: InterfacePixelFormat<DI::Word>,
{
di: DI,
model: MODEL,
Expand All @@ -39,8 +40,9 @@ where

impl<DI, MODEL> Builder<DI, MODEL, NoResetPin>
where
DI: WriteOnlyDataCommand,
DI: Interface,
MODEL: Model,
MODEL::ColorFormat: InterfacePixelFormat<DI::Word>,
{
///
/// Constructs a new builder for given [Model].
Expand All @@ -58,8 +60,9 @@ where

impl<DI, MODEL, RST> Builder<DI, MODEL, RST>
where
DI: WriteOnlyDataCommand,
DI: Interface,
MODEL: Model,
MODEL::ColorFormat: InterfacePixelFormat<DI::Word>,
RST: OutputPin,
{
///
Expand Down Expand Up @@ -149,29 +152,33 @@ where
pub fn init(
mut self,
delay_source: &mut impl DelayNs,
) -> Result<Display<DI, MODEL, RST>, InitError<RST::Error>> {
) -> Result<Display<DI, MODEL, RST>, InitError<DI::Error, RST::Error>> {
let to_u32 = |(a, b)| (u32::from(a), u32::from(b));
let (width, height) = to_u32(self.options.display_size);
let (offset_x, offset_y) = to_u32(self.options.display_offset);
let (max_width, max_height) = to_u32(MODEL::FRAMEBUFFER_SIZE);
assert!(width + offset_x <= max_width);
assert!(height + offset_y <= max_height);

let mut dcs = Dcs::write_only(self.di);

match self.rst {
Some(ref mut rst) => {
rst.set_low().map_err(InitError::Pin)?;
rst.set_low().map_err(InitError::ResetPin)?;
delay_source.delay_us(10);
rst.set_high().map_err(InitError::Pin)?;
rst.set_high().map_err(InitError::ResetPin)?;
}
None => dcs.write_command(crate::dcs::SoftReset)?,
None => self
.di
.write_command(crate::dcs::SoftReset)
.map_err(InitError::Interface)?,
}

let madctl = self.model.init(&mut dcs, delay_source, &self.options)?;
let madctl = self
.model
.init(&mut self.di, delay_source, &self.options)
.map_err(InitError::Interface)?;

let display = Display {
dcs,
di: self.di,
model: self.model,
rst: self.rst,
options: self.options,
Expand All @@ -183,6 +190,15 @@ where
}
}

/// Error returned by [`Builder::init`].
#[derive(Debug)]
pub enum InitError<DI, P> {
/// Error caused by the display interface.
Interface(DI),
/// Error caused by the reset pin's [`OutputPin`](embedded_hal::digital::OutputPin) implementation.
ResetPin(P),
}

/// Marker type for no reset pin.
pub enum NoResetPin {}

Expand Down
Loading

0 comments on commit 2681465

Please sign in to comment.