commit 891ed62f51cc364db7efdf5d5f4f4e1f06e62793 Author: Yuri Iozzelli Date: Sat Feb 24 14:37:17 2018 +0100 First commit. Basic functionality ok diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e1b78a1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ + +/target/ +**/*.rs.bk +Cargo.lock +**/*.swp diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..fabb5b7 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "ili9341" +version = "0.1.0" +authors = ["Yuri Iozzelli "] + +[dependencies] +embedded-hal = "0.1.0" diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..2b4f1ff --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,232 @@ +#![no_std] + +extern crate embedded_hal as hal; + +use hal::blocking::spi; +use hal::blocking::delay::DelayMs; +use hal::spi::{Mode, Phase, Polarity}; +use hal::digital::OutputPin; + +use core::iter::IntoIterator; + +/// SPI mode +pub const MODE: Mode = Mode { + polarity: Polarity::IdleLow, + phase: Phase::CaptureOnFirstTransition, +}; + +pub const WIDTH: u16 = 240; +pub const HEIGHT: u16 = 320; + +#[derive(Debug)] +pub enum Error { + Spi(E), +} + +pub struct Ili9341 { + spi: SPI, + cs: CS, + dc: DC, + reset: RESET, + width: usize, + height: usize, +} + +impl Ili9341 +where + SPI: spi::Transfer + spi::Write, + CS: OutputPin, + DC: OutputPin, + RESET: OutputPin, +{ + pub fn new>(spi: SPI, cs: CS, dc: DC, reset: RESET, delay: &mut DELAY) -> Result> { + let mut ili9341 = Ili9341 { + spi, + cs, + dc, + reset, + width: 240, + height: 320, + }; + + ili9341.hard_reset(delay); + ili9341.command(Command::SoftwareReset, &[])?; + delay.delay_ms(200); + + ili9341.command(Command::PowerControlA, &[0x39, 0x2c, 0x00, 0x34, 0x02])?; + ili9341.command(Command::PowerControlB, &[0x00, 0xc1, 0x30])?; + ili9341.command(Command::DriverTimingControlA, &[0x85, 0x00, 0x78])?; + ili9341.command(Command::DriverTimingControlB, &[0x00, 0x00])?; + ili9341.command(Command::PowerOnSequenceControl, &[0x64, 0x03, 0x12, 0x81])?; + ili9341.command(Command::PumpRatioControl, &[0x20])?; + ili9341.command(Command::PowerControl1, &[0x23])?; + ili9341.command(Command::PowerControl2, &[0x10])?; + ili9341.command(Command::VCOMControl1, &[0x3e, 0x28])?; + ili9341.command(Command::VCOMControl2, &[0x86])?; + ili9341.command(Command::MemoryAccessControl, &[0x48])?; + ili9341.command(Command::PixelFormatSet, &[0x55])?; + ili9341.command(Command::FrameControlNormal, &[0x00, 0x18])?; + ili9341.command(Command::DisplayFunctionControl, &[0x08, 0x82, 0x27])?; + ili9341.command(Command::Enable3G, &[0x00])?; + ili9341.command(Command::GammaSet, &[0x01])?; + ili9341.command( + Command::PositiveGammaCorrection, + &[ + 0x0f, 0x31, 0x2b, 0x0c, 0x0e, 0x08, 0x4e, 0xf1, 0x37, 0x07, 0x10, 0x03, 0x0e, 0x09, + 0x00, + ], + )?; + ili9341.command( + Command::NegativeGammaCorrection, + &[ + 0x00, 0x0e, 0x14, 0x03, 0x11, 0x07, 0x31, 0xc1, 0x48, 0x08, 0x0f, 0x0c, 0x31, 0x36, + 0x0f, + ], + )?; + ili9341.command(Command::SleepOut, &[])?; + delay.delay_ms(120); + ili9341.command(Command::DisplayOn, &[])?; + + Ok(ili9341) + } + + fn hard_reset>(&mut self, delay: &mut DELAY) { + // set high if previously low + self.reset.set_high(); + delay.delay_ms(200); + // set low for reset + self.reset.set_low(); + delay.delay_ms(200); + // set high for normal operation + self.reset.set_high(); + delay.delay_ms(200); + } + fn command(&mut self, cmd: Command, args: &[u8]) -> Result<(), Error> { + self.cs.set_low(); + + self.dc.set_low(); + self.spi.write(&[cmd as u8]).map_err(Error::Spi)?; + + self.dc.set_high(); + self.spi.write(args).map_err(Error::Spi)?; + + self.cs.set_high(); + Ok(()) + } + fn write_iter>(&mut self, data: I) -> Result<(), Error> { + self.cs.set_low(); + + self.dc.set_low(); + self.spi.write(&[Command::MemoryWrite as u8]).map_err(Error::Spi)?; + + self.dc.set_high(); + for d in data.into_iter() { + self.spi.write(&[(d>>8) as u8, (d&0xff) as u8]).map_err(Error::Spi)?; + } + + self.cs.set_high(); + Ok(()) + } + fn write_raw(&mut self, data: &[u8]) -> Result<(), Error> { + self.cs.set_low(); + + self.dc.set_low(); + self.spi.write(&[Command::MemoryWrite as u8]).map_err(Error::Spi)?; + + self.dc.set_high(); + self.spi.write(data).map_err(Error::Spi)?; + + self.cs.set_high(); + Ok(()) + } + fn set_window(&mut self, x0: u16, y0: u16, x1: u16, y1: u16) -> Result<(), Error> { + self.command( + Command::ColumnAddressSet, + &[ + (x0 >> 8) as u8, + (x0 & 0xff) as u8, + (x1 >> 8) as u8, + (x1 & 0xff) as u8, + ], + )?; + self.command( + Command::PageAddressSet, + &[ + (y0 >> 8) as u8, + (y0 & 0xff) as u8, + (y1 >> 8) as u8, + (y1 & 0xff) as u8, + ], + )?; + Ok(()) + } + pub fn draw_iter>(&mut self, x0: u16, y0: u16, x1: u16, y1: u16, data: I) -> Result<(), Error> { + self.set_window(x0, y0, x1, y1)?; + self.write_iter(data) + } + pub fn draw_raw(&mut self, x0: u16, y0: u16, x1: u16, y1: u16, data: &[u8]) -> Result<(), Error> { + self.set_window(x0, y0, x1, y1)?; + self.write_raw(data) + } + pub fn set_rotation(&mut self, mode: u8) -> Result<(), Error> { + match mode%4 { + 0 => { + self.width = 240; + self.height = 320; + self.command(Command::MemoryAccessControl, &[0x40|0x08]) + }, + 1 => { + self.width = 320; + self.height = 240; + self.command(Command::MemoryAccessControl, &[0x20|0x08]) + }, + 2 => { + self.width = 240; + self.height = 320; + self.command(Command::MemoryAccessControl, &[0x80|0x08]) + }, + 3 => { + self.width = 320; + self.height = 240; + self.command(Command::MemoryAccessControl, &[0x40|0x80|0x20|0x08]) + } + _ => { + unreachable!(); + } + } + } + pub fn width(&self) -> usize { + self.width + } + pub fn height(&self) -> usize { + self.height + } +} + +#[derive(Clone, Copy)] +enum Command { + SoftwareReset = 0x01, + PowerControlA = 0xcb, + PowerControlB = 0xcf, + DriverTimingControlA = 0xe8, + DriverTimingControlB = 0xea, + PowerOnSequenceControl = 0xed, + PumpRatioControl = 0xf7, + PowerControl1 = 0xc0, + PowerControl2 = 0xc1, + VCOMControl1 = 0xc5, + VCOMControl2 = 0xc7, + MemoryAccessControl = 0x36, + PixelFormatSet = 0x3a, + FrameControlNormal = 0xb1, + DisplayFunctionControl = 0xb6, + Enable3G = 0xf2, + GammaSet = 0x26, + PositiveGammaCorrection = 0xe0, + NegativeGammaCorrection = 0xe1, + SleepOut = 0x11, + DisplayOn = 0x29, + ColumnAddressSet = 0x2a, + PageAddressSet = 0x2b, + MemoryWrite = 0x2c, +}