Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
GrantM11235 committed Nov 16, 2024
1 parent e808fb9 commit 0a81216
Show file tree
Hide file tree
Showing 20 changed files with 665 additions and 366 deletions.
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
11 changes: 5 additions & 6 deletions mipidsi/src/batch.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
//! 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::PixelInterface, models::Model, Display};
use embedded_graphics_core::prelude::*;
use embedded_hal::digital::OutputPin;

pub trait DrawBatch<DI, M, I>
where
DI: WriteOnlyDataCommand,
DI: PixelInterface<M::ColorFormat>,
M: Model,
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: PixelInterface<M::ColorFormat>,
M: Model,
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
19 changes: 12 additions & 7 deletions mipidsi/src/builder.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
//! [super::Display] builder module
use display_interface::WriteOnlyDataCommand;
use embedded_hal::digital;
use embedded_hal::{delay::DelayNs, digital::OutputPin};

use crate::interface::PixelInterface;
use crate::{dcs::Dcs, error::InitError, models::Model, Display};

use crate::options::{ColorInversion, ColorOrder, ModelOptions, Orientation, RefreshOrder};
Expand All @@ -28,7 +28,7 @@ use crate::options::{ColorInversion, ColorOrder, ModelOptions, Orientation, Refr
/// ```
pub struct Builder<DI, MODEL, RST>
where
DI: WriteOnlyDataCommand,
DI: PixelInterface<MODEL::ColorFormat>,
MODEL: Model,
{
di: DI,
Expand All @@ -39,7 +39,7 @@ where

impl<DI, MODEL> Builder<DI, MODEL, NoResetPin>
where
DI: WriteOnlyDataCommand,
DI: PixelInterface<MODEL::ColorFormat>,
MODEL: Model,
{
///
Expand All @@ -58,7 +58,7 @@ where

impl<DI, MODEL, RST> Builder<DI, MODEL, RST>
where
DI: WriteOnlyDataCommand,
DI: PixelInterface<MODEL::ColorFormat>,
MODEL: Model,
RST: OutputPin,
{
Expand Down Expand Up @@ -149,7 +149,7 @@ 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);
Expand All @@ -165,10 +165,15 @@ where
delay_source.delay_us(10);
rst.set_high().map_err(InitError::Pin)?;
}
None => dcs.write_command(crate::dcs::SoftReset)?,
None => dcs
.write_command(crate::dcs::SoftReset)
.map_err(InitError::DisplayError)?,
}

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

let display = Display {
dcs,
Expand Down
20 changes: 7 additions & 13 deletions mipidsi/src/dcs.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
//! MIPI DCS commands.
use display_interface::{DataFormat, WriteOnlyDataCommand};

use crate::error::Error;
use crate::interface::CommandInterface;

#[macro_use]
mod macros;
Expand Down Expand Up @@ -35,7 +33,7 @@ pub trait DcsCommand {
fn fill_params_buf(&self, buffer: &mut [u8]) -> usize;
}

/// Wrapper around [`WriteOnlyDataCommand`] with support for writing DCS commands.
/// Wrapper around [`CommandInterface`] with support for writing DCS commands.
///
/// Commands which are part of the manufacturer independent user command set can be sent to the
/// display by using the [`write_command`](Self::write_command) method with one of the command types
Expand All @@ -51,7 +49,7 @@ pub struct Dcs<DI> {

impl<DI> Dcs<DI>
where
DI: WriteOnlyDataCommand,
DI: CommandInterface,
{
/// Creates a new [Dcs] instance from a display interface.
pub fn write_only(di: DI) -> Self {
Expand All @@ -64,7 +62,7 @@ where
}

/// Sends a DCS command to the display interface.
pub fn write_command(&mut self, command: impl DcsCommand) -> Result<(), Error> {
pub fn write_command(&mut self, command: impl DcsCommand) -> Result<(), DI::Error> {
let mut param_bytes: [u8; 16] = [0; 16];
let n = command.fill_params_buf(&mut param_bytes);
self.write_raw(command.instruction(), &param_bytes[..n])
Expand All @@ -79,13 +77,9 @@ where
/// This method is intended to be used for sending commands which are not part of the MIPI DCS
/// user command set. Use [`write_command`](Self::write_command) for commands in the user
/// command set.
pub fn write_raw(&mut self, instruction: u8, param_bytes: &[u8]) -> Result<(), Error> {
self.di.send_commands(DataFormat::U8(&[instruction]))?;

if !param_bytes.is_empty() {
self.di.send_data(DataFormat::U8(param_bytes))?; // TODO: empty guard?
}
Ok(())
pub fn write_raw(&mut self, instruction: u8, param_bytes: &[u8]) -> Result<(), DI::Error> {
self.di.send_command(instruction, param_bytes)?;
self.di.flush()
}
}

Expand Down
22 changes: 4 additions & 18 deletions mipidsi/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,10 @@
//! [Error] module for [super::Display]
use display_interface::DisplayError;
//! Error module for [super::Display]
/// Error returned by [`Builder::init`](crate::Builder).
#[derive(Debug)]
pub enum InitError<PE> {
pub enum InitError<DI, P> {
/// Error caused by the display interface.
DisplayError,
DisplayError(DI),
/// Error caused by the reset pin's [`OutputPin`](embedded_hal::digital::OutputPin) implementation.
Pin(PE),
}

///
/// Alias of [DisplayError] for out-of-init use cases
/// since the pin error is only possible during [super::Builder] use
///
pub type Error = DisplayError;

impl<PE> From<DisplayError> for InitError<PE> {
fn from(_: DisplayError) -> Self {
InitError::DisplayError
}
Pin(P),
}
20 changes: 11 additions & 9 deletions mipidsi/src/graphics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,17 @@ use embedded_graphics_core::{
};
use embedded_hal::digital::OutputPin;

use crate::dcs::BitsPerPixel;
use crate::models::Model;
use crate::{error::Error, Display};
use display_interface::WriteOnlyDataCommand;
use crate::Display;
use crate::{dcs::BitsPerPixel, interface::PixelInterface};
use crate::{dcs::WriteMemoryStart, models::Model};

impl<DI, M, RST> DrawTarget for Display<DI, M, RST>
where
DI: WriteOnlyDataCommand,
DI: PixelInterface<M::ColorFormat>,
M: Model,
RST: OutputPin,
{
type Error = Error;
type Error = DI::Error;
type Color = M::ColorFormat;

#[cfg(not(feature = "batch"))]
Expand Down Expand Up @@ -104,19 +103,22 @@ where
};

let count = area.size.width * area.size.height;
let mut colors = take_u32(core::iter::repeat(color), count);

let sx = area.top_left.x as u16;
let sy = area.top_left.y as u16;
let ex = bottom_right.x as u16;
let ey = bottom_right.y as u16;
self.set_pixels(sx, sy, ex, ey, &mut colors)

self.set_address_window(sx, sy, ex, ey)?;
self.dcs.write_command(WriteMemoryStart)?;
self.dcs.di.send_repeated_pixel(color, count)?;
self.dcs.di.flush()
}
}

impl<DI, MODEL, RST> OriginDimensions for Display<DI, MODEL, RST>
where
DI: WriteOnlyDataCommand,
DI: PixelInterface<MODEL::ColorFormat>,
MODEL: Model,
RST: OutputPin,
{
Expand Down
38 changes: 38 additions & 0 deletions mipidsi/src/interface/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//! Interface traits and implementations
/// Command interface
pub trait CommandInterface {
/// Error type
type Error: core::fmt::Debug;

/// Send a command with optional parameters
///
/// [`CommandInterface::flush`] must be called to ensure the data is actually sent
fn send_command(&mut self, command: u8, args: &[u8]) -> Result<(), Self::Error>;

/// Sends any remaining buffered data
fn flush(&mut self) -> Result<(), Self::Error>;
}

/// Pixel interface
pub trait PixelInterface<P: Copy>: CommandInterface {
/// Send a single pixel
///
/// `WriteMemoryStart` must be sent before calling this function
///
/// [`CommandInterface::flush`] must be called to ensure the data is actually sent
fn send_pixel(&mut self, pixel: P) -> Result<(), Self::Error>;

/// Send the same pixel value multiple times
///
/// `WriteMemoryStart` must be sent before calling this function
///
/// [`CommandInterface::flush`] must be called to ensure the data is actually sent
fn send_repeated_pixel(&mut self, pixel: P, count: u32) -> Result<(), Self::Error>;
}

mod spi;
pub use spi::*;

mod parallel;
pub use parallel::*;
Loading

0 comments on commit 0a81216

Please sign in to comment.