Skip to content

Commit

Permalink
Update 7in5 V3 implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
CyanBlob committed May 19, 2022
1 parent 9c88a84 commit a234f05
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 249 deletions.
42 changes: 7 additions & 35 deletions src/epd7in5_v2/graphics.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use crate::color::TriColor;
use crate::epd7in5_v2::{DEFAULT_BACKGROUND_COLOR, HEIGHT, WIDTH, NUM_DISPLAY_BITS};
use crate::graphics::{TriDisplay, DisplayRotation};
use crate::epd7in5_v2::{DEFAULT_BACKGROUND_COLOR, HEIGHT, WIDTH};
use crate::graphics::{Display, DisplayRotation};
use embedded_graphics_core::pixelcolor::BinaryColor;
use embedded_graphics_core::prelude::*;

Expand All @@ -9,30 +8,30 @@ use embedded_graphics_core::prelude::*;
/// Can also be manually constructed:
/// `buffer: [DEFAULT_BACKGROUND_COLOR.get_byte_value(); WIDTH / 8 * HEIGHT]`
pub struct Display7in5 {
buffer: [u8; 2 * NUM_DISPLAY_BITS as usize],
buffer: [u8; WIDTH as usize * HEIGHT as usize / 8],
rotation: DisplayRotation,
}

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

impl DrawTarget for Display7in5 {
type Color = TriColor;
type Color = BinaryColor;
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)?;
self.draw_helper(WIDTH, HEIGHT, pixel)?;
}
Ok(())
}
Expand All @@ -44,7 +43,7 @@ impl OriginDimensions for Display7in5 {
}
}

