diff --git a/src/main.rs b/src/main.rs index 31ab70a..ed4dcab 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,14 +1,15 @@ extern crate enum_primitive; extern crate num; extern crate spidev; -use std::{thread, time}; mod instructions; mod panel; +mod sequence_linux_kernel; +mod sequence_tdo; mod spi; -use instructions::{BK0Command2, BK1Command2, Command, Command2Selection, CommandsGeneral}; use panel::TDOMode; +use sequence_tdo::init; use spi::ST7701S; /// ST7701S supports two kinds of RGB interface, DE mode (mode 1) and HV mode @@ -19,166 +20,8 @@ use spi::ST7701S; fn main() { println!("Initializing SPI driver for ST7701S panel"); - let mut CMD2: Command2Selection = Command2Selection::Disabled; let mut display = ST7701S::new(String::from("/dev/spidev1.0")); let mode = TDOMode; - // SOFTWARE RESET - // 5ms delay - display.write_command(CommandsGeneral::software_reset()); - thread::sleep(time::Duration::from_millis(10)); - - // EXIT SLEEP MODE - // Variable delay (200ms is "safe") - display.write_command(CommandsGeneral::sleep_mode_off()); - thread::sleep(time::Duration::from_millis(300)); - - // ENTER BK0 COMMAND2 MODE - display.write_command(CommandsGeneral::set_command_2(Command2Selection::BK0)); - CMD2 = Command2Selection::BK0; - - display.write_command(BK0Command2::positive_gamma_control( - &CMD2, - &[ - 0x00, 0x0E, 0x15, 0x0F, 0x11, 0x08, 0x08, 0x08, 0x08, 0x23, 0x04, 0x13, 0x12, 0x2B, - 0x34, 0x1F, - ], - )); - display.write_command(BK0Command2::negative_gamma_control( - &CMD2, - &[ - 0x00, 0x0E, 0x95, 0x0F, 0x13, 0x07, 0x09, 0x08, 0x08, 0x22, 0x04, 0x10, 0x0E, 0x2C, - 0x34, 0x1F, - ], - )); - display.write_command(BK0Command2::display_line_setting(&CMD2, 0x80, 0x69, 0x02)); - display.write_command(BK0Command2::porch_control(&CMD2, &mode)); - display.write_command(BK0Command2::inversion_select( - &CMD2, - instructions::Inversion::Column, - 0xFF, - )); - display.write_command(BK0Command2::rgb_control( - &CMD2, - instructions::DataEnable::DE, - instructions::VsyncActive::Low, - instructions::HsyncActive::Low, - instructions::DataPolarity::Rising, - instructions::EnablePolarity::Low, - &mode, - )); - - // ENTER BK1 COMMAND2 MODE - display.write_command(CommandsGeneral::set_command_2(Command2Selection::BK1)); - CMD2 = Command2Selection::BK1; - - display.write_command(BK1Command2::set_vop_amplitude(&CMD2, 0x45)); - display.write_command(BK1Command2::set_vcom_amplitude(&CMD2, 0x13)); - display.write_command(BK1Command2::set_vgh_voltage(&CMD2, 0x07)); - display.write_command(BK1Command2::test_command_setting(&CMD2)); - display.write_command(BK1Command2::set_vgl_voltage(&CMD2, 0x07)); - display.write_command(BK1Command2::power_control_one( - &CMD2, - instructions::GammaOPBias::Middle, - instructions::SourceOPInput::Min, - instructions::SourceOPOutput::Off, - )); - - display.write_command(BK1Command2::power_control_two( - &CMD2, - instructions::VoltageAVDD::Pos6_6, - instructions::VoltageAVCL::Neg4_4, - )); - display.write_command(BK1Command2::set_pre_drive_timing_one(&CMD2, 0x03)); - display.write_command(BK1Command2::set_pre_drive_timing_two(&CMD2, 0x03)); - - // UNKNOWABLE CARGO-CULTED MYSTERY MEAT - // - // I copied this command sequence from the Linux MIPI driver for the ST7701, - // written in C. The author of that driver _also_ had no idea what this - // command sequence does or means, and claims to have himself copied it from - // a sample provided by a Sitronix engineer. Since this is a Linux SPI - // driver for the ST7701S written in Rust, there's ample opportunity for - // something to not line up. - // - // May whatever gods you pray to have mercy on our souls. - display.write_command(Ok(Command { - address: 0xE0, - parameters: vec![0x00, 0x00, 0x02], - })); - display.write_command(Ok(Command { - address: 0xE1, - parameters: vec![ - 0x0B, 0x00, 0x0D, 0x00, 0x0C, 0x00, 0x0E, 0x00, 0x00, 0x44, 0x44, - ], - })); - display.write_command(Ok(Command { - address: 0xE2, - parameters: vec![ - 0x33, 0x33, 0x44, 0x44, 0x64, 0x00, 0x66, 0x00, 0x65, 0x00, 0x67, 0x00, 0x00, - ], - })); - display.write_command(Ok(Command { - address: 0xE3, - parameters: vec![0x00, 0x00, 0x33, 0x33], - })); - display.write_command(Ok(Command { - address: 0xE4, - parameters: vec![0x44, 0x44], - })); - display.write_command(Ok(Command { - address: 0xE5, - parameters: vec![ - 0x0C, 0x78, 0x3C, 0xA0, 0x0E, 0x78, 0x3C, 0xA0, 0x10, 0x78, 0x3C, 0xA0, 0x12, 0x78, - 0x3C, 0xA0, - ], - })); - display.write_command(Ok(Command { - address: 0xE6, - parameters: vec![0x00, 0x00, 0x33, 0x33], - })); - display.write_command(Ok(Command { - address: 0xE7, - parameters: vec![0x44, 0x44], - })); - display.write_command(Ok(Command { - address: 0xE8, - parameters: vec![ - 0x0D, 0x78, 0x3C, 0xA0, 0x0F, 0x78, 0x3C, 0xA0, 0x11, 0x78, 0x3C, 0xA0, 0x13, 0x78, - 0x3C, 0xA0, - ], - })); - display.write_command(Ok(Command { - address: 0xEB, - parameters: vec![0x02, 0x02, 0x39, 0x39, 0xEE, 0x44, 0x00], - })); - display.write_command(Ok(Command { - address: 0xEC, - parameters: vec![0x00, 0x00], - })); - display.write_command(Ok(Command { - address: 0xED, - parameters: vec![ - 0xFF, 0xF1, 0x04, 0x56, 0x72, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0x27, 0x65, 0x40, - 0x1F, 0xFF, - ], - })); - - // BK1 COMMAND2 DISABLE - display.write_command(CommandsGeneral::set_command_2(Command2Selection::Disabled)); - CMD2 = Command2Selection::Disabled; - - display.write_command(CommandsGeneral::set_color_mode( - instructions::BitsPerPixel::Rgb666, - )); - display.write_command(CommandsGeneral::display_data_control( - instructions::ScanDirection::Normal, - instructions::ColorOrder::Rgb, - )); - display.write_command(CommandsGeneral::tearing_effect_on( - instructions::TearingEffect::VHBlank, - )); - - display.write_command(CommandsGeneral::display_on()); - thread::sleep(time::Duration::from_millis(200)); + init(&mut display, mode); } diff --git a/src/sequence_tdo.rs b/src/sequence_tdo.rs new file mode 100644 index 0000000..ab45726 --- /dev/null +++ b/src/sequence_tdo.rs @@ -0,0 +1,164 @@ +use std::{thread, time}; + +use crate::instructions; +use crate::instructions::{BK0Command2, BK1Command2, Command, Command2Selection, CommandsGeneral}; +use crate::panel::Mode; +use crate::spi::ST7701S; + +pub fn init(display: &mut ST7701S, mode: Mode) { + let mut CMD2: Command2Selection = Command2Selection::Disabled; + + // Set Command2 for BK0 + display.write_command(CommandsGeneral::set_command_2(Command2Selection::BK0)); + CMD2 = Command2Selection::BK0; + + display.write_command(BK0Command2::display_line_setting(&CMD2, 0x3B, 0x00, 0x00)); + // Note: This will be off by one from the TDO spec: + // SPI_WriteComm(0xC1); // PORCTRL + // 0x0B); // V, + // 0x02); // V, + display.write_command(BK0Command2::porch_control(&CMD2, &mode)); + display.write_command(BK0Command2::inversion_select( + &CMD2, + instructions::Inversion::OneDot, + 0x02, + )); + display.write_command(Ok(Command { + address: 0xCC, + parameters: vec![0x10], + })); + display.write_command(BK0Command2::color_control( + &CMD2, + instructions::PWMPolarity::Low, + instructions::LEDPolarity::Low, + instructions::PixelPinout::Condensed, + instructions::EndPixelFormat::SelfMSB, + )); + display.write_command(BK0Command2::positive_gamma_control( + &CMD2, + &[ + 0x02, 0x13, 0x1B, 0x0D, 0x10, 0x05, 0x08, 0x07, 0x07, 0x24, 0x04, 0x11, 0x0E, 0x2C, 0x33, + 0x1D, + ], + )); + display.write_command(BK0Command2::negative_gamma_control( + &CMD2, + &[ + 0xB1, 0x05, 0x13, 0x1B, 0x0D, 0x11, 0x05, 0x08, 0x07, 0x07, 0x24, 0x04, 0x11, 0x0E, 0x2C, + 0x33, 0x1D, + ], + )); + + // Set Command2 for BK1 + display.write_command(CommandsGeneral::set_command_2(Command2Selection::BK1)); + CMD2 = Command2Selection::BK1; + + display.write_command(BK1Command2::set_vop_amplitude(&CMD2, 0x5d)); + display.write_command(BK1Command2::set_vcom_amplitude(&CMD2, 0x43)); + display.write_command(BK1Command2::set_vgh_voltage(&CMD2, 0x81)); + display.write_command(BK1Command2::test_command_setting(&CMD2)); + display.write_command(BK1Command2::set_vgl_voltage(&CMD2, 0x43)); + display.write_command(BK1Command2::power_control_one( + &CMD2, + instructions::GammaOPBias::Middle, + instructions::SourceOPInput::Min, + instructions::SourceOPOutput::Min, + )); + + display.write_command(BK1Command2::power_control_two( + &CMD2, + instructions::VoltageAVDD::Pos6_6, + instructions::VoltageAVCL::Neg4_4, + )); + display.write_command(BK1Command2::set_pre_drive_timing_one(&CMD2, 0x08)); + display.write_command(BK1Command2::set_pre_drive_timing_two(&CMD2, 0x08)); + display.write_command(Ok(Command { + address: 0xD0, + parameters: vec![0x88], + })); + display.write_command(Ok(Command { + address: 0xE0, + parameters: vec![0x00, 0x00, 0x02], + })); + display.write_command(Ok(Command { + address: 0xE1, + parameters: vec![ + 0x03, 0xA0, 0x00, 0x00, 0x04, 0xA0, 0x00, 0x00, 0x00, 0x20, 0x20, + ], + })); + display.write_command(Ok(Command { + address: 0xE2, + parameters: vec![ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ], + })); + display.write_command(Ok(Command { + address: 0xE3, + parameters: vec![0x00, 0x00, 0x11, 0x00], + })); + display.write_command(Ok(Command { + address: 0xE4, + parameters: vec![0x22, 0x00], + })); + display.write_command(Ok(Command { + address: 0xE5, + parameters: vec![ + 0x05, 0xEC, 0xA0, 0xA0, 0x07, 0xEE, 0xA0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, + ], + })); + display.write_command(Ok(Command { + address: 0xE6, + parameters: vec![0x00, 0x00, 0x11, 0x00], + })); + display.write_command(Ok(Command { + address: 0xE7, + parameters: vec![0x22, 0x00], + })); + display.write_command(Ok(Command { + address: 0xE8, + parameters: vec![ + 0x06, 0xED, 0xA0, 0xA0, 0x08, 0xEF, 0xA0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, + ], + })); + display.write_command(Ok(Command { + address: 0xEB, + parameters: vec![0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00], + })); + display.write_command(Ok(Command { + address: 0xED, + parameters: vec![ + 0xFF, 0xFF, 0xFF, 0xBA, 0x0A, 0xBF, 0x45, 0xFF, 0xFF, 0x54, 0xFB, 0xA0, 0xAB, 0xFF, 0xFF, + 0xFF, + ], + })); + display.write_command(Ok(Command { + address: 0xEF, + parameters: vec![0x10, 0x0D, 0x04, 0x08, 0x3F, 0x1F], + })); + + // Set Command2 for BK3 + display.write_command(CommandsGeneral::set_command_2(Command2Selection::BK1)); + CMD2 = Command2Selection::BK1; + display.write_command(Ok(Command { + address: 0xEF, + parameters: vec![0x08], + })); + + // COMMAND2 DISABLE + display.write_command(CommandsGeneral::set_command_2(Command2Selection::Disabled)); + CMD2 = Command2Selection::Disabled; + + display.write_command(CommandsGeneral::sleep_mode_off()); + thread::sleep(time::Duration::from_millis(120)); + + display.write_command(CommandsGeneral::display_on()); + display.write_command(CommandsGeneral::display_data_control( + instructions::ScanDirection::Normal, + instructions::ColorOrder::Rgb, + )); + display.write_command(CommandsGeneral::set_color_mode( + instructions::BitsPerPixel::Rgb666, + )); +}