Do not hardcode display size

ili driver family is pretty generic with support
of multiple display sizes. By having width and size
as parameter this driver can support broader range
of ili displays.
This commit is contained in:
Ales Musil 2020-10-26 13:28:04 +01:00
parent 64963398c7
commit b5077900be

View file

@ -34,8 +34,29 @@ pub trait Interface {
) -> Result<(), Self::Error>; ) -> Result<(), Self::Error>;
} }
/// Trait that defines display size information
pub trait DisplaySize {
/// Width in pixels
const WIDTH: usize;
/// Height in pixels
const HEIGHT: usize;
}
/// Generic display size of 240x320 pixels
pub struct DisplaySize240x320;
impl DisplaySize for DisplaySize240x320 {
const WIDTH: usize = 240; const WIDTH: usize = 240;
const HEIGHT: usize = 320; const HEIGHT: usize = 320;
}
/// Generic display size of 320x480 pixels
pub struct DisplaySize320x480;
impl DisplaySize for DisplaySize320x480 {
const WIDTH: usize = 320;
const HEIGHT: usize = 480;
}
#[derive(Debug)] #[derive(Debug)]
pub enum Error<PinE> { pub enum Error<PinE> {
@ -72,6 +93,7 @@ pub struct Ili9341<IFACE, RESET> {
reset: RESET, reset: RESET,
width: usize, width: usize,
height: usize, height: usize,
mode: Orientation,
} }
impl<PinE, IFACE, RESET> Ili9341<IFACE, RESET> impl<PinE, IFACE, RESET> Ili9341<IFACE, RESET>
@ -79,16 +101,23 @@ where
IFACE: WriteOnlyDataCommand, IFACE: WriteOnlyDataCommand,
RESET: OutputPin<Error = PinE>, RESET: OutputPin<Error = PinE>,
{ {
pub fn new<DELAY: DelayMs<u16>>( pub fn new<DELAY, SIZE>(
interface: IFACE, interface: IFACE,
reset: RESET, reset: RESET,
delay: &mut DELAY, delay: &mut DELAY,
) -> Result<Self, Error<PinE>> { mode: Orientation,
_display_size: SIZE,
) -> Result<Self, Error<PinE>>
where
DELAY: DelayMs<u16>,
SIZE: DisplaySize,
{
let mut ili9341 = Ili9341 { let mut ili9341 = Ili9341 {
interface, interface,
reset, reset,
width: WIDTH, width: SIZE::WIDTH,
height: HEIGHT, height: SIZE::HEIGHT,
mode: Orientation::Portrait,
}; };
// Do hardware reset by holding reset low for at least 10us // Do hardware reset by holding reset low for at least 10us
@ -108,7 +137,7 @@ where
// and 120ms before sending Sleep Out // and 120ms before sending Sleep Out
delay.delay_ms(120); delay.delay_ms(120);
ili9341.set_orientation(Orientation::Portrait)?; ili9341.set_orientation(mode)?;
// Set pixel format to 16 bits per pixel // Set pixel format to 16 bits per pixel
ili9341.command(Command::PixelFormatSet, &[0x55])?; ili9341.command(Command::PixelFormatSet, &[0x55])?;
@ -167,7 +196,11 @@ where
fixed_top_lines: u16, fixed_top_lines: u16,
fixed_bottom_lines: u16, fixed_bottom_lines: u16,
) -> Result<Scroller, Error<PinE>> { ) -> Result<Scroller, Error<PinE>> {
let scroll_lines = HEIGHT as u16 - fixed_top_lines - fixed_bottom_lines; let height = match self.mode {
Orientation::Landscape | Orientation::LandscapeFlipped => self.width,
Orientation::Portrait | Orientation::PortraitFlipped => self.height,
} as u16;
let scroll_lines = height as u16 - fixed_top_lines - fixed_bottom_lines;
self.command( self.command(
Command::VerticalScrollDefine, Command::VerticalScrollDefine,
@ -181,7 +214,7 @@ where
], ],
)?; )?;
Ok(Scroller::new(fixed_top_lines, fixed_bottom_lines)) Ok(Scroller::new(fixed_top_lines, fixed_bottom_lines, height))
} }
pub fn scroll_vertically( pub fn scroll_vertically(
@ -189,11 +222,10 @@ where
scroller: &mut Scroller, scroller: &mut Scroller,
num_lines: u16, num_lines: u16,
) -> Result<(), Error<PinE>> { ) -> Result<(), Error<PinE>> {
let height = HEIGHT as u16;
scroller.top_offset += num_lines; scroller.top_offset += num_lines;
if scroller.top_offset > (height - scroller.fixed_bottom_lines) { if scroller.top_offset > (scroller.height - scroller.fixed_bottom_lines) {
scroller.top_offset = scroller.fixed_top_lines scroller.top_offset = scroller.fixed_top_lines
+ (scroller.top_offset - height + scroller.fixed_bottom_lines) + (scroller.top_offset - scroller.height + scroller.fixed_bottom_lines)
} }
self.command( self.command(
@ -249,28 +281,33 @@ where
/// Change the orientation of the screen /// Change the orientation of the screen
pub fn set_orientation(&mut self, mode: Orientation) -> Result<(), Error<PinE>> { pub fn set_orientation(&mut self, mode: Orientation) -> Result<(), Error<PinE>> {
match mode { let was_landscape = match self.mode {
Orientation::Landscape | Orientation::LandscapeFlipped => true,
Orientation::Portrait | Orientation::PortraitFlipped => false,
};
let is_landscape = match mode {
Orientation::Portrait => { Orientation::Portrait => {
self.width = WIDTH; self.command(Command::MemoryAccessControl, &[0x40 | 0x08])?;
self.height = HEIGHT; false
self.command(Command::MemoryAccessControl, &[0x40 | 0x08])
} }
Orientation::Landscape => { Orientation::Landscape => {
self.width = HEIGHT; self.command(Command::MemoryAccessControl, &[0x20 | 0x08])?;
self.height = WIDTH; true
self.command(Command::MemoryAccessControl, &[0x20 | 0x08])
} }
Orientation::PortraitFlipped => { Orientation::PortraitFlipped => {
self.width = WIDTH; self.command(Command::MemoryAccessControl, &[0x80 | 0x08])?;
self.height = HEIGHT; false
self.command(Command::MemoryAccessControl, &[0x80 | 0x08])
} }
Orientation::LandscapeFlipped => { Orientation::LandscapeFlipped => {
self.width = HEIGHT; self.command(Command::MemoryAccessControl, &[0x40 | 0x80 | 0x20 | 0x08])?;
self.height = WIDTH; true
self.command(Command::MemoryAccessControl, &[0x40 | 0x80 | 0x20 | 0x08])
} }
};
if was_landscape ^ is_landscape {
core::mem::swap(&mut self.height, &mut self.width);
} }
self.mode = mode;
Ok(())
} }
/// Get the current screen width. It can change based on the current orientation /// Get the current screen width. It can change based on the current orientation
@ -290,14 +327,16 @@ pub struct Scroller {
top_offset: u16, top_offset: u16,
fixed_bottom_lines: u16, fixed_bottom_lines: u16,
fixed_top_lines: u16, fixed_top_lines: u16,
height: u16,
} }
impl Scroller { impl Scroller {
fn new(fixed_top_lines: u16, fixed_bottom_lines: u16) -> Scroller { fn new(fixed_top_lines: u16, fixed_bottom_lines: u16, height: u16) -> Scroller {
Scroller { Scroller {
top_offset: fixed_top_lines, top_offset: fixed_top_lines,
fixed_top_lines, fixed_top_lines,
fixed_bottom_lines, fixed_bottom_lines,
height,
} }
} }
} }