Initial commit
This commit is contained in:
commit
b1e9960e10
14
Cargo.toml
Normal file
14
Cargo.toml
Normal 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
312
src/lib.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user