Skip to content

Commit

Permalink
Merge pull request #17 from almindor/colorswap
Browse files Browse the repository at this point in the history
use DisplayOptions to allow MADCTL control, fixes #10
  • Loading branch information
almindor authored Apr 12, 2022
2 parents 97190e8 + 9c466dc commit 9b06028
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 40 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ The `Display` driver itself contains most of the functionality. Each specific di
let di = SPIInterfaceNoCS::new(spi, dc);
// create the ILI9486 display driver in rgb666 color mode from the display interface and RST pin
let mut display = Display::ili9486_rgb666(di, rst);
display.init(&mut delay::Ets)?;
display.init(&mut delay::Ets, DisplayOptions::default())?;
// clear the display to black
display.clear(Rgb666::BLACK)?;
```
Expand Down
103 changes: 84 additions & 19 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,36 @@ where
///
/// Display orientation.
///
#[repr(u8)]
#[derive(Copy, Clone)]
pub enum Orientation {
Portrait = 0b0000_0000, // no inverting
Landscape = 0b0110_0000, // invert column and page/column order
/// Portrait orientation, with mirror image parameter
Portrait(bool),
/// Landscape orientation, with mirror image parameter
Landscape(bool),
/// Inverted Portrait orientation, with mirror image parameter
PortraitInverted(bool),
/// Inverted Lanscape orientation, with mirror image parameter
LandscapeInverted(bool),
}

impl Default for Orientation {
fn default() -> Self {
Self::Portrait
Self::Portrait(false)
}
}

impl Orientation {
pub fn value_u8(&self) -> u8 {
match self {
Orientation::Portrait(false) => 0b0000_0000,
Orientation::Portrait(true) => 0b0100_0000,
Orientation::PortraitInverted(false) => 0b1100_0000,
Orientation::PortraitInverted(true) => 0b1000_0000,
Orientation::Landscape(false) => 0b0010_0000,
Orientation::Landscape(true) => 0b0110_0000,
Orientation::LandscapeInverted(false) => 0b1110_0000,
Orientation::LandscapeInverted(true) => 0b1010_0000,
}
}
}

Expand All @@ -87,6 +107,55 @@ pub enum TearingEffect {
HorizontalAndVertical,
}

///
/// Defines expected color component ordering, RGB or BGR
///
#[derive(Copy, Clone)]
pub enum ColorOrder {
Rgb,
Bgr,
}

impl Default for ColorOrder {
fn default() -> Self {
Self::Rgb
}
}

///
/// Options for displays used on initialization
///
#[derive(Copy, Clone, Default)]
pub struct DisplayOptions {
/// Initial display orientation (without inverts)
pub orientation: Orientation,
/// Set to make display vertical refresh bottom to top
pub invert_vertical_refresh: bool,
/// Specify display color ordering
pub color_order: ColorOrder,
/// Set to make display horizontal refresh right to left
pub invert_horizontal_refresh: bool,
}

impl DisplayOptions {
/// Returns MADCTL register value for given display options
pub fn madctl(&self) -> u8 {
let mut value = self.orientation.value_u8();
if self.invert_vertical_refresh {
value |= 0b0001_0000;
}
match self.color_order {
ColorOrder::Rgb => {}
ColorOrder::Bgr => value |= 0b0000_1000,
}
if self.invert_horizontal_refresh {
value |= 0b0000_0100;
}

value
}
}

///
/// An error holding its source (pins or SPI)
///
Expand Down Expand Up @@ -134,8 +203,15 @@ where
///
/// * `delay_source` - mutable reference to a [DelayUs] provider
///
pub fn init(&mut self, delay_source: &mut impl DelayUs<u32>) -> Result<(), Error<RST::Error>> {
self.madctl = self.model.init(&mut self.di, &mut self.rst, delay_source)?;
pub fn init(
&mut self,
delay_source: &mut impl DelayUs<u32>,
options: DisplayOptions,
) -> Result<(), Error<RST::Error>> {
self.madctl = self
.model
.init(&mut self.di, &mut self.rst, delay_source, options)?;
self.orientation = options.orientation;
Ok(())
}

Expand All @@ -149,19 +225,8 @@ where
///
/// Sets display [Orientation]
///
pub fn set_orientation(
&mut self,
orientation: Orientation,
invert_x: bool,
invert_y: bool,
) -> Result<(), Error<RST::Error>> {
let mut value = self.madctl | ((orientation as u8) & 0b1110_0000);
if invert_x {
value ^= 0x40
};
if invert_y {
value ^= 0x80
};
pub fn set_orientation(&mut self, orientation: Orientation) -> Result<(), Error<RST::Error>> {
let value = (self.madctl & 0b0001_1111) | orientation.value_u8();
self.write_command(Instruction::MADCTL)?;
self.write_data(&[value])?;
self.orientation = orientation;
Expand Down
3 changes: 2 additions & 1 deletion src/models.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{instruction::Instruction, Error, Orientation};
use crate::{instruction::Instruction, DisplayOptions, Error, Orientation};
use display_interface::{DataFormat, DisplayError, WriteOnlyDataCommand};
use embedded_graphics_core::prelude::RgbColor;
use embedded_hal::{blocking::delay::DelayUs, digital::v2::OutputPin};
Expand All @@ -25,6 +25,7 @@ pub trait Model {
di: &mut DI,
rst: &mut Option<RST>,
delay: &mut DELAY,
options: DisplayOptions,
) -> Result<u8, Error<RST::Error>>
where
RST: OutputPin,
Expand Down
24 changes: 15 additions & 9 deletions src/models/ili9486.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use embedded_graphics_core::{
};
use embedded_hal::{blocking::delay::DelayUs, digital::v2::OutputPin};

use crate::{instruction::Instruction, Display, Error, Orientation};
use crate::{instruction::Instruction, Display, DisplayOptions, Error, Orientation};

use super::{write_command, Model};

Expand All @@ -31,6 +31,7 @@ impl Model for ILI9486Rgb565 {
di: &mut DI,
rst: &mut Option<RST>,
delay: &mut DELAY,
options: DisplayOptions,
) -> Result<u8, Error<RST::Error>>
where
RST: OutputPin,
Expand All @@ -43,7 +44,7 @@ impl Model for ILI9486Rgb565 {
}
delay.delay_us(120_000);

init_common(di, delay).map_err(|_| Error::DisplayError)
init_common(di, delay, options).map_err(|_| Error::DisplayError)
}

fn write_pixels<DI, I>(&mut self, di: &mut DI, colors: I) -> Result<(), DisplayError>
Expand All @@ -60,8 +61,8 @@ impl Model for ILI9486Rgb565 {

fn display_size(&self, orientation: Orientation) -> (u16, u16) {
match orientation {
Orientation::Portrait => (320, 480),
Orientation::Landscape => (480, 320),
Orientation::Portrait(_) | Orientation::PortraitInverted(_) => (320, 480),
Orientation::Landscape(_) | Orientation::LandscapeInverted(_) => (480, 320),
}
}
}
Expand All @@ -78,6 +79,7 @@ impl Model for ILI9486Rgb666 {
di: &mut DI,
rst: &mut Option<RST>,
delay: &mut DELAY,
options: DisplayOptions,
) -> Result<u8, Error<RST::Error>>
where
RST: OutputPin,
Expand All @@ -91,7 +93,7 @@ impl Model for ILI9486Rgb666 {

delay.delay_us(120_000);

init_common(di, delay).map_err(|_| Error::DisplayError)
init_common(di, delay, options).map_err(|_| Error::DisplayError)
}

fn write_pixels<DI, I>(&mut self, di: &mut DI, colors: I) -> Result<(), DisplayError>
Expand All @@ -113,8 +115,8 @@ impl Model for ILI9486Rgb666 {

fn display_size(&self, orientation: Orientation) -> (u16, u16) {
match orientation {
Orientation::Portrait => (320, 480),
Orientation::Landscape => (480, 320),
Orientation::Portrait(_) | Orientation::PortraitInverted(_) => (320, 480),
Orientation::Landscape(_) | Orientation::LandscapeInverted(_) => (480, 320),
}
}
}
Expand Down Expand Up @@ -161,12 +163,16 @@ where
}

// common init for all color format models
fn init_common<DELAY, DI>(di: &mut DI, delay: &mut DELAY) -> Result<u8, DisplayError>
fn init_common<DELAY, DI>(
di: &mut DI,
delay: &mut DELAY,
options: DisplayOptions,
) -> Result<u8, DisplayError>
where
DELAY: DelayUs<u32>,
DI: WriteOnlyDataCommand,
{
let madctl = 0b0000_0000;
let madctl = options.madctl();

write_command(di, Instruction::SLPOUT, &[])?; // turn off sleep
write_command(di, Instruction::COLMOD, &[0b0110_0110])?; // 18bit 256k colors
Expand Down
14 changes: 8 additions & 6 deletions src/models/st7735s.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use embedded_graphics_core::{pixelcolor::Rgb565, prelude::IntoStorage};
use embedded_hal::{blocking::delay::DelayUs, digital::v2::OutputPin};

use crate::no_pin::NoPin;
use crate::Orientation;
use crate::{instruction::Instruction, Display, Error};
use crate::{DisplayOptions, Orientation};

use super::{write_command, Model};

Expand All @@ -24,13 +24,15 @@ impl Model for ST7735s {
di: &mut DI,
rst: &mut Option<RST>,
delay: &mut DELAY,
options: DisplayOptions,
) -> Result<u8, Error<RST::Error>>
where
RST: OutputPin,
DELAY: DelayUs<u32>,
DI: WriteOnlyDataCommand,
{
let madctl = 0b0000_1000;
let madctl = options.madctl() ^ 0b0000_1000; // this model has flipped RGB/BGR bit

match rst {
Some(ref mut rst) => self.hard_reset(rst, delay)?,
None => write_command(di, Instruction::SWRESET, &[])?,
Expand Down Expand Up @@ -93,15 +95,15 @@ impl Model for ST7735s {

fn display_size(&self, orientation: Orientation) -> (u16, u16) {
match orientation {
Orientation::Portrait => (80, 160),
Orientation::Landscape => (160, 80),
Orientation::Portrait(_) | Orientation::PortraitInverted(_) => (80, 160),
Orientation::Landscape(_) | Orientation::LandscapeInverted(_) => (160, 80),
}
}

fn framebuffer_size(&self, orientation: Orientation) -> (u16, u16) {
match orientation {
Orientation::Portrait => (132, 162),
Orientation::Landscape => (162, 132),
Orientation::Portrait(_) | Orientation::PortraitInverted(_) => (132, 162),
Orientation::Landscape(_) | Orientation::LandscapeInverted(_) => (162, 132),
}
}
}
Expand Down
9 changes: 5 additions & 4 deletions src/models/st7789.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use embedded_graphics_core::{pixelcolor::Rgb565, prelude::IntoStorage};
use embedded_hal::{blocking::delay::DelayUs, digital::v2::OutputPin};

use crate::no_pin::NoPin;
use crate::Orientation;
use crate::{instruction::Instruction, Display, Error};
use crate::{DisplayOptions, Orientation};

use super::{write_command, Model};

Expand All @@ -24,13 +24,14 @@ impl Model for ST7789 {
di: &mut DI,
rst: &mut Option<RST>,
delay: &mut DELAY,
options: DisplayOptions,
) -> Result<u8, Error<RST::Error>>
where
RST: OutputPin,
DELAY: DelayUs<u32>,
DI: WriteOnlyDataCommand,
{
let madctl = 0b0000_0000;
let madctl = options.madctl() ^ 0b0000_1000; // this model has flipped RGB/BGR bit
match rst {
Some(ref mut rst) => self.hard_reset(rst, delay)?,
None => write_command(di, Instruction::SWRESET, &[])?,
Expand Down Expand Up @@ -75,8 +76,8 @@ impl Model for ST7789 {

fn framebuffer_size(&self, orientation: Orientation) -> (u16, u16) {
match orientation {
Orientation::Portrait => (240, 320),
Orientation::Landscape => (320, 240),
Orientation::Portrait(_) | Orientation::PortraitInverted(_) => (240, 320),
Orientation::Landscape(_) | Orientation::LandscapeInverted(_) => (320, 240),
}
}
}
Expand Down

0 comments on commit 9b06028

Please sign in to comment.