ssd1675/src/display.rs

174 lines
5.8 KiB
Rust
Raw Normal View History

2018-12-26 01:54:30 +00:00
extern crate libm;
use hal;
2018-12-26 01:54:30 +00:00
use command::{BufCommand, Command, DeepSleepMode};
2018-12-25 21:43:04 +00:00
use config::Config;
use interface::DisplayInterface;
// Max display resolution is 160x296
2018-12-26 01:54:30 +00:00
/// The maximum number of rows supported by the controller
pub const MAX_GATE_OUTPUTS: u16 = 296;
/// The maximum number of columns supported by the controller
pub const MAX_SOURCE_OUTPUTS: u8 = 160;
// Magic numbers from the data sheet
const ANALOG_BLOCK_CONTROL_MAGIC: u8 = 0x54;
const DIGITAL_BLOCK_CONTROL_MAGIC: u8 = 0x3B;
2018-12-26 01:54:30 +00:00
/// Represents the dimensions of the display.
2018-11-14 07:02:33 +00:00
pub struct Dimensions {
2018-12-26 01:54:30 +00:00
/// The number of rows the display has.
///
/// Must be less than or equal to MAX_GATE_OUTPUTS.
2018-11-14 07:02:33 +00:00
pub rows: u16,
2018-12-26 01:54:30 +00:00
/// The number of columns the display has.
///
/// Must be less than or equal to MAX_SOURCE_OUTPUTS.
2018-11-14 07:02:33 +00:00
pub cols: u8,
}
2018-12-26 01:54:30 +00:00
/// Represents the physical rotation of the display relative to the native orientation.
///
/// For example the native orientation of the Inky pHAT display is a tall (portrait) 104x212
/// display. `Rotate270` can be used to make it the right way up when attached to a Raspberry Pi
/// Zero with the ports on the top.
2018-11-14 07:02:33 +00:00
#[derive(Clone, Copy)]
pub enum Rotation {
Rotate0,
Rotate90,
Rotate180,
Rotate270,
}
impl Default for Rotation {
2018-12-26 01:54:30 +00:00
/// Default is no rotation (`Rotate0`).
2018-11-14 07:02:33 +00:00
fn default() -> Self {
Rotation::Rotate0
}
}
2018-12-26 01:54:30 +00:00
/// A configured display with a hardware interface.
2018-12-25 21:43:04 +00:00
pub struct Display<'a, I>
where
I: DisplayInterface,
{
interface: I,
2018-11-27 21:10:16 +00:00
config: Config<'a>,
}
2018-12-25 21:43:04 +00:00
impl<'a, I> Display<'a, I>
where
I: DisplayInterface,
{
2018-12-26 01:54:30 +00:00
/// Create a new display instance from a DisplayInterface and Config.
///
/// The `Config` is typically created with `config::Builder`.
2018-11-27 21:10:16 +00:00
pub fn new(interface: I, config: Config<'a>) -> Self {
Self { interface, config }
}
2018-12-26 01:54:30 +00:00
/// Perform a hardware reset followed by software reset.
///
/// This will wake a controller that has previously entered deep sleep.
2018-12-25 21:43:04 +00:00
pub fn reset<D: hal::blocking::delay::DelayMs<u8>>(
&mut self,
delay: &mut D,
) -> Result<(), I::Error> {
self.interface.reset(delay);
Command::SoftReset.execute(&mut self.interface)?;
self.interface.busy_wait();
2018-11-14 07:02:33 +00:00
2018-11-27 21:10:16 +00:00
self.init()
}
/// Initialise the controller according to Section 9: Typical Operating Sequence
/// from the data sheet
2018-11-27 21:10:16 +00:00
fn init(&mut self) -> Result<(), I::Error> {
Command::AnalogBlockControl(ANALOG_BLOCK_CONTROL_MAGIC).execute(&mut self.interface)?;
Command::DigitalBlockControl(DIGITAL_BLOCK_CONTROL_MAGIC).execute(&mut self.interface)?;
2018-12-25 21:43:04 +00:00
Command::DriverOutputControl(self.config.dimensions.rows, 0x00)
.execute(&mut self.interface)?;
2018-11-27 21:10:16 +00:00
self.config.dummy_line_period.execute(&mut self.interface)?;
self.config.gate_line_width.execute(&mut self.interface)?;
// Command::GateDrivingVoltage(0b10000 | 0b0001);
// Command::SourceDrivingVoltage(0x2D, 0xB2, 0x22).execute(&mut self.interface)?;
2018-11-27 21:10:16 +00:00
self.config.write_vcom.execute(&mut self.interface)?;
// POR is HiZ. Need pull from config
// Command::BorderWaveform(u8).execute(&mut self.interface)?;
2018-11-27 21:10:16 +00:00
if let Some(ref write_lut) = self.config.write_lut {
write_lut.execute(&mut self.interface)?;
}
2018-11-27 21:10:16 +00:00
self.config.data_entry_mode.execute(&mut self.interface)?;
2018-11-27 21:10:16 +00:00
let end = self.config.dimensions.cols / 8 - 1;
Command::StartEndXPosition(0, end).execute(&mut self.interface)?;
2018-11-27 21:10:16 +00:00
Command::StartEndYPosition(0, self.config.dimensions.rows).execute(&mut self.interface)?;
Ok(())
}
2018-12-26 01:54:30 +00:00
/// Update the display by writing the supplied B/W and Red buffers to the controller.
///
/// This method will write the two buffers to the controller then initiate the update
/// display command. Currently it will busy wait until the update has completed.
2018-12-25 21:43:04 +00:00
pub fn update<D: hal::blocking::delay::DelayMs<u8>>(
&mut self,
black: &[u8],
red: &[u8],
delay: &mut D,
) -> Result<(), I::Error> {
// Write the B/W RAM
2018-12-26 01:54:30 +00:00
let buf_limit = libm::ceilf((self.rows() * self.cols() as u16) as f32 / 8.) as usize;
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)?;
// 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)?;
// 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);
// 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
2018-12-25 21:29:03 +00:00
// the interface like a smart pointer in which deref would wait until it's not
// busy.
self.interface.busy_wait();
Ok(())
}
2018-12-26 01:54:30 +00:00
/// Enter deep sleep mode.
///
/// This puts the display controller into a low power mode. `reset` must be called to wake it
/// from sleep.
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 07:02:33 +00:00
2018-12-26 01:54:30 +00:00
/// Returns the number of rows the display has.
2018-11-14 07:02:33 +00:00
pub fn rows(&self) -> u16 {
2018-11-27 21:10:16 +00:00
self.config.dimensions.rows
2018-11-14 07:02:33 +00:00
}
2018-12-26 01:54:30 +00:00
/// Returns the number of columns the display has.
2018-11-14 07:02:33 +00:00
pub fn cols(&self) -> u8 {
2018-11-27 21:10:16 +00:00
self.config.dimensions.cols
2018-11-14 07:02:33 +00:00
}
2018-12-26 01:54:30 +00:00
/// Returns the rotation the display was configured with.
2018-11-14 07:02:33 +00:00
pub fn rotation(&self) -> Rotation {
2018-11-27 21:10:16 +00:00
self.config.rotation
2018-11-14 07:02:33 +00:00
}
}