Skip to content

Commit

Permalink
Merge pull request #118 from peckpeck/epd7in5b_v2
Browse files Browse the repository at this point in the history
Add epd7in5b_v2 and v3 support thanks to @peckpeck
  • Loading branch information
caemor authored Oct 21, 2022
2 parents e36c134 + 716b84a commit b909be6
Show file tree
Hide file tree
Showing 7 changed files with 636 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

- Added support for positive and negatives modes of rendering in TriColor display in #92 (thanks to @akashihi)
- Added Epd 5in83 V2 (B) support in #92 (thanks to @akashihi)
- Added Epd 7in5 (B) V2 and V3 support

### Changed

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,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/R V2/V3 (B)](https://www.waveshare.com/product/displays/e-paper/epaper-1/7.5inch-e-paper-b.htm) | Black, White, Red |||||
| [7.5 Inch B/W HD (A)](https://www.waveshare.com/product/displays/e-paper/epaper-1/7.5inch-hd-e-paper-hat.htm) | Black, White |||||
| [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 (A)](https://www.waveshare.com/product/7.5inch-e-paper-hat.htm) | Black, White |||||
Expand Down
6 changes: 3 additions & 3 deletions src/color.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ impl OutOfColorRangeParseError {
}

/// Only for the Black/White-Displays
#[derive(Clone, Copy, PartialEq, Debug)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Color {
/// Black color
Black,
Expand All @@ -35,7 +35,7 @@ pub enum Color {
}

/// Only for the Black/White/Color-Displays
#[derive(Clone, Copy, PartialEq, Debug)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum TriColor {
/// Black color
Black,
Expand All @@ -46,7 +46,7 @@ pub enum TriColor {
}

/// For the 5in65 7 Color Display
#[derive(Clone, Copy, PartialEq, Debug)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum OctColor {
/// Black Color
Black = 0x00,
Expand Down
156 changes: 156 additions & 0 deletions src/epd7in5b_v2/command.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
//! SPI Commands for the Waveshare 7.5"(B) V2 and V3 -Ink Display
use crate::traits;

/// Epd7in5 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)]
#[derive(Copy, Clone)]
pub(crate) enum Command {
/// Set Resolution, LUT selection, BWR pixels, gate scan direction, source shift
/// direction, booster switch, soft reset.
PanelSetting = 0x00,

/// Selecting internal and external power
PowerSetting = 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.
PowerOff = 0x02,

/// Setting Power OFF sequence
PowerOffSequenceSetting = 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".
PowerOn = 0x04,

/// Starting data transmission
BoosterSoftStart = 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.
DeepSleep = 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.
///
/// BLACK/WHITE or OLD_DATA
DataStartTransmission1 = 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.
DataStop = 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.
DisplayRefresh = 0x12,

/// RED or NEW_DATA
DataStartTransmission2 = 0x13,

/// Dual SPI - what for?
DualSpi = 0x15,

/// This command builds the VCOM Look-Up Table (LUTC).
LutC = 0x20,
/// This command builds the Black Look-Up Table (LUTB).
LutWW = 0x21,
/// This command builds the White Look-Up Table (LUTW).
LutBW = 0x22,
/// This command builds the Gray1 Look-Up Table (LUTG1).
LutWB = 0x23,
/// This command builds the Gray2 Look-Up Table (LUTG2).
LutBB = 0x24,
/// This command builds the Red0 Look-Up Table (LUTR0).
LutBD = 0x25,

/// LUT Option
LutOpt = 0x2A,
/// KW LUT Option
KWLutOpt = 0x2B,

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

/// This command reads the temperature sensed by the temperature sensor.
TemperatureSensor = 0x40,
/// This command selects the Internal or External temperature sensor.
TemperatureCalibration = 0x41,
/// This command could write data to the external temperature sensor.
TemperatureSensorWrite = 0x42,
/// This command could read data from the external temperature sensor.
TemperatureSensorRead = 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).
VcomAndDataIntervalSetting = 0x50,
/// This command indicates the input power condition. Host can read this flag to learn
/// the battery condition.
LowPowerDetection = 0x51,

/// This command defines non-overlap period of Gate and Source.
TconSetting = 0x60,
/// This command defines alternative resolution and this setting is of higher priority
/// than the RES\[1:0\] in R00H (PSR).
TconResolution = 0x61,
/// This command defines MCU host direct access external memory mode.
SpiFlashControl = 0x65,

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

/// This command implements related VCOM sensing setting.
AutoMeasurementVcom = 0x80,
/// This command gets the VCOM value.
ReadVcomValue = 0x81,
/// This command sets `VCOM_DC` value.
VcmDcSetting = 0x82,
// /// This is in all the Waveshare controllers for Epd7in5, but it's not documented
// /// anywhere in the datasheet `¯\_(ツ)_/¯`
// FlashMode = 0xE5,
/// Sets window size for the partial update
PartialWindow = 0x90,
/// Sets chip into partial update mode
PartialIn = 0x91,
/// Quits partial update mode
PartialOut = 0x92,
}

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::PanelSetting.address(), 0x00);
assert_eq!(Command::DisplayRefresh.address(), 0x12);
}
}
131 changes: 131 additions & 0 deletions src/epd7in5b_v2/graphics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
use crate::color::TriColor;
use crate::epd7in5b_v2::{DEFAULT_BACKGROUND_COLOR, HEIGHT, NUM_DISPLAY_BYTES, WIDTH};
use crate::graphics::{DisplayRotation, TriDisplay};
use embedded_graphics_core::prelude::*;

