Skip to content

Commit

Permalink
Add 7in5bc support, caemor#26
Browse files Browse the repository at this point in the history
  • Loading branch information
marcelbuesing committed Apr 14, 2020
1 parent 22f16ea commit 8835664
Show file tree
Hide file tree
Showing 5 changed files with 732 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ epd.update_and_display_frame(&mut spi, &display.buffer())?;
| Device (with Link) | Colors | Flexible Display | Partial Refresh | Supported | Tested |
| :---: | --- | :---: | :---: | :---: | :---: |
| [7.5 Inch B/W V2 (A)](https://www.waveshare.com/product/7.5inch-e-paper-hat.htm) [[1](#1-75-inch-bw-v2-a)] | Black, White |||||
| [7.5 Inch B/W/R (B/C)](https://www.waveshare.com/7.5inch-e-Paper-HAT-B.htm) | Black, White, Red |||||
| [7.5 Inch B/W (A)](https://www.waveshare.com/product/7.5inch-e-paper-hat.htm) | Black, White |||||
| [4.2 Inch B/W (A)](https://www.waveshare.com/product/4.2inch-e-paper-module.htm) | Black, White || Not officially [[2](#2-42-inch-e-ink-blackwhite---partial-refresh)] |||
| [1.54 Inch B/W (A)](https://www.waveshare.com/1.54inch-e-Paper-Module.htm) | Black, White |||||
Expand Down
154 changes: 154 additions & 0 deletions src/epd7in5bc/command.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
//! SPI Commands for the Waveshare 7.5" E-Ink Display
use crate::traits;

/// EPD7in5b commands
///
/// Should rarely (never?) be needed directly.
///
/// For more infos about the addresses and what they are doing look into the PDFs.
#[allow(dead_code)]
#[allow(non_camel_case_types)]
#[derive(Copy, Clone)]
pub(crate) 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; BUSY signal will become "0". 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: 0V or floating.
POWER_OFF = 0x02,

/// Setting Power OFF sequence
POWER_OFF_SEQUENCE_SETTING = 0x03,

/// Turning On the Power
///
/// After the Power ON command, the driver will power on following the Power ON
/// sequence. Once complete, the BUSY signal will become "1".
POWER_ON = 0x04,

/// Starting data transmission
BOOSTER_SOFT_START = 0x06,

/// This command makes the chip enter the deep-sleep mode to save power.
///
/// The deep sleep mode would return to stand-by 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 Stop) must be issued. Then the chip will start to
/// send data/VCOM for panel.
DATA_START_TRANSMISSION_1 = 0x10,

/// To stop data transmission, this command must be issued to check the `data_flag`.
///
/// After this command, BUSY signal will become "0" until the display update is
/// finished.
DATA_STOP = 0x11,

/// After this command is issued, driver will refresh display (data/VCOM) according to
/// SRAM data and LUT.
///
/// After Display Refresh command, BUSY signal will become "0" until the display
/// update is finished.
DISPLAY_REFRESH = 0x12,

/// After this command is issued, image process engine will find thin lines/pixels
/// from frame SRAM and update the frame SRAM for applying new gray level waveform.
///
/// After "Image Process Command", BUSY_N signal will become "0" until image process
/// is finished.
IMAGE_PROCESS = 0x13,

/// This command builds the VCOM Look-Up Table (LUTC).
LUT_FOR_VCOM = 0x20,
/// This command builds the Black Look-Up Table (LUTB).
LUT_BLACK = 0x21,
/// This command builds the White Look-Up Table (LUTW).
LUT_WHITE = 0x22,
/// This command builds the Gray1 Look-Up Table (LUTG1).
LUT_GRAY_1 = 0x23,
/// This command builds the Gray2 Look-Up Table (LUTG2).
LUT_GRAY_2 = 0x24,
/// This command builds the Red0 Look-Up Table (LUTR0).
LUT_RED_0 = 0x25,
/// This command builds the Red1 Look-Up Table (LUTR1).
LUT_RED_1 = 0x26,
/// This command builds the Red2 Look-Up Table (LUTR2).
LUT_RED_2 = 0x27,
/// This command builds the Red3 Look-Up Table (LUTR3).
LUT_RED_3 = 0x28,
/// This command builds the XON Look-Up Table (LUTXON).
LUT_XON = 0x29,

/// The command controls the PLL clock frequency.
PLL_CONTROL = 0x30,

/// This command reads the temperature sensed by the temperature sensor.
TEMPERATURE_SENSOR_COMMAND = 0x40,
/// This command selects the Internal or External temperature sensor.
TEMPERATURE_CALIBRATION = 0x41,
/// This command could write data to the external temperature sensor.
TEMPERATURE_SENSOR_WRITE = 0x42,
/// This command could read data from the external temperature sensor.
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).
TCON_RESOLUTION = 0x61,
/// This command defines MCU host direct access external memory mode.
SPI_FLASH_CONTROL = 0x65,

/// The LUT_REV / Chip Revision is read from OTP address = 25001 and 25000.
REVISION = 0x70,
/// This command reads the IC status.
GET_STATUS = 0x71,

/// This command implements related VCOM sensing setting.
AUTO_MEASUREMENT_VCOM = 0x80,
/// This command gets the VCOM value.
READ_VCOM_VALUE = 0x81,
/// This command sets `VCOM_DC` value.
VCM_DC_SETTING = 0x82,

/// This is in all the Waveshare controllers for EPD7in5, but it's not documented
/// anywhere in the datasheet `¯\_(ツ)_/¯`
FLASH_MODE = 0xE5,
}

impl traits::Command for Command {
/// Returns the address of the command
fn address(self) -> u8 {
self as u8
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::traits::Command as CommandTrait;

#[test]
fn command_addr() {
assert_eq!(Command::PANEL_SETTING.address(), 0x00);
assert_eq!(Command::DISPLAY_REFRESH.address(), 0x12);
}
}
146 changes: 146 additions & 0 deletions src/epd7in5bc/graphics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
use crate::epd7in5::{DEFAULT_BACKGROUND_COLOR, HEIGHT, WIDTH};
use crate::graphics::{Display, DisplayRotation};
use embedded_graphics::pixelcolor::BinaryColor;
use embedded_graphics::prelude::*;

/// Full size buffer for use with the 7in5 EPD
///
/// Can also be manually constructed:
/// `buffer: [DEFAULT_BACKGROUND_COLOR.get_byte_value(); WIDTH / 8 * HEIGHT]`
pub struct Display7in5bc {
buffer: [u8; WIDTH as usize * HEIGHT as usize / 8],
rotation: DisplayRotation,
}

impl Default for Display7in5bc {
fn default() -> Self {
Display7in5bc {
buffer: [DEFAULT_BACKGROUND_COLOR.get_byte_value();
WIDTH as usize * HEIGHT as usize / 8],
rotation: DisplayRotation::default(),
}
}
}

impl DrawTarget<BinaryColor> for Display7in5bc {
type Error = core::convert::Infallible;

fn draw_pixel(&mut self, pixel: Pixel<BinaryColor>) -> Result<(), Self::Error> {
self.draw_helper(WIDTH, HEIGHT, pixel)
}

fn size(&self) -> Size {
Size::new(WIDTH, HEIGHT)
}
}

impl Display for Display7in5bc {
fn buffer(&self) -> &[u8] {
&self.buffer
}

fn get_mut_buffer(&mut self) -> &mut [u8] {
&mut self.buffer
}

fn set_rotation(&mut self, rotation: DisplayRotation) {
self.rotation = rotation;
}

fn rotation(&self) -> DisplayRotation {
self.rotation
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::color::Black;
use crate::color::Color;
use crate::epd7in5;
use crate::graphics::{Display, DisplayRotation};
use embedded_graphics::{primitives::Line, style::PrimitiveStyle};

// test buffer length
#[test]
fn graphics_size() {
let display = Display7in5bc::default();
assert_eq!(display.buffer().len(), 30720);
}

// test default background color on all bytes
#[test]
fn graphics_default() {
let display = Display7in5bc::default();
for &byte in display.buffer() {
assert_eq!(byte, epd7in5::DEFAULT_BACKGROUND_COLOR.get_byte_value());
}
}

#[test]
fn graphics_rotation_0() {
let mut display = Display7in5bc::default();
let _ = Line::new(Point::new(0, 0), Point::new(7, 0))
.into_styled(PrimitiveStyle::with_stroke(Black, 1))
.draw(&mut display);

let buffer = display.buffer();

assert_eq!(buffer[0], Color::Black.get_byte_value());

for &byte in buffer.iter().skip(1) {
assert_eq!(byte, epd7in5::DEFAULT_BACKGROUND_COLOR.get_byte_value());
}
}

#[test]
fn graphics_rotation_90() {
let mut display = Display7in5bc::default();
display.set_rotation(DisplayRotation::Rotate90);
let _ = Line::new(Point::new(0, 632), Point::new(0, 639))
.into_styled(PrimitiveStyle::with_stroke(Black, 1))
.draw(&mut display);

let buffer = display.buffer();

assert_eq!(buffer[0], Color::Black.get_byte_value());

for &byte in buffer.iter().skip(1) {
assert_eq!(byte, epd7in5::DEFAULT_BACKGROUND_COLOR.get_byte_value());
}
}

#[test]
fn graphics_rotation_180() {
let mut display = Display7in5bc::default();
display.set_rotation(DisplayRotation::Rotate180);
let _ = Line::new(Point::new(632, 383), Point::new(639, 383))
.into_styled(PrimitiveStyle::with_stroke(Black, 1))
.draw(&mut display);

let buffer = display.buffer();

assert_eq!(buffer[0], Color::Black.get_byte_value());

for &byte in buffer.iter().skip(1) {
assert_eq!(byte, epd7in5::DEFAULT_BACKGROUND_COLOR.get_byte_value());
}
}

#[test]
fn graphics_rotation_270() {
let mut display = Display7in5bc::default();
display.set_rotation(DisplayRotation::Rotate270);
let _ = Line::new(Point::new(383, 0), Point::new(383, 7))
.into_styled(PrimitiveStyle::with_stroke(Black, 1))
.draw(&mut display);

let buffer = display.buffer();

assert_eq!(buffer[0], Color::Black.get_byte_value());

for &byte in buffer.iter().skip(1) {
assert_eq!(byte, epd7in5::DEFAULT_BACKGROUND_COLOR.get_byte_value());
}
}
}
Loading

0 comments on commit 8835664

Please sign in to comment.