Support for boards that need a non-standard initialization command

This commit is contained in:
imarkov 2021-07-14 21:32:23 +03:00
parent 19efa445bf
commit 8a4aee95c2

View file

@ -40,7 +40,19 @@ impl DisplaySize for DisplaySize320x480 {
const HEIGHT: usize = 480; const HEIGHT: usize = 480;
} }
/// The default orientation is Portrait /// For quite a few boards (ESP32-S2-Kaluga-1, M5Stack, M5Core2 and others),
/// the ILI9341 initialization command arguments are slightly different
///
/// This trait provides the flexibility for users to define their own
/// initialization command arguments suitable for the particular board they are using
pub trait Mode {
fn mode(&self) -> u8;
fn is_landscape(&self) -> bool;
}
/// The default implementation of the Mode trait from above
/// Should work for most (but not all) boards
pub enum Orientation { pub enum Orientation {
Portrait, Portrait,
PortraitFlipped, PortraitFlipped,
@ -48,6 +60,24 @@ pub enum Orientation {
LandscapeFlipped, LandscapeFlipped,
} }
impl Mode for Orientation {
fn mode(&self) -> u8 {
match self {
Self::Portrait => 0x40 | 0x08,
Self::Landscape => 0x20 | 0x08,
Self::PortraitFlipped => 0x80 | 0x08,
Self::LandscapeFlipped => 0x40 | 0x80 | 0x20 | 0x08,
}
}
fn is_landscape(&self) -> bool {
match self {
Self::Landscape | Self::LandscapeFlipped => true,
Self::Portrait | Self::PortraitFlipped => false,
}
}
}
/// There are two method for drawing to the screen: /// There are two method for drawing to the screen:
/// [Ili9341::draw_raw_iter] and [Ili9341::draw_raw_slice] /// [Ili9341::draw_raw_iter] and [Ili9341::draw_raw_slice]
/// ///
@ -68,7 +98,7 @@ pub struct Ili9341<IFACE, RESET> {
reset: RESET, reset: RESET,
width: usize, width: usize,
height: usize, height: usize,
mode: Orientation, landscape: bool,
} }
impl<IFACE, RESET> Ili9341<IFACE, RESET> impl<IFACE, RESET> Ili9341<IFACE, RESET>
@ -76,23 +106,24 @@ where
IFACE: WriteOnlyDataCommand, IFACE: WriteOnlyDataCommand,
RESET: OutputPin, RESET: OutputPin,
{ {
pub fn new<DELAY, SIZE>( pub fn new<DELAY, SIZE, MODE>(
interface: IFACE, interface: IFACE,
reset: RESET, reset: RESET,
delay: &mut DELAY, delay: &mut DELAY,
mode: Orientation, mode: MODE,
_display_size: SIZE, _display_size: SIZE,
) -> Result<Self> ) -> Result<Self>
where where
DELAY: DelayMs<u16>, DELAY: DelayMs<u16>,
SIZE: DisplaySize, SIZE: DisplaySize,
MODE: Mode,
{ {
let mut ili9341 = Ili9341 { let mut ili9341 = Ili9341 {
interface, interface,
reset, reset,
width: SIZE::WIDTH, width: SIZE::WIDTH,
height: SIZE::HEIGHT, height: SIZE::HEIGHT,
mode: Orientation::Portrait, landscape: false,
}; };
// Do hardware reset by holding reset low for at least 10us // Do hardware reset by holding reset low for at least 10us
@ -172,9 +203,10 @@ where
fixed_top_lines: u16, fixed_top_lines: u16,
fixed_bottom_lines: u16, fixed_bottom_lines: u16,
) -> Result<Scroller> { ) -> Result<Scroller> {
let height = match self.mode { let height = if self.landscape {
Orientation::Landscape | Orientation::LandscapeFlipped => self.width, self.width
Orientation::Portrait | Orientation::PortraitFlipped => self.height, } else {
self.height
} as u16; } as u16;
let scroll_lines = height as u16 - fixed_top_lines - fixed_bottom_lines; let scroll_lines = height as u16 - fixed_top_lines - fixed_bottom_lines;
@ -244,33 +276,16 @@ where
} }
/// Change the orientation of the screen /// Change the orientation of the screen
pub fn set_orientation(&mut self, mode: Orientation) -> Result { pub fn set_orientation<MODE>(&mut self, mode: MODE) -> Result
let was_landscape = match self.mode { where
Orientation::Landscape | Orientation::LandscapeFlipped => true, MODE: Mode,
Orientation::Portrait | Orientation::PortraitFlipped => false, {
}; self.command(Command::MemoryAccessControl, &[mode.mode()])?;
let is_landscape = match mode {
Orientation::Portrait => { if self.landscape ^ mode.is_landscape() {
self.command(Command::MemoryAccessControl, &[0x40 | 0x08])?;
false
}
Orientation::Landscape => {
self.command(Command::MemoryAccessControl, &[0x20 | 0x08])?;
true
}
Orientation::PortraitFlipped => {
self.command(Command::MemoryAccessControl, &[0x80 | 0x08])?;
false
}
Orientation::LandscapeFlipped => {
self.command(Command::MemoryAccessControl, &[0x40 | 0x80 | 0x20 | 0x08])?;
true
}
};
if was_landscape ^ is_landscape {
core::mem::swap(&mut self.height, &mut self.width); core::mem::swap(&mut self.height, &mut self.width);
} }
self.mode = mode; self.landscape = mode.is_landscape();
Ok(()) Ok(())
} }
} }