impl TriDisplay for Display7in5 {
impl Display for Display7in5 {
fn buffer(&self) -> &[u8] {
&self.buffer
}
Expand All @@ -60,33 +59,6 @@ impl TriDisplay for Display7in5 {
fn rotation(&self) -> DisplayRotation {
self.rotation
}

fn chromatic_offset(&self) -> usize {
NUM_DISPLAY_BITS as usize
}

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

fn chromatic_buffer(&self) -> &[u8] {
&self.buffer[self.chromatic_offset()..]
}
/*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)]
Expand Down
95 changes: 14 additions & 81 deletions src/epd7in5_v2/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ use embedded_hal::{
digital::v2::{InputPin, OutputPin},
};

use crate::color::TriColor;
use crate::color::Color;
use crate::interface::DisplayInterface;
use crate::traits::{InternalWiAdditions, RefreshLut, WaveshareDisplay, WaveshareThreeColorDisplay};
use crate::traits::{InternalWiAdditions, RefreshLut, WaveshareDisplay};

pub(crate) mod command;
use self::command::Command;
Expand All @@ -32,12 +32,7 @@ pub const WIDTH: u32 = 800;
/// Height of the display
pub const HEIGHT: u32 = 480;
/// Default Background Color
//pub const DEFAULT_BACKGROUND_COLOR: Color = Color::White;

pub const DEFAULT_BACKGROUND_COLOR: TriColor = TriColor::White;

/// Number of bits for b/w buffer and same for chromatic buffer
const NUM_DISPLAY_BITS: u32 = WIDTH * HEIGHT / 8;
pub const DEFAULT_BACKGROUND_COLOR: Color = Color::White;
const IS_BUSY_LOW: bool = true;

/// Epd7in5 (V2) driver
Expand All @@ -46,7 +41,7 @@ pub struct Epd7in5<SPI, CS, BUSY, DC, RST, DELAY> {
/// Connection Interface
interface: DisplayInterface<SPI, CS, BUSY, DC, RST, DELAY>,
/// Background Color
color: TriColor,
color: Color,
}

impl<SPI, CS, BUSY, DC, RST, DELAY> InternalWiAdditions<SPI, CS, BUSY, DC, RST, DELAY>
Expand All @@ -61,74 +56,28 @@ where
{
fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
// Reset the device
self.interface.reset(delay, 4);
self.interface.reset(delay, 2);

// V2 procedure as described here:
// https://github.com/waveshare/e-Paper/blob/master/RaspberryPi%26JetsonNano/python/lib/waveshare_epd/epd7in5bc_V2.py
// and as per specs:
// https://www.waveshare.com/w/upload/6/60/7.5inch_e-Paper_V2_Specification.pdf

//self.cmd_with_data(spi, Command::BoosterSoftStart, &[0x17, 0x17, 0x27, 0x17])?;
self.cmd_with_data(spi, Command::PowerSetting, &[0x07, 0x07, 0x3F, 0x3F])?;
self.cmd_with_data(spi, Command::BoosterSoftStart, &[0x17, 0x17, 0x27, 0x17])?;
self.cmd_with_data(spi, Command::PowerSetting, &[0x07, 0x17, 0x3F, 0x3F])?;
self.command(spi, Command::PowerOn)?;
self.wait_until_idle(spi, delay)?;
self.cmd_with_data(spi, Command::PanelSetting, &[0x0F])?;
//self.cmd_with_data(spi, Command::PllControl, &[0x06])?;
self.cmd_with_data(spi, Command::PanelSetting, &[0x1F])?;
self.cmd_with_data(spi, Command::PllControl, &[0x06])?;
self.cmd_with_data(spi, Command::TconResolution, &[0x03, 0x20, 0x01, 0xE0])?;
self.cmd_with_data(spi, Command::DualSpi, &[0x00])?;
self.cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x11, 0x07])?;
self.cmd_with_data(spi, Command::TconSetting, &[0x22])?;
self.cmd_with_data(spi, Command::SpiFlashControl, &[0x00, 0x00, 0x00, 0x00])?;
self.cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x10, 0x07])?;
self.wait_until_idle(spi, delay)?;
Ok(())
}
}

impl<SPI, CS, BUSY, DC, RST, DELAY> WaveshareThreeColorDisplay<SPI, CS, BUSY, DC, RST, DELAY>
for Epd7in5<SPI, CS, BUSY, DC, RST, DELAY>
where
SPI: Write<u8>,
CS: OutputPin,
BUSY: InputPin,
DC: OutputPin,
RST: OutputPin,
DELAY: DelayMs<u8>,
{
fn update_color_frame(
&mut self,
spi: &mut SPI,
black: &[u8],
chromatic: &[u8],
) -> Result<(), SPI::Error> {
self.update_achromatic_frame(spi, black)?;
self.update_chromatic_frame(spi, chromatic)
}

/// Update only the black/white data of the display.
///
/// Finish by calling `update_chromatic_frame`.
fn update_achromatic_frame(&mut self, spi: &mut SPI, black: &[u8]) -> Result<(), SPI::Error> {
self.interface.cmd(spi, Command::DataStartTransmission1)?;
self.interface.data(spi, black)?;
Ok(())
}

/// Update only chromatic data of the display.
///
/// This data takes precedence over the black/white data.
fn update_chromatic_frame(
&mut self,
spi: &mut SPI,
chromatic: &[u8],
) -> Result<(), SPI::Error> {
self.interface.cmd(spi, Command::DataStartTransmission2)?;
self.interface.data(spi, chromatic)?;

self.wait_until_idle_no_delay(spi);
Ok(())
}
}

impl<SPI, CS, BUSY, DC, RST, DELAY> WaveshareDisplay<SPI, CS, BUSY, DC, RST, DELAY>
for Epd7in5<SPI, CS, BUSY, DC, RST, DELAY>
where
Expand All @@ -139,7 +88,7 @@ where
RST: OutputPin,
DELAY: DelayMs<u8>,
{
type DisplayColor = TriColor;
type DisplayColor = Color;
fn new(
spi: &mut SPI,
cs: CS,
Expand Down Expand Up @@ -178,17 +127,6 @@ where
) -> Result<(), SPI::Error> {
self.wait_until_idle(spi, delay)?;
self.cmd_with_data(spi, Command::DataStartTransmission2, buffer)?;

self.interface.data(spi, buffer)?;

// Clear the chromatic layer
let color = self.color.get_byte_value();

self.interface.cmd(spi, Command::DataStartTransmission2)?;
self.interface.data_x_times(spi, color, NUM_DISPLAY_BITS)?;

self.wait_until_idle(spi, delay)?;

Ok(())
}

Expand Down Expand Up @@ -235,11 +173,11 @@ where
Ok(())
}

fn set_background_color(&mut self, color: TriColor) {
fn set_background_color(&mut self, color: Color) {
self.color = color;
}

fn background_color(&self) -> &TriColor {
fn background_color(&self) -> &Color {
&self.color
}

Expand Down Expand Up @@ -298,11 +236,6 @@ where
Ok(())
}

fn wait_until_idle_no_delay(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
let _ = self.interface.wait_until_idle(IS_BUSY_LOW);
Ok(())
}

fn send_resolution(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
let w = self.width();
let h = self.height();
Expand All @@ -323,6 +256,6 @@ mod tests {
fn epd_size() {
assert_eq!(WIDTH, 800);
assert_eq!(HEIGHT, 480);
assert_eq!(DEFAULT_BACKGROUND_COLOR, TriColor::White);
assert_eq!(DEFAULT_BACKGROUND_COLOR, Color::White);
}
}
59 changes: 35 additions & 24 deletions src/epd7in5_v3/command.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! SPI Commands for the Waveshare 7.5" E-Ink Display
//! SPI Commands for the Waveshare 7.5" V3 E-Ink Display
use crate::traits;

Expand Down Expand Up @@ -71,52 +71,63 @@ pub(crate) enum Command {

/// This command builds the VCOM Look-Up Table (LUTC).
LutForVcom = 0x20,
/// This command builds the White to White Look-Up Table (LUTWW).
LutWhiteToWhite = 0x21,
/// This command builds the Black to White Look-Up Table (LUTKW).
LutBlackToWhite = 0x22,
/// This command builds the White to Black Look-Up Table (LUTWK).
LutWhiteToBlack = 0x23,
/// This command builds the Black to Black Look-Up Table (LUTKK).
LutBlackToBlack = 0x24,
/// This command builds the Border? Look-Up Table (LUTR0).
LutBorder = 0x25,

/// This command builds the Black Look-Up Table (LUTB).
LutBlack = 0x21,
/// This command builds the White Look-Up Table (LUTW).
LutWhite = 0x22,
/// This command builds the Gray1 Look-Up Table (LUTG1).
LutGray1 = 0x23,
/// This command builds the Gray2 Look-Up Table (LUTG2).
LutGray2 = 0x24,
/// This command builds the Red0 Look-Up Table (LUTR0).
LutRed0 = 0x25,
/// This command builds the Red1 Look-Up Table (LUTR1).
LutRed1 = 0x26,
/// This command builds the Red2 Look-Up Table (LUTR2).
LutRed2 = 0x27,
/// This command builds the Red3 Look-Up Table (LUTR3).
LutRed3 = 0x28,
/// This command builds the XON Look-Up Table (LUTXON).
LutXon = 0x2A,
LutXon = 0x29,

/// 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,
//TODO /// This command defines MCU host direct access external memory mode.
GateSourceStart = 0x65,
/// 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,

// TODO
ProgramMode = 0xA0,
//
// TODO
ActiveProgram = 0xA1,

// TODO
ReadOtpData = 0xA2,
// /// This is in all the Waveshare controllers for Epd7in5, but it's not documented
// /// anywhere in the datasheet `¯\_(ツ)_/¯`
// FlashMode = 0xE5,
Expand Down
Loading

0 comments on commit a234f05

Please sign in to comment.