Initial commit

This commit is contained in:
Kevin Hamacher 2018-10-17 18:38:14 +02:00
commit b1e9960e10
2 changed files with 326 additions and 0 deletions

14
Cargo.toml Normal file
View File

@ -0,0 +1,14 @@
[package]
name = "ili9225"
version = "0.1.0"
authors = ["Kevin Hamacher <kevin.hamacher@ruhr-uni-bochum.de>"]
[dependencies]
embedded-graphics = { version = "0.4.0", optional = true }
[dependencies.embedded-hal]
version = "0.2.1"
[features]
default = ["graphics"]
graphics = ["embedded-graphics"]

312
src/lib.rs Normal file
View File

@ -0,0 +1,312 @@
#![no_std]
extern crate embedded_hal as hal;
use hal::digital::OutputPin;
pub const WIDTH: usize = 176;
pub const HEIGHT: usize = 220;
enum Register {
DriverOutputControl = 0x01, // Driver Output Control
LcdACDrivingControl = 0x02, // LCD AC Driving Control
EntryMode = 0x03, // Entry Mode
DisplayControl1 = 0x07, // Display Control 1
BlankPeriodControl = 0x08, // Blank Period Control
FrameCycleControl = 0x0B, // Frame Cycle Control
InterfaceControl = 0x0C, // Interface Control
OscControl = 0x0F, // Osc Control
PowerControl1 = 0x10, // Power Control 1
PowerControl2 = 0x11, // Power Control 2
PowerControl3 = 0x12, // Power Control 3
PowerControl4 = 0x13, // Power Control 4
PowerControl5 = 0x14, // Power Control 5
VciRecycling = 0x15, // VCI Recycling
RamAddressSet1 = 0x20, // Horizontal GRAM Address Set
RamAddressSet2 = 0x21, // Vertical GRAM Address Set
GramData = 0x22, // GRAM Data Register
GateScanControl = 0x30, // Gate Scan Control Register
VerticalScrollControl1 = 0x31, // Vertical Scroll Control 1 Register
VerticalScrollControl2 = 0x32, // Vertical Scroll Control 2 Register
VerticalScrollControl3 = 0x33, // Vertical Scroll Control 3 Register
PartialDrivingPosition1 = 0x34, // Partial Driving Position 1 Register
PartialDrivingPosition2 = 0x35, // Partial Driving Position 2 Register
HorizontalWindowStart = 0x36, // Horizontal Address Start Position
HorizontalWindowEnd = 0x37, // Horizontal Address End Position
VerticalWindowStart = 0x38, // Vertical Address Start Position
VerticalWindowEnd = 0x39, // Vertical Address End Position
GammaControl1 = 0x50, // Gamma Control 1
GammaControl2 = 0x51, // Gamma Control 2
GammaControl3 = 0x52, // Gamma Control 3
GammaControl4 = 0x53, // Gamma Control 4
GammaControl5 = 0x54, // Gamma Control 5
GammaControl6 = 0x55, // Gamma Control 6
GammaControl7 = 0x56, // Gamma Control 7
GammaControl8 = 0x57, // Gamma Control 8
GammaControl9 = 0x58, // Gamma Control 9
GammaControl10 = 0x59, // Gamma Control 10
// TODO
UnknownTodo = 0x00FF,
}
const InvertOnCommand: u16 = 0x20;
const InvertOffCommand: u16 = 0x21;
/*
// autoincrement modes (register ILI9225_ENTRY_MODE, bit 5..3 )
enum autoIncMode_t { R2L_BottomUp, BottomUp_R2L, L2R_BottomUp, BottomUp_L2R, R2L_TopDown, TopDown_R2L, L2R_TopDown, TopDown_L2R };
*/
pub enum Orientation {
Portrait = 0,
Landscape = 1,
InvertedPortrait = 2,
InvertedLandscape = 3,
}
pub fn to_rgb565(r: u8, g: u8, b: u8) -> u16 {
(((r >> 3) as u16) << 11) | (((g >> 2) as u16) << 5) | (b >> 3) as u16
}
// TODO: Do we need a CS?
pub struct ILI9225<SPI, DC, RESET, DELAY> {
spi: SPI,
dc: DC,
reset: RESET,
delay: DELAY,
}
impl<SPI, DC, RESET, DELAY> ILI9225<SPI, DC, RESET, DELAY>
where
SPI: hal::blocking::spi::Write<u8>,
DC: OutputPin,
RESET: OutputPin,
DELAY: hal::blocking::delay::DelayMs<u8>,
{
pub fn new(spi: SPI, dc: DC, reset: RESET, delay: DELAY) -> Self {
Self {
spi,
dc,
reset,
delay,
}
}
fn write_command8(&mut self, cmd: u8) {
self.dc.set_low();
//CS?
self.spi.write(&[cmd]).ok(); // Ignore result (TODO)
}
fn write_command16(&mut self, cmd: u16) {
self.write_command8((cmd >> 8) as u8);
self.write_command8(cmd as u8);
}
fn write_data8(&mut self, val: u8) {
self.dc.set_high();
//CS?
self.spi.write(&[val]).ok(); // Ignore result (TODO)
}
fn write_data16(&mut self, val: u16) {
self.write_data8((val >> 8) as u8);
self.write_data8(val as u8);
}
fn write_register(&mut self, reg: Register, value: u16) {
self.write_command16(reg as u16);
self.write_data16(value);
}
pub fn init(&mut self) {
// Reset device.
self.reset.set_low();
self.delay.delay_ms(50);
self.reset.set_high();
self.delay.delay_ms(50);
// Assume device is ready now.
// startWrite();
// Reset power control before power-on.
self.write_register(Register::PowerControl1, 0);
self.write_register(Register::PowerControl2, 0);
self.write_register(Register::PowerControl3, 0);
self.write_register(Register::PowerControl4, 0);
self.write_register(Register::PowerControl5, 0);
//endWrite(), repeat for below?
self.delay.delay_ms(40);
self.write_register(Register::PowerControl2, 0x0018);
self.write_register(Register::PowerControl3, 0x6121);
self.write_register(Register::PowerControl4, 0x006F);
self.write_register(Register::PowerControl5, 0x495F);
self.write_register(Register::PowerControl1, 0x0800);
self.delay.delay_ms(10);
self.write_register(Register::PowerControl2, 0x103B);
self.delay.delay_ms(50);
self.write_register(Register::DriverOutputControl, 0x011C); // set the display line number and display direction
self.write_register(Register::LcdACDrivingControl, 0x0100); // set 1 line inversion
self.write_register(Register::EntryMode, 0x1038); // set GRAM write direction and BGR=1.
self.write_register(Register::DisplayControl1, 0x0000); // Display off
self.write_register(Register::BlankPeriodControl, 0x0808); // set the back porch and front porch
self.write_register(Register::FrameCycleControl, 0x1100); // set the clocks number per line
self.write_register(Register::InterfaceControl, 0x0000); // CPU interface
self.write_register(Register::OscControl, 0x0D01); // Set Osc /*0e01*/
self.write_register(Register::VciRecycling, 0x0020); // Set VCI recycling
self.write_register(Register::RamAddressSet1, 0x0000); // RAM Address
self.write_register(Register::RamAddressSet2, 0x0000); // RAM Address
// Set GRam stuff.
self.write_register(Register::GateScanControl, 0x0000);
self.write_register(Register::VerticalScrollControl1, 0x00DB);
self.write_register(Register::VerticalScrollControl2, 0x0000);
self.write_register(Register::VerticalScrollControl3, 0x0000);
self.write_register(Register::PartialDrivingPosition1, 0x00DB);
self.write_register(Register::PartialDrivingPosition2, 0x0000);
self.write_register(Register::HorizontalWindowStart, 0x00AF);
self.write_register(Register::HorizontalWindowEnd, 0x0000);
self.write_register(Register::VerticalWindowStart, 0x00DB);
self.write_register(Register::VerticalWindowEnd, 0x0000);
// Gamma curve.
self.write_register(Register::GammaControl1, 0x0000);
self.write_register(Register::GammaControl2, 0x0808);
self.write_register(Register::GammaControl3, 0x080A);
self.write_register(Register::GammaControl4, 0x000A);
self.write_register(Register::GammaControl5, 0x0A08);
self.write_register(Register::GammaControl6, 0x0808);
self.write_register(Register::GammaControl7, 0x0000);
self.write_register(Register::GammaControl8, 0x0A00);
self.write_register(Register::GammaControl9, 0x0710);
self.write_register(Register::GammaControl10, 0x0710);
// Display on?
self.write_register(Register::DisplayControl1, 0x0012);
self.delay.delay_ms(50);
self.write_register(Register::DisplayControl1, 0x1017);
}
//pub fn clear(&mut self) {}
//pub fn enableBacklight(&mut self, enable: bool) {}
//pub fn setBacklightBrightness(&mut self, brightness: u8) {}
pub fn enable_display(&mut self, enable: bool) {
self.write_register(Register::UnknownTodo, 0);
if enable {
self.write_register(Register::PowerControl1, 0);
self.delay.delay_ms(50);
self.write_register(Register::DisplayControl1, 0x1017);
} else {
self.write_register(Register::DisplayControl1, 0);
self.delay.delay_ms(50);
self.write_register(Register::PowerControl1, 3);
}
}
pub fn invert_display(&mut self, invert: bool) {
self.write_command16(if invert {
InvertOnCommand
} else {
InvertOffCommand
});
}
pub fn set_orientation(&mut self, orientation: Orientation) {}
// getOrientation?
// getSize?
pub fn set_pixel(&mut self, pos: (u16, u16), color: u16) {
// TODO: Bounds checks
// TODO: Orientation
self.write_register(Register::RamAddressSet1, pos.0);
self.write_register(Register::RamAddressSet2, pos.1);
self.write_register(Register::GramData, color);
}
}
#[cfg(feature = "graphics")]
extern crate embedded_graphics;
#[cfg(feature = "graphics")]
use self::embedded_graphics::drawable;
#[cfg(feature = "graphics")]
use self::embedded_graphics::pixelcolor::PixelColorU16;
#[cfg(feature = "graphics")]
use self::embedded_graphics::unsignedcoord::UnsignedCoord;
#[cfg(feature = "graphics")]
use self::embedded_graphics::Drawing;
#[cfg(feature = "graphics")]
impl<SPI, DC, RESET, DELAY> Drawing<PixelColorU16> for ILI9225<SPI, DC, RESET, DELAY>
where
SPI: hal::blocking::spi::Write<u8>,
DC: OutputPin,
RESET: OutputPin,
DELAY: hal::blocking::delay::DelayMs<u8>,
{
fn draw<T>(&mut self, item_pixels: T)
where
T: Iterator<Item = drawable::Pixel<PixelColorU16>>,
{
//let (width, height) = self.display.get_size().dimensions();
for drawable::Pixel(UnsignedCoord(x, y), color) in item_pixels {
//if x <= width.into() && y <= height.into() {
//let color = to_rgb565(color.into(), 0, 0);
// TODO: Is pixelcoloru16 already rgb565?
self.set_pixel((x as u16, y as u16), color.into_inner());
//}
}
}
}
#[cfg(test)]
mod tests {
#[test]
fn color_conversion_works() {
use to_rgb565;
for (res, (r, g, b)) in [
(0x0000, (0, 0, 0)),
(0x0000, (7, 3, 7)),
(0x000F, (0, 0, 127)),
(0x0011, (0, 0, 139)),
(0x001F, (0, 0, 255)),
(0x03E0, (0, 127, 0)),
(0x03EF, (0, 127, 127)),
(0x07E0, (0, 255, 0)),
(0x07FF, (0, 255, 255)),
(0x471A, (64, 224, 208)),
(0x4810, (75, 0, 130)),
(0x7BE0, (127, 127, 0)),
(0x7BEF, (127, 127, 127)),
(0x8000, (128, 0, 0)),
(0x8410, (128, 128, 128)),
(0x867D, (135, 206, 235)),
(0x895C, (138, 43, 226)),
(0x901A, (148, 0, 211)),
(0x9772, (144, 238, 144)),
(0x9E66, (154, 205, 50)),
(0xA145, (165, 42, 42)),
(0xA285, (160, 82, 45)),
(0xAEDC, (172, 216, 230)),
(0xAFE5, (173, 255, 47)),
(0xC618, (192, 192, 192)),
(0xE7FF, (224, 255, 255)),
(0xEC1D, (238, 130, 238)),
(0xF7BB, (245, 245, 220)),
(0xF7FF, (240, 255, 255)),
(0xF800, (255, 0, 0)),
(0xF81F, (255, 0, 255)),
(0xFB08, (255, 99, 71)),
(0xFD20, (255, 165, 0)),
(0xFEA0, (255, 215, 0)),
(0xFFDF, (255, 250, 250)),
(0xFFE0, (255, 255, 0)),
(0xFFFF, (255, 255, 255)),
]
.iter()
{
assert_eq!(to_rgb565(*r, *g, *b), *res);
}
}
}