/// Full size buffer for use with the 7in5 EPD
///
/// Can also be manually constructed:
/// `buffer: [DEFAULT_BACKGROUND_COLOR.get_byte_value(); 2 * NUM_DISPLAY_BYTES]`
pub struct Display7in5 {
buffer: [u8; 2 * NUM_DISPLAY_BYTES],
rotation: DisplayRotation,
}

impl Default for Display7in5 {
// inline is necessary here to allow heap allocation via Box on stack limited programs
#[inline(always)]
fn default() -> Self {
Display7in5 {
// This way of initializing doesn't work for bicolor buffer
buffer: [DEFAULT_BACKGROUND_COLOR.get_byte_value(); 2 * NUM_DISPLAY_BYTES],
rotation: DisplayRotation::default(),
}
}
}

impl Display7in5 {
/// Please call me after creating a default Display7in5 for bicolor display, otherwise
/// the default color won't be correct
pub fn init(&mut self) {
match DEFAULT_BACKGROUND_COLOR {
// white and chromatic are both 1
TriColor::White => self.buffer[NUM_DISPLAY_BYTES..].fill(0x00),
TriColor::Black => {}
TriColor::Chromatic => self.buffer[NUM_DISPLAY_BYTES..].fill(0xFF),
}
}
}

impl DrawTarget for Display7in5 {
type Color = TriColor;
type Error = core::convert::Infallible;

fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
where
I: IntoIterator<Item = Pixel<Self::Color>>,
{
for pixel in pixels {
self.draw_helper_tri(
WIDTH,
HEIGHT,
pixel,
crate::graphics::DisplayColorRendering::Negative,
)?;
}
Ok(())
}
}

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

impl TriDisplay for Display7in5 {
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
}

fn chromatic_offset(&self) -> usize {
NUM_DISPLAY_BYTES
}

fn bw_buffer(&self) -> &[u8] {
&self.buffer[0..self.chromatic_offset()]
}

fn chromatic_buffer(&self) -> &[u8] {
&self.buffer[self.chromatic_offset()..]
}

fn clear_buffer(&mut self, background_color: TriColor) {
let offset = self.chromatic_offset();

for (i, elem) in self.get_mut_buffer().iter_mut().enumerate() {
if i < offset {
*elem = background_color.get_byte_value();
}
// for V3, white in the BW buffer is 255. But in the chromatic buffer 255 is red.
// This means that the chromatic buffer needs to be inverted when clearing
else {
*elem = background_color.get_byte_value() ^ 0xFF;
}
}
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::epd7in5_v3;

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

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

0 comments on commit b909be6

Please sign in to comment.