Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add epd7in5b_v2 support #118

Merged
merged 4 commits into from
Oct 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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