8000 Add LCD ili9225 by darkautism · Pull Request #181 · almindor/mipidsi · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Add LCD ili9225 #181

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Apr 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- added `RM67162` model support
- made `InitError` visible
- added `ILI9488` model support
- added `ILI9228` model support
- added `KIND` constant to `Interface` trait to detect invalid model, color format, and interface combinations
- added `InvalidConfiguration` variant to `InitError` enum
- added `update_address_window` in Model trait.

### Changed

- changed the returned error type of `Model::init` to a new `ModelInitError` type to allow implementations to report configuration errors
- added new errors returned from `Builder::init` in case of invalid `display_size` or `display_offset` parameters
- Move functions `set_vertical_scroll_offset`, `set_vertical_scroll_region`, `set_tearing_effect`, `update_options`, `software_reset`, `write_memory_start`, `wake` and `sleep` 's dcs command part into Model trait from Display trait.

## Removed

Expand Down
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,3 @@ batch = ["heapless"]

[workspace]
members = ["mipidsi-async"]

2 changes: 1 addition & 1 deletion src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ where
match self.rst {
Some(ref mut rst) => {
rst.set_low().map_err(InitError::ResetPin)?;
delay_source.delay_us(10);
delay_source.delay_us(MODEL::RESET_DURATION);
rst.set_high().map_err(InitError::ResetPin)?;
}
None => self
Expand Down
3 changes: 1 addition & 2 deletions src/dcs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use crate::interface::Interface;

#[macro_use]
mod macros;
pub(crate) mod macros;

mod set_address_mode;
pub use set_address_mode::*;
Expand Down Expand Up @@ -72,7 +72,6 @@ dcs_basic_command!(
SoftReset,
0x01
);

dcs_basic_command!(
/// Enter Sleep Mode
EnterSleepMode,
Expand Down
51 changes: 19 additions & 32 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
//!
//! * GC9107
//! * GC9A01
//! * ILI9225
//! * ILI9341
//! * ILI9342C
//! * ILI9486
Expand Down Expand Up @@ -105,7 +106,7 @@
//! display.clear(Rgb666::RED).unwrap();
//! ```

use dcs::InterfaceExt;
use dcs::SetAddressMode;

pub mod interface;

Expand Down Expand Up @@ -153,7 +154,7 @@ where
// Model Options, includes current orientation
options: options::ModelOptions,
// Current MADCTL value copy for runtime updates
madctl: dcs::SetAddressMode,
madctl: SetAddressMode,
// State monitor for sleeping TODO: refactor to a Model-connected state machine
sleeping: bool,
}
Expand Down Expand Up @@ -184,10 +185,8 @@ where
/// display.set_orientation(Orientation::default().rotate(Rotation::Deg180)).unwrap();
/// ```
pub fn set_orientation(&mut self, orientation: options::Orientation) -> Result<(), DI::Error> {
self.madctl = self.madctl.with_orientation(orientation); // set orientation
self.di.write_command(self.madctl)?;

Ok(())
self.options.orientation = orientation;
self.model.update_options(&mut self.di, &self.options)
}

///
Expand Down Expand Up @@ -251,7 +250,7 @@ where
{
self.set_address_window(sx, sy, ex, ey)?;

self.di.write_command(dcs::WriteMemoryStart)?;
M::write_memory_start(&mut self.di)?;

M::ColorFormat::send_pixels(&mut self.di, colors)
}
Expand All @@ -276,19 +275,7 @@ where
top_fixed_area: u16,
bottom_fixed_area: u16,
) -> Result<(), DI::Error> {
let rows = M::FRAMEBUFFER_SIZE.1;

let vscrdef = if top_fixed_area + bottom_fixed_area > rows {
dcs::SetScrollArea::new(rows, 0, 0)
} else {
dcs::SetScrollArea::new(
top_fixed_area,
rows - top_fixed_area - bottom_fixed_area,
bottom_fixed_area,
)
};

self.di.write_command(vscrdef)
M::set_vertical_scroll_region(&mut self.di, top_fixed_area, bottom_fixed_area)
}

