Browse Source

Started some shared traits between the different epds, saving now

digi-v2-tests
Christoph Groß 5 years ago
parent
commit
ceee294cda
  1. 167
      src/epd2in9/command.rs
  2. 17
      src/epd2in9/constants.rs
  3. 102
      src/epd2in9/lut.rs
  4. 214
      src/epd2in9/mod.rs
  5. 142
      src/interface/data_interface.rs
  6. 105
      src/interface/mod.rs
  7. 6
      src/lib.rs

167
src/epd2in9/command.rs

@ -1,6 +1,6 @@
//! SPI Commands for the Waveshare 4.2" E-Ink Display
//! SPI Commands for the Waveshare 2.9" E-Ink Display
/// EPD4IN2 commands
/// EPD2IN9 commands
///
/// Should rarely (never?) be needed directly.
///
@ -10,138 +10,31 @@
#[allow(dead_code)]
#[allow(non_camel_case_types)]
#[derive(Copy, Clone)]
pub enum Command {
/// Set Resolution, LUT selection, BWR pixels, gate scan direction, source shift direction, booster switch, soft reset
PANEL_SETTING = 0x00,
/// selecting internal and external power
POWER_SETTING = 0x01,
/// After the Power Off command, the driver will power off following the Power Off Sequence. This command will turn off charge
/// pump, T-con, source driver, gate driver, VCOM, and temperature sensor, but register data will be kept until VDD becomes OFF.
/// Source Driver output and Vcom will remain as previous condition, which may have 2 conditions: floating.
POWER_OFF = 0x02,
/// Setting Power OFF sequence
POWER_OFF_SEQUENCE_SETTING = 0x03,
/// Turning On the Power
POWER_ON = 0x04,
/// This command enables the internal bandgap, which will be cleared by the next POF.
POWER_ON_MEASURE = 0x05,
/// Starting data transmission
BOOSTER_SOFT_START = 0x06,
/// After this command is transmitted, the chip would enter the deep-sleep mode to save power.
///
/// The deep sleep mode would return to standby by hardware reset.
///
/// The only one parameter is a check code, the command would be excuted if check code = 0xA5.
DEEP_SLEEP = 0x07,
/// This command starts transmitting data and write them into SRAM. To complete data transmission, command DSP (Data
/// transmission Stop) must be issued. Then the chip will start to send data/VCOM for panel.
///
/// - In B/W mode, this command writes “OLD” data to SRAM.
/// - In B/W/Red mode, this command writes “B/W” data to SRAM.
/// - In Program mode, this command writes “OTP” data to SRAM for programming.
DATA_START_TRANSMISSION_1 = 0x10,
/// Stopping data transmission
DATA_STOP = 0x11,
/// While user sent this command, driver will refresh display (data/VCOM) according to SRAM data and LUT.
///
/// After Display Refresh command, BUSY_N signal will become “0” and the refreshing of panel starts.
DISPLAY_REFRESH = 0x12,
/// This command starts transmitting data and write them into SRAM. To complete data transmission, command DSP (Data
/// transmission Stop) must be issued. Then the chip will start to send data/VCOM for panel.
/// - In B/W mode, this command writes “NEW” data to SRAM.
/// - In B/W/Red mode, this command writes “RED” data to SRAM.
DATA_START_TRANSMISSION_2 = 0x13,
/// This command stores VCOM Look-Up Table with 7 groups of data. Each group contains information for one state and is stored
/// with 6 bytes, while the sixth byte indicates how many times that phase will repeat.
///
/// from IL0373
LUT_FOR_VCOM = 0x20,
/// This command stores White-to-White Look-Up Table with 7 groups of data. Each group contains information for one state and is
/// stored with 6 bytes, while the sixth byte indicates how many times that phase will repeat.
///
/// from IL0373
LUT_WHITE_TO_WHITE = 0x21,
/// This command stores Black-to-White Look-Up Table with 7 groups of data. Each group contains information for one state and is
/// stored with 6 bytes, while the sixth byte indicates how many times that phase will repeat.
///
/// from IL0373
LUT_BLACK_TO_WHITE = 0x22,
/// This command stores White-to-Black Look-Up Table with 7 groups of data. Each group contains information for one state and is
/// stored with 6 bytes, while the sixth byte indicates how many times that phase will repeat.
///
/// from IL0373
LUT_WHITE_TO_BLACK = 0x23,
/// This command stores Black-to-Black Look-Up Table with 7 groups of data. Each group contains information for one state and is
/// stored with 6 bytes, while the sixth byte indicates how many times that phase will repeat.
///
/// from IL0373
LUT_BLACK_TO_BLACK = 0x24,
/// The command controls the PLL clock frequency.
PLL_CONTROL = 0x30,
/// This command reads the temperature sensed by the temperature sensor.
///
/// Doesn't work! Waveshare doesn't connect the read pin
TEMPERATURE_SENSOR_COMMAND = 0x40,
/// Selects the Internal or External temperature sensor and offset
TEMPERATURE_SENSOR_SELECTION = 0x41,
/// Write External Temperature Sensor
TEMPERATURE_SENSOR_WRITE = 0x42,
/// Read External Temperature Sensor
///
/// Doesn't work! Waveshare doesn't connect the read pin
TEMPERATURE_SENSOR_READ = 0x43,
/// This command indicates the interval of Vcom and data output. When setting the vertical back porch, the total blanking will be kept (20 Hsync)
VCOM_AND_DATA_INTERVAL_SETTING = 0x50,
/// This command indicates the input power condition. Host can read this flag to learn the battery condition.
LOW_POWER_DETECTION = 0x51,
/// This command defines non-overlap period of Gate and Source.
TCON_SETTING = 0x60,
/// This command defines alternative resolution and this setting is of higher priority than the RES[1:0] in R00H (PSR).
RESOLUTION_SETTING = 0x61,
/// This command defines the Fist Active Gate and First Active Source of active channels.
GSST_SETTING = 0x65,
/// The LUT_REV / Chip Revision is read from OTP address = 0x001.
///
/// Doesn't work! Waveshare doesn't connect the read pin
REVISION = 0x70,
/// Read Flags. This command reads the IC status
/// PTL, I2C_ERR, I2C_BUSY, DATA, PON, POF, BUSY
///
/// Doesn't work! Waveshare doesn't connect the read pin
GET_STATUS = 0x71,
/// Automatically measure VCOM. This command reads the IC status
AUTO_MEASUREMENT_VCOM = 0x80,
/// This command gets the VCOM value
///
/// Doesn't work! Waveshare doesn't connect the read pin
READ_VCOM_VALUE = 0x81,
/// Set VCM_DC
VCM_DC_SETTING = 0x82,
/// This command sets partial window
PARTIAL_WINDOW = 0x90,
/// This command makes the display enter partial mode
PARTIAL_IN = 0x91,
/// This command makes the display exit partial mode and enter normal mode
PARTIAL_OUT = 0x92,
/// After this command is issued, the chip would enter the program mode.
///
/// After the programming procedure completed, a hardware reset is necessary for leaving program mode.
///
/// The only one parameter is a check code, the command would be excuted if check code = 0xA5.
PROGRAM_MODE = 0xA0,
/// After this command is transmitted, the programming state machine would be activated.
///
/// The BUSY flag would fall to 0 until the programming is completed.
ACTIVE_PROGRAMMING = 0xA1,
/// The command is used for reading the content of OTP for checking the data of programming.
///
/// The value of (n) is depending on the amount of programmed data, tha max address = 0xFFF.
READ_OTP = 0xA2,
/// This command is set for saving power during fresh period. If the output voltage of VCOM / Source is from negative to positive or
/// from positive to negative, the power saving mechanism will be activated. The active period width is defined by the following two
/// parameters.
POWER_SAVING = 0xE3,
pub(crate) enum Command {
/// Driver Output control
/// 3 Databytes:
/// A[7:0]
/// 0.. A[8]
/// 0.. B[2:0]
/// Default: Set A[8:0] = 0x127 and B[2:0] = 0x0
DRIVER_OUTPUT_CONTROL = 0x01,
/// Booster Soft start control
/// 3 Databytes:
/// 1.. A[6:0]
/// 1.. B[6:0]
/// 1.. C[6:0]
/// Default: A[7:0] = 0xCF, B[7:0] = 0xCE, C[7:0] = 0x8D
BOOSTER_SOFT_START_CONTROL = 0x0C,
//TODO: useful?
// GATE_SCAN_START_POSITION = 0x0F,
/// Deep Sleep Mode Control
/// 1 Databyte:
/// 0.. A[0]
/// Values:
/// A[0] = 0: Normal Mode (POR)
/// A[0] = 1: Enter Deep Sleep Mode
DEEP_SLEEP_MODE = 0x10,
// /// Data Entry mode setting
}
@ -160,10 +53,10 @@ mod tests {
#[test]
fn command_addr() {
assert_eq!(Command::POWER_SAVING.addr(), 0xE3);
//assert_eq!(Command::POWER_SAVING.addr(), 0xE3);
assert_eq!(Command::PANEL_SETTING.addr(), 0x00);
//assert_eq!(Command::PANEL_SETTING.addr(), 0x00);
assert_eq!(Command::DISPLAY_REFRESH.addr(), 0x12);
//assert_eq!(Command::DISPLAY_REFRESH.addr(), 0x12);
}
}

17
src/epd2in9/constants.rs

@ -0,0 +1,17 @@
pub(crate) const WIDTH: usize = 128;
pub(crate) const HEIGHT: usize = 296;
// Original Waveforms from Waveshare
pub(crate) const LUT_FULL_UPDATE: [u8; 30] =[
0x02, 0x02, 0x01, 0x11, 0x12, 0x12, 0x22, 0x22,
0x66, 0x69, 0x69, 0x59, 0x58, 0x99, 0x99, 0x88,
0x00, 0x00, 0x00, 0x00, 0xF8, 0xB4, 0x13, 0x51,
0x35, 0x51, 0x51, 0x19, 0x01, 0x00
];
pub(crate) const LUT_PARTIAL_UPDATE: [u8; 30] =[
0x10, 0x18, 0x18, 0x08, 0x18, 0x18, 0x08, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x13, 0x14, 0x44, 0x12,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
];

102
src/epd2in9/lut.rs

@ -1,102 +0,0 @@
pub(crate) const LUT_VCOM0: [u8; 44] = [
0x00, 0x17, 0x00, 0x00, 0x00, 0x02,
0x00, 0x17, 0x17, 0x00, 0x00, 0x02,
0x00, 0x0A, 0x01, 0x00, 0x00, 0x01,
0x00, 0x0E, 0x0E, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
pub(crate) const LUT_VCOM0_QUICK: [u8; 44] = [
0x00, 0x0E, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
pub(crate) const LUT_WW: [u8; 42] =[
0x40, 0x17, 0x00, 0x00, 0x00, 0x02,
0x90, 0x17, 0x17, 0x00, 0x00, 0x02,
0x40, 0x0A, 0x01, 0x00, 0x00, 0x01,
0xA0, 0x0E, 0x0E, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
pub(crate) const LUT_WW_QUICK: [u8; 42] =[
0xA0, 0x0E, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
pub(crate) const LUT_BW: [u8; 42] =[
0x40, 0x17, 0x00, 0x00, 0x00, 0x02,
0x90, 0x17, 0x17, 0x00, 0x00, 0x02,
0x40, 0x0A, 0x01, 0x00, 0x00, 0x01,
0xA0, 0x0E, 0x0E, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
pub(crate) const LUT_BW_QUICK: [u8; 42] =[
0xA0, 0x0E, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
pub(crate) const LUT_BB: [u8; 42] =[
0x80, 0x17, 0x00, 0x00, 0x00, 0x02,
0x90, 0x17, 0x17, 0x00, 0x00, 0x02,
0x80, 0x0A, 0x01, 0x00, 0x00, 0x01,
0x50, 0x0E, 0x0E, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
pub(crate) const LUT_BB_QUICK: [u8; 42] =[
0x50, 0x0E, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
pub(crate) const LUT_WB: [u8; 42] =[
0x80, 0x17, 0x00, 0x00, 0x00, 0x02,
0x90, 0x17, 0x17, 0x00, 0x00, 0x02,
0x80, 0x0A, 0x01, 0x00, 0x00, 0x01,
0x50, 0x0E, 0x0E, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
pub(crate) const LUT_WB_QUICK: [u8; 42] =[
0x50, 0x0E, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];

214
src/epd2in9/mod.rs

@ -57,54 +57,108 @@ use hal::{
digital::*
};
//The Lookup Tables for the Display
mod lut;
use self::lut::*;
mod constants;
use self::constants::*;
use drawing::color::Color;
pub mod command;
pub use command::Command as Command;
//TODO: test spi mode
/// SPI mode -
/// For more infos see [Requirements: SPI](index.html#spi)
pub const SPI_MODE: Mode = Mode {
phase: Phase::CaptureOnFirstTransition,
polarity: Polarity::IdleLow,
};
use interface::*;
use interface::data_interface::DataInterface;
/// EPD4in2 driver
///
pub struct EPD2in9<SPI, CS, BUSY, DC, RST, D> {
/// SPI
interface: DataInterface<SPI, CS, BUSY, DC, RST, D>,
/// Width
width: u32,
/// Height
height: u32,
}
impl<SPI, CS, BUSY, DC, RST, D, E> EPD2in9<SPI, CS, BUSY, DC, RST, D>
where
SPI: Write<u8, Error = E>,
CS: OutputPin,
BUSY: InputPin,
DC: OutputPin,
RST: OutputPin,
D: DelayUs<u16> + DelayMs<u16>
{
}
impl<SPI, CS, BUSY, DC, RST, D, E> WaveshareInterface<SPI, CS, BUSY, DC, RST, D, E> for EPD2in9<SPI, CS, BUSY, DC, RST, D>
where
SPI: Write<u8, Error = E>,
CS: OutputPin,
BUSY: InputPin,
DC: OutputPin,
RST: OutputPin,
D: DelayUs<u16> + DelayMs<u16>,
{
fn get_width(&self) -> u32 {
self.width
}
fn get_height(&self) -> u32 {
self.height
}
fn new(
spi: SPI,
cs: CS,
busy: BUSY,
dc: DC,
rst: RST,
delay: D
) -> Result<Self, E> {
let width = WIDTH as u32;
let height = HEIGHT as u32;
let mut interface = DataInterface::new(spi, cs, busy, dc, rst, delay);
let mut epd = EPD2in9 {interface, width, height};
epd.init()?;
Ok(epd)
}
fn init(&mut self) -> Result<(), E> {
//TODO:
Ok(())
}
fn sleep(&mut self) -> Result<(), E> {
Ok(())
}
fn reset(&mut self) {
//TODO:
}
fn wait_until_idle(&mut self) {
}
fn delay_ms(&mut self, delay: u32) {
}
/// EPD4in2 driver
///
pub struct EPD4in2<SPI, CS, BUSY, DC, RST, D> {
/// SPI
spi: SPI,
/// CS for SPI
cs: CS,
/// Low for busy, Wait until display is ready!
busy: BUSY,
/// Data/Command Control Pin (High for data, Low for command)
dc: DC,
/// Pin for Reseting
rst: RST,
/// The concrete Delay implementation
delay: D,
/// Width
width: u16,
/// Height
height: u16,
}
impl<SPI, CS, BUSY, DC, RST, D, E> EPD4in2<SPI, CS, BUSY, DC, RST, D>
/*
impl<SPI, CS, BUSY, DC, RST, D, E> EPD2in9<SPI, CS, BUSY, DC, RST, D>
where
SPI: Write<u8, Error = E>,
CS: OutputPin,
@ -141,8 +195,8 @@ where
/// ```
pub fn new(spi: SPI, cs: CS, busy: BUSY, dc: DC, rst: RST, delay: D) -> Result<Self, E> {
//TODO: width und height anpassbar machen?
let width = 400;
let height = 300;
let width = WIDTH as u16;
let height = HEIGHT as u16;
let mut epd4in2 = EPD4in2 {spi, cs, busy, dc, rst, delay, width, height };
@ -390,22 +444,7 @@ where
Ok(())
}
/// Resets the device.
///
/// Often used to awake the module from deep sleep. See [EPD4in2::sleep()](EPD4in2::sleep())
///
/// TODO: Takes at least 400ms of delay alone, can it be shortened?
pub fn reset(&mut self) {
self.rst.set_low();
//TODO: why 200ms? (besides being in the waveshare code)
self.delay_ms(200);
self.rst.set_high();
//TODO: same as 3 lines above
self.delay_ms(200);
}
@ -463,89 +502,12 @@ where
Ok(())
}
/// Basic function for sending [Commands](Command).
///
/// Enables direct interaction with the device with the help of [EPD4in2::send_data()](EPD4in2::send_data())
/// Should rarely be needed!
/// //TODO: make public?
fn send_command(&mut self, command: Command) -> Result<(), E> {
// low for commands
self.dc.set_low();
// Transfer the command over spi
self.with_cs(|epd| {
epd.spi.write(&[command.addr()])
})
}
/// Basic function for sending a single u8 of data over spi
///
/// Enables direct interaction with the device with the help of [EPD4in2::send_command()](EPD4in2::send_command())
///
/// Should rarely be needed!
/// //TODO: make public?
fn send_data(&mut self, val: u8) -> Result<(), E> {
// high for data
self.dc.set_high();
// Transfer data (u8) over spi
self.with_cs(|epd| {
epd.spi.write(&[val])
})
}
/// Basic function for sending an array of u8-values of data over spi
///
/// Enables direct interaction with the device with the help of [EPD4in2::send_command()](EPD4in2::send_command())
///
/// Should rarely be needed!
/// //TODO: make public?
fn send_multiple_data(&mut self, data: &[u8]) -> Result<(), E> {
// high for data
self.dc.set_high();
// Transfer data (u8-array) over spi
self.with_cs(|epd| {
epd.spi.write(data)
})
}
// spi write helper/abstraction function
fn with_cs<F>(&mut self, f: F) -> Result<(), E>
where
F: FnOnce(&mut Self) -> Result<(), E>,
{
// activate spi with cs low
self.cs.set_low();
// transfer spi data
let result = f(self);
// deativate spi with cs high
self.cs.set_high();
// return result
result
}
/// Waits until device isn't busy anymore (busy == HIGH)
///
/// This is normally handled by the more complicated commands themselves,
/// but in the case you send data and commands directly you might need to check
/// if the device is still busy
pub fn wait_until_idle(&mut self) {
//low: busy, high: idle
while self.busy.is_low() {
//TODO: shorten the time? it was 100 in the beginning
self.delay_ms(10);
}
}
}
/// Abstraction of setting the delay for simpler calls
pub fn delay_ms(&mut self, delay: u16) {
self.delay.delay_ms(delay);
}
}
*/

142
src/interface/data_interface.rs

@ -0,0 +1,142 @@
use hal::{
blocking::{
spi::Write,
delay::*
},
spi::{Mode, Phase, Polarity},
digital::*
};
use interface::Command;
/// EPD4in2 driver
///
pub struct DataInterface<SPI, CS, BUSY, DC, RST, D> {
/// SPI
spi: SPI,
/// CS for SPI
cs: CS,
/// Low for busy, Wait until display is ready!
busy: BUSY,
/// Data/Command Control Pin (High for data, Low for command)
dc: DC,
/// Pin for Reseting
rst: RST,
/// The concrete Delay implementation
delay: D,
}
impl<SPI, CS, BUSY, DC, RST, D, E> DataInterface<SPI, CS, BUSY, DC, RST, D>
where
SPI: Write<u8, Error = E>,
CS: OutputPin,
BUSY: InputPin,
DC: OutputPin,
RST: OutputPin,
D: DelayUs<u16> + DelayMs<u16>,
{
pub fn new(spi: SPI, cs: CS, busy: BUSY, dc: DC, rst: RST, delay: D) -> Self {
DataInterface {spi, cs, busy, dc, rst, delay }
}
/// Basic function for sending [Commands](Command).
///
/// Enables direct interaction with the device with the help of [EPD4in2::send_data()](EPD4in2::send_data())
/// Should rarely be needed!
/// //TODO: make public?
fn send_command<T: Command>(&mut self, command: T) -> Result<(), E> {
// low for commands
self.dc.set_low();
// Transfer the command over spi
self.with_cs(|epd| {
epd.spi.write(&[command.address()])
})
}
/// Basic function for sending a single u8 of data over spi
///
/// Enables direct interaction with the device with the help of [EPD4in2::send_command()](EPD4in2::send_command())
///
/// Should rarely be needed!
/// //TODO: make public?
fn send_data(&mut self, val: u8) -> Result<(), E> {
// high for data
self.dc.set_high();
// Transfer data (u8) over spi
self.with_cs(|epd| {
epd.spi.write(&[val])
})
}
/// Basic function for sending an array of u8-values of data over spi
///
/// Enables direct interaction with the device with the help of [EPD4in2::send_command()](EPD4in2::send_command())
///
/// Should rarely be needed!
/// //TODO: make public?
fn send_multiple_data(&mut self, data: &[u8]) -> Result<(), E> {
// high for data
self.dc.set_high();
// Transfer data (u8-array) over spi
self.with_cs(|epd| {
epd.spi.write(data)
})
}
// spi write helper/abstraction function
fn with_cs<F>(&mut self, f: F) -> Result<(), E>
where
F: FnOnce(&mut Self) -> Result<(), E>,
{
// activate spi with cs low
self.cs.set_low();
// transfer spi data
let result = f(self);
// deativate spi with cs high
self.cs.set_high();
// return result
result
}
/// Waits until device isn't busy anymore (busy == HIGH)
///
/// This is normally handled by the more complicated commands themselves,
/// but in the case you send data and commands directly you might need to check
/// if the device is still busy
pub fn wait_until_idle(&mut self) {
//low: busy, high: idle
while self.busy.is_low() {
//TODO: shorten the time? it was 100 in the beginning
self.delay_ms(10);
}
}
/// Abstraction of setting the delay for simpler calls
pub fn delay_ms(&mut self, delay: u16) {
self.delay.delay_ms(delay);
}
/// Resets the device.
///
/// Often used to awake the module from deep sleep. See [EPD4in2::sleep()](EPD4in2::sleep())
///
/// TODO: Takes at least 400ms of delay alone, can it be shortened?
pub fn reset(&mut self) {
self.rst.set_low();
//TODO: why 200ms? (besides being in the waveshare code)
self.delay_ms(200);
self.rst.set_high();
//TODO: same as 3 lines above
self.delay_ms(200);
}
}

105
src/interface/mod.rs

@ -0,0 +1,105 @@
use hal::{
blocking::{
spi::Write,
delay::*
},
spi::{Mode, Phase, Polarity},
digital::*
};
pub mod data_interface;
//TODO: test spi mode
/// SPI mode -
/// For more infos see [Requirements: SPI](index.html#spi)
pub const SPI_MODE: Mode = Mode {
phase: Phase::CaptureOnFirstTransition,
polarity: Polarity::IdleLow,
};
use core::marker::Sized;
pub(crate) trait Command {
fn address(&self) -> u8;
}
pub trait WaveshareInterface<SPI, CS, BUSY, DC, RST, D, E>
where
SPI: Write<u8, Error = E>,
CS: OutputPin,
BUSY: InputPin,
DC: OutputPin,
RST: OutputPin,
D: DelayUs<u16> + DelayMs<u16>,
{
/// Get the width of the display
fn get_width(&self) -> u32;
fn get_height(&self) -> u32;
fn new(
spi: SPI,
cs: CS,
busy: BUSY,
dc: DC,
rst: RST,
delay: D
) -> Result<Self, E>
where Self: Sized;
fn init(&mut self) -> Result<(), E>;
fn sleep(&mut self) -> Result<(), E>;
fn reset(&mut self);
fn wait_until_idle(&mut self);
fn delay_ms(&mut self, delay: u32);
/*
fn clear_frame(&mut self, reset_color: Option<Color>) -> Result<(), E>
fn display_frame_quick(&mut self) -> Result<(), E>
fn display_frame(&mut self) -> Result<(), E>
pub fn display_and_transfer_frame(
&mut self,
buffer: &[u8],
color: Option<u8>
) -> Result<(), E>
pub fn set_partial_window(
&mut self,
buffer: &[u8],
x: u16,
y: u16,
w: u16,
l: u16,
is_dtm1: bool
) -> Result<(), E>
*/
}
pub trait TestInterface
{
fn get_width(&self) -> u32;
fn get_height(&self) -> u32;
}
struct testStruct {
width: u32,
height: u32,
}
impl TestInterface for testStruct {
fn get_width(&self) -> u32 {
self.width
}
fn get_height(&self) -> u32 {
self.height
}
}

6
src/lib.rs

@ -60,6 +60,12 @@ pub mod drawing;
pub mod epd4in2;
use epd4in2::*;
pub mod epd2in9;
pub mod interface;
//TODO: test spi mode
/// SPI mode -
/// For more infos see [Requirements: SPI](index.html#spi)

Loading…
Cancel
Save