2018-11-14 02:13:04 +00:00
|
|
|
use hal;
|
|
|
|
|
2018-11-14 04:35:10 +00:00
|
|
|
use command::{BufCommand, Command, DataEntryMode, DeepSleepMode, IncrementAxis};
|
2018-11-14 02:13:04 +00:00
|
|
|
use interface::DisplayInterface;
|
|
|
|
|
2018-11-14 04:26:09 +00:00
|
|
|
// Max display resolution is 160x296
|
|
|
|
const MAX_SOURCE_OUTPUTS: usize = 160;
|
|
|
|
const MAX_GATE_OUTPUTS: usize = 296;
|
|
|
|
|
|
|
|
// Magic numbers from the data sheet
|
|
|
|
const ANALOG_BLOCK_CONTROL_MAGIC: u8 = 0x54;
|
|
|
|
const DIGITAL_BLOCK_CONTROL_MAGIC: u8 = 0x3B;
|
|
|
|
|
2018-11-14 02:13:04 +00:00
|
|
|
struct Config {}
|
|
|
|
|
2018-11-14 07:02:33 +00:00
|
|
|
pub struct Dimensions {
|
|
|
|
pub rows: u16,
|
|
|
|
pub cols: u8,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
pub enum Rotation {
|
|
|
|
Rotate0,
|
|
|
|
Rotate90,
|
|
|
|
Rotate180,
|
|
|
|
Rotate270,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for Rotation {
|
|
|
|
fn default() -> Self {
|
|
|
|
Rotation::Rotate0
|
|
|
|
}
|
2018-11-14 02:13:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Display<I> where I: DisplayInterface {
|
|
|
|
interface: I,
|
|
|
|
dimensions: Dimensions,
|
2018-11-14 07:02:33 +00:00
|
|
|
rotation: Rotation,
|
2018-11-14 02:13:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<I> Display<I> where I: DisplayInterface {
|
2018-11-14 07:02:33 +00:00
|
|
|
pub fn new(interface: I, dimensions: Dimensions, rotation: Rotation) -> Self {
|
2018-11-16 11:34:31 +00:00
|
|
|
// TODO: Assert dimensions are evenly divisible by 8
|
2018-11-14 02:13:04 +00:00
|
|
|
Self { interface, dimensions, rotation }
|
|
|
|
}
|
|
|
|
|
2018-11-14 04:26:09 +00:00
|
|
|
/// Perform a hardware reset followed by software reset
|
2018-11-14 07:02:33 +00:00
|
|
|
pub fn reset<D: hal::blocking::delay::DelayMs<u8>>(&mut self, delay: &mut D) -> Result<(), I::Error> {
|
2018-11-14 04:26:09 +00:00
|
|
|
self.interface.reset(delay);
|
|
|
|
Command::SoftReset.execute(&mut self.interface)?;
|
|
|
|
self.interface.busy_wait();
|
2018-11-14 07:02:33 +00:00
|
|
|
|
|
|
|
self.init(Config {})
|
2018-11-14 02:13:04 +00:00
|
|
|
}
|
|
|
|
|
2018-11-14 04:26:09 +00:00
|
|
|
/// Initialise the controller according to Section 9: Typical Operating Sequence
|
|
|
|
/// from the data sheet
|
2018-11-14 02:13:04 +00:00
|
|
|
fn init(&mut self, config: Config) -> Result<(), I::Error> {
|
2018-11-14 04:26:09 +00:00
|
|
|
Command::AnalogBlockControl(ANALOG_BLOCK_CONTROL_MAGIC).execute(&mut self.interface)?;
|
|
|
|
Command::DigitalBlockControl(DIGITAL_BLOCK_CONTROL_MAGIC).execute(&mut self.interface)?;
|
|
|
|
|
|
|
|
Command::DriverOutputControl(self.dimensions.rows, 0x00).execute(&mut self.interface)?;
|
|
|
|
|
|
|
|
Command::DummyLinePeriod(0x07).execute(&mut self.interface)?;
|
|
|
|
Command::GateLineWidth(0x04).execute(&mut self.interface)?;
|
|
|
|
|
2018-11-16 11:58:55 +00:00
|
|
|
// Command::GateDrivingVoltage(0b10000 | 0b0001);
|
|
|
|
// Command::SourceDrivingVoltage(0x2D, 0xB2, 0x22).execute(&mut self.interface)?;
|
2018-11-14 04:26:09 +00:00
|
|
|
Command::WriteVCOM(0x3C).execute(&mut self.interface)?;
|
|
|
|
|
|
|
|
// POR is HiZ. Need pull from config
|
|
|
|
// Command::BorderWaveform(u8).execute(&mut self.interface)?;
|
|
|
|
|
2018-11-14 10:09:04 +00:00
|
|
|
BufCommand::WriteLUT(&LUT_RED).execute(&mut self.interface)?;
|
2018-11-14 04:26:09 +00:00
|
|
|
|
|
|
|
Command::DataEntryMode(DataEntryMode::IncrementYIncrementX, IncrementAxis::Horizontal).execute(&mut self.interface)?;
|
2018-11-14 02:13:04 +00:00
|
|
|
|
2018-11-14 04:26:09 +00:00
|
|
|
let end = self.dimensions.cols / 8 - 1;
|
|
|
|
Command::StartEndXPosition(0, end).execute(&mut self.interface)?;
|
|
|
|
Command::StartEndYPosition(0, self.dimensions.rows).execute(&mut self.interface)?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2018-11-14 07:02:33 +00:00
|
|
|
pub fn update<D: hal::blocking::delay::DelayMs<u8>>(&mut self, black: &[u8], red: &[u8], delay: &mut D) -> Result<(), I::Error> {
|
2018-11-14 04:26:09 +00:00
|
|
|
// Write the B/W RAM
|
2018-11-14 10:09:04 +00:00
|
|
|
let buf_limit = ((self.rows() * self.cols() as u16) as f32 / 8.).ceil() as usize;
|
2018-11-14 04:26:09 +00:00
|
|
|
Command::XAddress(0).execute(&mut self.interface)?;
|
|
|
|
Command::YAddress(0).execute(&mut self.interface)?;
|
2018-11-14 10:09:04 +00:00
|
|
|
BufCommand::WriteBlackData(&black[..buf_limit]).execute(&mut self.interface)?;
|
2018-11-14 04:26:09 +00:00
|
|
|
|
|
|
|
// Write the Red RAM
|
|
|
|
Command::XAddress(0).execute(&mut self.interface)?;
|
|
|
|
Command::YAddress(0).execute(&mut self.interface)?;
|
2018-11-14 10:09:04 +00:00
|
|
|
BufCommand::WriteRedData(&red[..buf_limit]).execute(&mut self.interface)?;
|
2018-11-14 04:26:09 +00:00
|
|
|
|
|
|
|
// Kick off the display update
|
|
|
|
Command::UpdateDisplayOption2(0xC7).execute(&mut self.interface)?;
|
|
|
|
Command::UpdateDisplay.execute(&mut self.interface)?;
|
2018-11-14 10:09:04 +00:00
|
|
|
delay.delay_ms(50);
|
2018-11-14 04:26:09 +00:00
|
|
|
// TODO: We don't really need to wait here... the program can go off and do other things
|
|
|
|
// and only busy wait if it wants to talk to the display again. Could possibly treat
|
|
|
|
// the interface like a smart pointer in which "acquiring" it would wait until it's not
|
|
|
|
// busy.
|
|
|
|
self.interface.busy_wait();
|
2018-11-14 02:13:04 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2018-11-14 07:02:33 +00:00
|
|
|
pub fn deep_sleep(&mut self) -> Result<(), I::Error> {
|
2018-11-14 04:35:10 +00:00
|
|
|
Command::DeepSleepMode(DeepSleepMode::PreserveRAM).execute(&mut self.interface)
|
2018-11-14 02:13:04 +00:00
|
|
|
}
|
2018-11-14 07:02:33 +00:00
|
|
|
|
|
|
|
pub fn rows(&self) -> u16 {
|
|
|
|
self.dimensions.rows
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn cols(&self) -> u8 {
|
|
|
|
self.dimensions.cols
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn rotation(&self) -> Rotation {
|
|
|
|
self.rotation
|
|
|
|
}
|
2018-11-14 02:13:04 +00:00
|
|
|
}
|
2018-11-14 10:09:04 +00:00
|
|
|
|
|
|
|
const LUT_RED: [u8; 70] = [
|
|
|
|
// Phase 0 Phase 1 Phase 2 Phase 3 Phase 4 Phase 5 Phase 6
|
|
|
|
// A B C D A B C D A B C D A B C D A B C D A B C D A B C D
|
|
|
|
0b01001000, 0b10100000, 0b00010000, 0b00010000, 0b00010011, 0b00000000, 0b00000000, // LUT0 - Black
|
|
|
|
0b01001000, 0b10100000, 0b10000000, 0b00000000, 0b00000011, 0b00000000, 0b00000000, // LUTT1 - White
|
|
|
|
0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, // IGNORE
|
|
|
|
0b01001000, 0b10100101, 0b00000000, 0b10111011, 0b00000000, 0b00000000, 0b00000000, // LUT3 - Red
|
|
|
|
0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, // LUT4 - VCOM
|
|
|
|
|
|
|
|
// Duration | Repeat
|
|
|
|
// A B C D |
|
|
|
|
64, 12, 32, 12, 6, // 0 Flash
|
|
|
|
16, 8, 4, 4, 6, // 1 clear
|
|
|
|
4, 8, 8, 16, 16, // 2 bring in the black
|
|
|
|
2, 2, 2, 64, 32, // 3 time for red
|
|
|
|
2, 2, 2, 2, 2, // 4 final black sharpen phase
|
|
|
|
0, 0, 0, 0, 0, // 5
|
|
|
|
0, 0, 0, 0, 0 // 6
|
|
|
|
];
|