/// Sets the vertical scroll offset.
Expand All @@ -299,8 +286,7 @@ where
/// Use [`set_vertical_scroll_region`](Self::set_vertical_scroll_region) to setup the scroll region, before
/// using this method.
pub fn set_vertical_scroll_offset(&mut self, offset: u16) -> Result<(), DI::Error> {
let vscad = dcs::SetScrollStart::new(offset);
self.di.write_command(vscad)
M::set_vertical_scroll_offset(&mut self.di, offset)
}

///
Expand Down Expand Up @@ -328,8 +314,14 @@ where

let (sx, sy, ex, ey) = (sx + offset.0, sy + offset.1, ex + offset.0, ey + offset.1);

self.di.write_command(dcs::SetColumnAddress::new(sx, ex))?;
self.di.write_command(dcs::SetPageAddress::new(sy, ey))
M::update_address_window(
&mut self.di,
self.options.orientation.rotation,
sx,
sy,
ex,
ey,
)
}

///
Expand All @@ -339,8 +331,7 @@ where
&mut self,
tearing_effect: options::TearingEffect,
) -> Result<(), DI::Error> {
self.di
.write_command(dcs::SetTearingEffect::new(tearing_effect))
M::set_tearing_effect(&mut self.di, tearing_effect, &self.options)
}

///
Expand All @@ -355,9 +346,7 @@ where
/// Need to call [Self::wake] before issuing other commands
///
pub fn sleep<D: DelayNs>(&mut self, delay: &mut D) -> Result<(), DI::Error> {
self.di.write_command(dcs::EnterSleepMode)?;
// All supported models requires a 120ms delay before issuing other commands
delay.delay_us(120_000);
M::sleep(&mut self.di, delay)?;
self.sleeping = true;
Ok(())
}
Expand All @@ -366,9 +355,7 @@ where
/// Wakes the display after it's been set to sleep via [Self::sleep]
///
pub fn wake<D: DelayNs>(&mut self, delay: &mut D) -> Result<(), DI::Error> {
self.di.write_command(dcs::ExitSleepMode)?;
// ST7789 and st7735s have the highest minimal delay of 120ms
delay.delay_us(120_000);
M::wake(&mut self.di, delay)?;
self.sleeping = false;
Ok(())
}
Expand Down
151 changes: 150 additions & 1 deletion src/models.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
//! Display models.

use crate::{dcs::SetAddressMode, interface::Interface, options::ModelOptions, ConfigurationError};
use crate::{
dcs::{self, InterfaceExt, SetAddressMode},
interface::Interface,
options::{self, ModelOptions, Rotation},
ConfigurationError,
};
use embedded_graphics_core::prelude::RgbColor;
use embedded_hal::delay::DelayNs;

// existing model implementations
mod gc9107;
mod gc9a01;
mod ili9225;
mod ili9341;
mod ili9342c;
mod ili934x;
Expand All @@ -20,6 +26,7 @@ mod st7796;

pub use gc9107::*;
pub use gc9a01::*;
pub use ili9225::*;
pub use ili9341::*;
pub use ili9342c::*;
pub use ili9486::*;
Expand All @@ -37,6 +44,9 @@ pub trait Model {
/// The framebuffer size in pixels.
const FRAMEBUFFER_SIZE: (u16, u16);

/// Duration of the active low reset pulse in µs.
const RESET_DURATION: u32 = 10;

/// Initializes the display for this model with MADCTL from [crate::Display]
/// and returns the value of MADCTL set by init
fn init<DELAY, DI>(
Expand All @@ -48,6 +58,144 @@ pub trait Model {
where
DELAY: DelayNs,
DI: Interface;

/// Updates the address window of the display.
fn update_address_window<DI>(
di: &mut DI,
_rotation: Rotation,
sx: u16,
sy: u16,
ex: u16,
ey: u16,
) -> Result<(), DI::Error>
where
DI: Interface,
{
di.write_command(dcs::SetColumnAddress::new(sx, ex))?;
di.write_command(dcs::SetPageAddress::new(sy, ey))
}

///
/// Need to call [Self::wake] before issuing other commands
///
fn sleep<DI, DELAY>(di: &mut DI, delay: &mut DELAY) -> Result<(), DI::Error>
where
DI: Interface,
DELAY: DelayNs,
{
di.write_command(dcs::EnterSleepMode)?;
// All supported models requires a 120ms delay before issuing other commands
delay.delay_us(120_000);
Ok(())
}
///
/// Wakes the display after it's been set to sleep via [Self::sleep]
///
fn wake<DI, DELAY>(di: &mut DI, delay: &mut DELAY) -> Result<(), DI::Error>
where
DI: Interface,
DELAY: DelayNs,
{
di.write_command(dcs::ExitSleepMode)?;
// ST7789 and st7735s have the highest minimal delay of 120ms
delay.delay_us(120_000);
Ok(())
}
///
/// We need WriteMemoryStart befor write pixel
///
fn write_memory_start<DI>(di: &mut DI) -> Result<(), DI::Error>
where
DI: Interface,
{
di.write_command(dcs::WriteMemoryStart)
}
///
/// SoftReset
///
fn software_reset<DI>(di: &mut DI) -> Result<(), DI::Error>
where
DI: Interface,
{
di.write_command(dcs::SoftReset)
}
///
/// This function will been called if user update options
///
fn update_options<DI>(&self, di: &mut DI, options: &ModelOptions) -> Result<(), DI::Error>
where
DI: Interface,
{
let madctl = SetAddressMode::from(options);
di.write_command(madctl)
}

///
/// Configures the tearing effect output.
///
fn set_tearing_effect<DI>(
di: &mut DI,
tearing_effect: options::TearingEffect,
_options: &ModelOptions,
) -> Result<(), DI::Error>
where
DI: Interface,
{
di.write_command(dcs::SetTearingEffect::new(tearing_effect))
}

/// Sets the vertical scroll region.
///
/// The `top_fixed_area` and `bottom_fixed_area` arguments can be used to
/// define an area on the top and/or bottom of the display which won't be
/// affected by scrolling.
///
/// Note that this method is not affected by the current display orientation
/// and will always scroll vertically relative to the default display
/// orientation.
///
/// The combined height of the fixed area must not larger than the
/// height of the framebuffer height in the default orientation.
///
/// After the scrolling region is defined the [`set_vertical_scroll_offset`](Self::set_vertical_scroll_offset) can be
/// used to scroll the display.
fn set_vertical_scroll_region<DI>(
di: &mut DI,
top_fixed_area: u16,
bottom_fixed_area: u16,
) -> Result<(), DI::Error>
where
DI: Interface,
{
let rows = Self::FRAMEBUFFER_SIZE.1;

let vscrdef = if top_fixed_area + bottom_fixed_area > rows {
dcs::SetScrollArea::new(rows, 0, 0)
} else {
dcs::SetScrollArea::new(
top_fixed_area,
rows - top_fixed_area - bottom_fixed_area,
bottom_fixed_area,
)
};

di.write_command(vscrdef)
}

/// Sets the vertical scroll offset.
///
/// Setting the vertical scroll offset shifts the vertical scroll region
/// upwards by `offset` pixels.
///
/// Use [`set_vertical_scroll_region`](Self::set_vertical_scroll_region) to setup the scroll region, before
/// using this method.
fn set_vertical_scroll_offset<DI>(di: &mut DI, offset: u16) -> Result<(), DI::Error>
where
DI: Interface,
{
let vscad = dcs::SetScrollStart::new(offset);
di.write_command(vscad)
}
}

/// Error returned by [`Model::init`].
Expand Down Expand Up @@ -79,6 +227,7 @@ mod tests {
use crate::{
Builder,
_mock::{MockDelay, MockDisplayInterface},
dcs::SetAddressMode,
interface::InterfaceKind,
ConfigurationError, InitError,
};
Expand Down
Loading
Loading
0