Not all Type A screens are completly the same to the change to bring it all together was reverted.

This commit is contained in:
Christoph Groß 2018-08-06 13:34:33 +02:00
parent 230fb947cb
commit 6422142133
13 changed files with 689 additions and 62 deletions

View File

@ -2,14 +2,16 @@
This library contains a driver for E-Paper Modules from Waveshare.
Support for more than the 4.2" EPD (especially the smaller and faster ones) is in the work.
Support for more than the 4.2in EPD (especially the smaller and faster ones) is in the work.
The 2.9in (A) and 1.54 (A) variant should both work but aren't tested yet.
## (Supported) Devices
| Device (with Link) | Colors | Flexible Display | Partial Refresh | Supported | Tested |
| :---: | --- | :---: | :---: | :---: | :---: |
| [4.2 Inch B/W (A)](https://www.waveshare.com/product/4.2inch-e-paper-module.htm) | Black, White | ✕ | Not officially [[1](#42-inch-e-ink-blackwhite)] | ✔ | ✔ |
| [1.54 Inch B/W (A)](https://www.waveshare.com/1.54inch-e-Paper-Module.htm) | Black, White | ✕ | ✔ | | |
| [1.54 Inch B/W (A)](https://www.waveshare.com/1.54inch-e-Paper-Module.htm) | Black, White | ✕ | ✔ | | |
| [2.13 Inch B/W (A)](https://www.waveshare.com/product/2.13inch-e-paper-hat.htm) | Black, White | ✕ | ✔ | | |
| [2.9 Inch B/W (A)](https://www.waveshare.com/product/2.9inch-e-paper-module.htm) | Black, White | ✕ | ✔ | ✔ | |

View File

@ -5,7 +5,13 @@ extern crate linux_embedded_hal as lin_hal;
extern crate eink_waveshare_rs;
use eink_waveshare_rs::{epd4in2::EPD4in2, drawing::{Graphics, color::Color}, interface::WaveshareInterface};
use eink_waveshare_rs::{
epd4in2::{EPD4in2, self},
drawing::{Graphics, color::Color},
interface::{
WaveshareInterface,
connection_interface::ConnectionInterface},
};
use lin_hal::spidev::{self, SpidevOptions};
use lin_hal::{Pin, Spidev};
@ -99,7 +105,8 @@ fn main() {
//TODO: wait for Digital::InputPin
//fixed currently with the HackInputPin, see further above
let mut epd4in2 = EPD4in2::new(spi, cs, busy_in, dc, rst, delay).expect("eink inialize error");
let connection_interface = ConnectionInterface::new(spi, cs, busy_in, dc, rst, delay);
let mut epd4in2 = EPD4in2::new(connection_interface, epd4in2::new()).expect("eink inialize error");
//let mut buffer = [0u8, epd4in2.get_width() / 8 * epd4in2.get_height()];
let mut buffer = [0u8; 15000];

View File

@ -1,3 +1,310 @@
pub(crate) const WIDTH: u16 = 128;
pub(crate) const HEIGHT: u16 = 296;
pub(crate) const DPI: u16 = 184;
//! A simple Driver for the Waveshare 1.54" E-Ink Display via SPI
//!
//!
//! # Examples from the 4.2" Display. It should work the same for the 1.54" one.
//!
//! ```ignore
//! let mut epd4in2 = EPD4in2::new(spi, cs, busy, dc, rst, delay).unwrap();
//!
//! let mut buffer = [0u8, epd4in2.get_width() / 8 * epd4in2.get_height()];
//!
//! // draw something into the buffer
//!
//! epd4in2.display_and_transfer_buffer(buffer, None);
//!
//! // wait and look at the image
//!
//! epd4in2.clear_frame(None);
//!
//! epd4in2.sleep();
//! ```
const WIDTH: u16 = 200;
const HEIGHT: u16 = 200;
const DPI: u16 = 184;
use epds::EPD;
use hal::{
blocking::{
spi::Write,
delay::*
},
digital::*
};
use type_a::luts::*;
pub use type_a::command::Command;
use drawing::color::Color;
use interface::*;
use interface::connection_interface::ConnectionInterface;
/// EPD2in9 driver
///
pub struct EPD2in9<SPI, CS, BUSY, DataCommand, RST, Delay> {
/// SPI
interface: ConnectionInterface<SPI, CS, BUSY, DataCommand, RST, Delay>,
/// EPD (width, height)
//epd: EPD,
/// Color
background_color: Color,
}
impl<SPI, CS, BUSY, DataCommand, RST, Delay, E> EPD2in9<SPI, CS, BUSY, DataCommand, RST, Delay>
where
SPI: Write<u8, Error = E>,
CS: OutputPin,
BUSY: InputPin,
DataCommand: OutputPin,
RST: OutputPin,
Delay: DelayUs<u16> + DelayMs<u16>
{
}
impl<SPI, CS, BUSY, DataCommand, RST, Delay, E> WaveshareInterface<SPI, CS, BUSY, DataCommand, RST, Delay, E>
for EPD2in9<SPI, CS, BUSY, DataCommand, RST, Delay>
where
SPI: Write<u8, Error = E>,
CS: OutputPin,
BUSY: InputPin,
DataCommand: OutputPin,
RST: OutputPin,
Delay: DelayUs<u16> + DelayMs<u16>,
{
fn get_width(&self) -> u16 {
WIDTH
}
fn get_height(&self) -> u16 {
HEIGHT
}
fn new(
interface: ConnectionInterface<SPI, CS, BUSY, DataCommand, RST, Delay>
) -> Result<Self, E> {
let epd = EPD::new(WIDTH, HEIGHT);
let background_color = Color::White;
let mut epd = EPD2in9 {interface, /*epd,*/ background_color};
epd.init()?;
Ok(epd)
}
fn init(&mut self) -> Result<(), E> {
self.reset();
// 3 Databytes:
// A[7:0]
// 0.. A[8]
// 0.. B[2:0]
// Default Values: A = Height of Screen (0x127), B = 0x00 (GD, SM and TB=0?)
self.interface.send_command(Command::DRIVER_OUTPUT_CONTROL)?;
self.interface.send_data(HEIGHT as u8)?;
self.interface.send_data((HEIGHT >> 8) as u8)?;
self.interface.send_data(0x00)?;
// 3 Databytes: (and default values from datasheet and arduino)
// 1 .. A[6:0] = 0xCF | 0xD7
// 1 .. B[6:0] = 0xCE | 0xD6
// 1 .. C[6:0] = 0x8D | 0x9D
//TODO: test
self.interface.send_command(Command::BOOSTER_SOFT_START_CONTROL)?;
self.interface.send_data(0xD7)?;
self.interface.send_data(0xD6)?;
self.interface.send_data(0x9D)?;
// One Databyte with value 0xA8 for 7V VCOM
self.interface.send_command(Command::WRITE_VCOM_REGISTER)?;
self.interface.send_data(0xA8)?;
// One Databyte with default value 0x1A for 4 dummy lines per gate
self.interface.send_command(Command::SET_DUMMY_LINE_PERIOD)?;
self.interface.send_data(0x1A)?;
// One Databyte with default value 0x08 for 2us per line
self.interface.send_command(Command::SET_GATE_LINE_WIDTH)?;
self.interface.send_data(0x08)?;
// One Databyte with default value 0x03
// -> address: x increment, y increment, address counter is updated in x direction
self.interface.send_command(Command::DATA_ENTRY_MODE_SETTING)?;
self.interface.send_data(0x03)?;
self.set_lut()
}
fn sleep(&mut self) -> Result<(), E> {
self.interface.send_command(Command::DEEP_SLEEP_MODE)?;
// 0x00 for Normal mode (Power on Reset), 0x01 for Deep Sleep Mode
//TODO: is 0x00 needed here?
self.interface.send_data(0x00)?;
self.wait_until_idle();
Ok(())
}
fn reset(&mut self) {
self.interface.reset()
}
fn delay_ms(&mut self, delay: u16) {
self.interface.delay_ms(delay)
}
fn update_frame(&mut self, buffer: &[u8]) -> Result<(), E>{
self.use_full_frame()?;
self.interface.send_command(Command::WRITE_RAM)?;
self.interface.send_multiple_data(buffer)
}
//TODO: update description: last 3 bits will be ignored for width and x_pos
fn update_partial_frame(&mut self, buffer: &[u8], x: u16, y: u16, width: u16, height: u16) -> Result<(), E>{
self.set_ram_area(x, y, x + width, y + height)?;
self.set_ram_counter(x, y)?;
self.interface.send_command(Command::WRITE_RAM)?;
self.interface.send_multiple_data(buffer)
}
fn display_frame(&mut self) -> Result<(), E>{
// enable clock signal, enable cp, display pattern -> 0xC4 (tested with the arduino version)
//TODO: test control_1 or control_2 with default value 0xFF (from the datasheet)
self.interface.send_command(Command::DISPLAY_UPDATE_CONTROL_2)?;
self.interface.send_data(0xC4)?;
self.interface.send_command(Command::MASTER_ACTIVATION)?;
// MASTER Activation should not be interupted to avoid currption of panel images
// therefore a terminate command is send
self.interface.send_command(Command::TERMINATE_COMMANDS_AND_FRAME_WRITE)
}
fn update_and_display_frame(&mut self, buffer: &[u8]) -> Result<(), E>{
self.update_frame(buffer)?;
self.display_frame()
}
fn clear_frame(&mut self) -> Result<(), E>{
self.use_full_frame()?;
// clear the ram with the background color
let color = self.background_color.get_byte_value();
self.interface.send_command(Command::WRITE_RAM)?;
self.interface.send_data_x_times(color, WIDTH / 8 * HEIGHT)
}
/// Sets the backgroundcolor for various commands like [WaveshareInterface::clear_frame()](clear_frame())
fn set_background_color(&mut self, background_color: Color){
self.background_color = background_color;
}
}
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>,
{
fn wait_until_idle(&mut self) {
self.interface.wait_until_idle(false);
}
pub(crate) fn use_full_frame(&mut self) -> Result<(), E> {
// choose full frame/ram
self.set_ram_area(0, 0, WIDTH - 1, HEIGHT - 1)?;
// start from the beginning
self.set_ram_counter(0,0)
}
pub(crate) fn set_ram_area(&mut self, start_x: u16, start_y: u16, end_x: u16, end_y: u16) -> Result<(), E> {
assert!(start_x < end_x);
assert!(start_y < end_y);
// x is positioned in bytes, so the last 3 bits which show the position inside a byte in the ram
// aren't relevant
self.interface.send_command(Command::SET_RAM_X_ADDRESS_START_END_POSITION)?;
self.interface.send_data((start_x >> 3) as u8)?;
self.interface.send_data((end_x >> 3) as u8)?;
// 2 Databytes: A[7:0] & 0..A[8] for each - start and end
self.interface.send_command(Command::SET_RAM_Y_ADDRESS_START_END_POSITION)?;
self.interface.send_data(start_y as u8)?;
self.interface.send_data((start_y >> 8) as u8)?;
self.interface.send_data(end_y as u8)?;
self.interface.send_data((end_y >> 8) as u8)
}
pub(crate) fn set_ram_counter(&mut self, x: u16, y: u16) -> Result<(), E> {
// x is positioned in bytes, so the last 3 bits which show the position inside a byte in the ram
// aren't relevant
self.interface.send_command(Command::SET_RAM_X_ADDRESS_COUNTER)?;
self.interface.send_data((x >> 3) as u8)?;
// 2 Databytes: A[7:0] & 0..A[8]
self.interface.send_command(Command::SET_RAM_Y_ADDRESS_COUNTER)?;
self.interface.send_data(y as u8)?;
self.interface.send_data((y >> 8) as u8)?;
self.wait_until_idle();
Ok(())
}
/// Uses the slower full update
pub fn set_lut(&mut self) -> Result<(), E> {
self.set_lut_helper(&LUT_FULL_UPDATE)
}
/// Uses the quick partial refresh
pub fn set_lut_quick(&mut self) -> Result<(), E> {
self.set_lut_helper(&LUT_PARTIAL_UPDATE)
}
//TODO: assert length for LUT is exactly 30
fn set_lut_manual(&mut self, buffer: &[u8]) -> Result<(), E> {
self.set_lut_helper(buffer)
}
fn set_lut_helper(&mut self, buffer: &[u8]) -> Result<(), E> {
assert!(buffer.len() == 30);
self.interface.send_command(Command::WRITE_LUT_REGISTER)?;
self.interface.send_multiple_data(buffer)
}
}

View File

@ -1,2 +1,308 @@
pub(crate) const WIDTH: u16 = 128;
pub(crate) const HEIGHT: u16 = 296;
//! A simple Driver for the Waveshare 2.9" E-Ink Display via SPI
//!
//!
//! # Examples from the 4.2" Display. It should work the same for the 2.9" one.
//!
//! ```ignore
//! let mut epd4in2 = EPD4in2::new(spi, cs, busy, dc, rst, delay).unwrap();
//!
//! let mut buffer = [0u8, epd4in2.get_width() / 8 * epd4in2.get_height()];
//!
//! // draw something into the buffer
//!
//! epd4in2.display_and_transfer_buffer(buffer, None);
//!
//! // wait and look at the image
//!
//! epd4in2.clear_frame(None);
//!
//! epd4in2.sleep();
//! ```
const WIDTH: u16 = 128;
const HEIGHT: u16 = 296;
use epds::EPD;
use hal::{
blocking::{
spi::Write,
delay::*
},
digital::*
};
use type_a::luts::*;
pub use type_a::command::Command;
use drawing::color::Color;
use interface::*;
use interface::connection_interface::ConnectionInterface;
/// EPD2in9 driver
///
pub struct EPD2in9<SPI, CS, BUSY, DataCommand, RST, Delay> {
/// SPI
interface: ConnectionInterface<SPI, CS, BUSY, DataCommand, RST, Delay>,
/// EPD (width, height)
//epd: EPD,
/// Color
background_color: Color,
}
impl<SPI, CS, BUSY, DataCommand, RST, Delay, E> EPD2in9<SPI, CS, BUSY, DataCommand, RST, Delay>
where
SPI: Write<u8, Error = E>,
CS: OutputPin,
BUSY: InputPin,
DataCommand: OutputPin,
RST: OutputPin,
Delay: DelayUs<u16> + DelayMs<u16>
{
}
impl<SPI, CS, BUSY, DataCommand, RST, Delay, E> WaveshareInterface<SPI, CS, BUSY, DataCommand, RST, Delay, E>
for EPD2in9<SPI, CS, BUSY, DataCommand, RST, Delay>
where
SPI: Write<u8, Error = E>,
CS: OutputPin,
BUSY: InputPin,
DataCommand: OutputPin,
RST: OutputPin,
Delay: DelayUs<u16> + DelayMs<u16>,
{
fn get_width(&self) -> u16 {
WIDTH
}
fn get_height(&self) -> u16 {
HEIGHT
}
fn new(
interface: ConnectionInterface<SPI, CS, BUSY, DataCommand, RST, Delay>
) -> Result<Self, E> {
//let epd = EPD::new(WIDTH, HEIGHT);
let background_color = Color::White;
let mut epd = EPD2in9 {interface, /*epd,*/ background_color};
epd.init()?;
Ok(epd)
}
fn init(&mut self) -> Result<(), E> {
self.reset();
// 3 Databytes:
// A[7:0]
// 0.. A[8]
// 0.. B[2:0]
// Default Values: A = Height of Screen (0x127), B = 0x00 (GD, SM and TB=0?)
self.interface.send_command(Command::DRIVER_OUTPUT_CONTROL)?;
self.interface.send_data(HEIGHT as u8)?;
self.interface.send_data((HEIGHT >> 8) as u8)?;
self.interface.send_data(0x00)?;
// 3 Databytes: (and default values from datasheet and arduino)
// 1 .. A[6:0] = 0xCF | 0xD7
// 1 .. B[6:0] = 0xCE | 0xD6
// 1 .. C[6:0] = 0x8D | 0x9D
//TODO: test
self.interface.send_command(Command::BOOSTER_SOFT_START_CONTROL)?;
self.interface.send_data(0xD7)?;
self.interface.send_data(0xD6)?;
self.interface.send_data(0x9D)?;
// One Databyte with value 0xA8 for 7V VCOM
self.interface.send_command(Command::WRITE_VCOM_REGISTER)?;
self.interface.send_data(0xA8)?;
// One Databyte with default value 0x1A for 4 dummy lines per gate
self.interface.send_command(Command::SET_DUMMY_LINE_PERIOD)?;
self.interface.send_data(0x1A)?;
// One Databyte with default value 0x08 for 2us per line
self.interface.send_command(Command::SET_GATE_LINE_WIDTH)?;
self.interface.send_data(0x08)?;
// One Databyte with default value 0x03
// -> address: x increment, y increment, address counter is updated in x direction
self.interface.send_command(Command::DATA_ENTRY_MODE_SETTING)?;
self.interface.send_data(0x03)?;
self.set_lut()
}
fn sleep(&mut self) -> Result<(), E> {
self.interface.send_command(Command::DEEP_SLEEP_MODE)?;
// 0x00 for Normal mode (Power on Reset), 0x01 for Deep Sleep Mode
//TODO: is 0x00 needed here?
self.interface.send_data(0x00)?;
self.wait_until_idle();
Ok(())
}
fn reset(&mut self) {
self.interface.reset()
}
fn delay_ms(&mut self, delay: u16) {
self.interface.delay_ms(delay)
}
fn update_frame(&mut self, buffer: &[u8]) -> Result<(), E>{
self.use_full_frame()?;
self.interface.send_command(Command::WRITE_RAM)?;
self.interface.send_multiple_data(buffer)
}
//TODO: update description: last 3 bits will be ignored for width and x_pos
fn update_partial_frame(&mut self, buffer: &[u8], x: u16, y: u16, width: u16, height: u16) -> Result<(), E>{
self.set_ram_area(x, y, x + width, y + height)?;
self.set_ram_counter(x, y)?;
self.interface.send_command(Command::WRITE_RAM)?;
self.interface.send_multiple_data(buffer)
}
fn display_frame(&mut self) -> Result<(), E>{
// enable clock signal, enable cp, display pattern -> 0xC4 (tested with the arduino version)
//TODO: test control_1 or control_2 with default value 0xFF (from the datasheet)
self.interface.send_command(Command::DISPLAY_UPDATE_CONTROL_2)?;
self.interface.send_data(0xC4)?;
self.interface.send_command(Command::MASTER_ACTIVATION)?;
// MASTER Activation should not be interupted to avoid currption of panel images
// therefore a terminate command is send
self.interface.send_command(Command::TERMINATE_COMMANDS_AND_FRAME_WRITE)
}
fn update_and_display_frame(&mut self, buffer: &[u8]) -> Result<(), E>{
self.update_frame(buffer)?;
self.display_frame()
}
fn clear_frame(&mut self) -> Result<(), E>{
self.use_full_frame()?;
// clear the ram with the background color
let color = self.background_color.get_byte_value();
self.interface.send_command(Command::WRITE_RAM)?;
self.interface.send_data_x_times(color, WIDTH / 8 * HEIGHT)
}
/// Sets the backgroundcolor for various commands like [WaveshareInterface::clear_frame()](clear_frame())
fn set_background_color(&mut self, background_color: Color){
self.background_color = background_color;
}
}
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>,
{
fn wait_until_idle(&mut self) {
self.interface.wait_until_idle(false);
}
pub(crate) fn use_full_frame(&mut self) -> Result<(), E> {
// choose full frame/ram
self.set_ram_area(0, 0, WIDTH - 1, HEIGHT - 1)?;
// start from the beginning
self.set_ram_counter(0,0)
}
pub(crate) fn set_ram_area(&mut self, start_x: u16, start_y: u16, end_x: u16, end_y: u16) -> Result<(), E> {
assert!(start_x < end_x);
assert!(start_y < end_y);
// x is positioned in bytes, so the last 3 bits which show the position inside a byte in the ram
// aren't relevant
self.interface.send_command(Command::SET_RAM_X_ADDRESS_START_END_POSITION)?;
self.interface.send_data((start_x >> 3) as u8)?;
self.interface.send_data((end_x >> 3) as u8)?;
// 2 Databytes: A[7:0] & 0..A[8] for each - start and end
self.interface.send_command(Command::SET_RAM_Y_ADDRESS_START_END_POSITION)?;
self.interface.send_data(start_y as u8)?;
self.interface.send_data((start_y >> 8) as u8)?;
self.interface.send_data(end_y as u8)?;
self.interface.send_data((end_y >> 8) as u8)
}
pub(crate) fn set_ram_counter(&mut self, x: u16, y: u16) -> Result<(), E> {
// x is positioned in bytes, so the last 3 bits which show the position inside a byte in the ram
// aren't relevant
self.interface.send_command(Command::SET_RAM_X_ADDRESS_COUNTER)?;
self.interface.send_data((x >> 3) as u8)?;
// 2 Databytes: A[7:0] & 0..A[8]
self.interface.send_command(Command::SET_RAM_Y_ADDRESS_COUNTER)?;
self.interface.send_data(y as u8)?;
self.interface.send_data((y >> 8) as u8)?;
self.wait_until_idle();
Ok(())
}
/// Uses the slower full update
pub fn set_lut(&mut self) -> Result<(), E> {
self.set_lut_helper(&LUT_FULL_UPDATE)
}
/// Uses the quick partial refresh
pub fn set_lut_quick(&mut self) -> Result<(), E> {
self.set_lut_helper(&LUT_PARTIAL_UPDATE)
}
//TODO: assert length for LUT is exactly 30
fn set_lut_manual(&mut self, buffer: &[u8]) -> Result<(), E> {
self.set_lut_helper(buffer)
}
fn set_lut_helper(&mut self, buffer: &[u8]) -> Result<(), E> {
assert!(buffer.len() == 30);
self.interface.send_command(Command::WRITE_LUT_REGISTER)?;
self.interface.send_multiple_data(buffer)
}
}

View File

@ -1,5 +1,5 @@
pub(crate) const WIDTH: usize = 400;
pub(crate) const HEIGHT: usize = 300;
pub(crate) const WIDTH: u16 = 400;
pub(crate) const HEIGHT: u16 = 300;
pub(crate) const LUT_VCOM0: [u8; 44] = [
0x00, 0x17, 0x00, 0x00, 0x00, 0x02,

View File

@ -49,7 +49,6 @@
use hal::{
blocking::{delay::*, spi::Write},
digital::*,
spi::{Mode, Phase, Polarity},
};
use interface::{connection_interface::ConnectionInterface, WaveshareInterface};
@ -65,6 +64,14 @@ pub use self::command::Command;
use epds::EPD;
pub(crate) fn new() -> EPD {
EPD::new(
constants::WIDTH,
constants::HEIGHT
)
}
/// EPD4in2 driver
///
pub struct EPD4in2<SPI, CS, BUSY, DC, RST, D>
@ -81,10 +88,10 @@ pub struct EPD4in2<SPI, CS, BUSY, DC, RST, D>
impl<SPI, CS, BUSY, DataCommand, RST, Delay, SPI_Error> WaveshareInterface<SPI, CS, BUSY, DataCommand, RST, Delay, SPI_Error>
impl<SPI, CS, BUSY, DataCommand, RST, Delay, SpiError> WaveshareInterface<SPI, CS, BUSY, DataCommand, RST, Delay, SpiError>
for EPD4in2<SPI, CS, BUSY, DataCommand, RST, Delay>
where
SPI: Write<u8, Error = SPI_Error>,
SPI: Write<u8, Error = SpiError>,
CS: OutputPin,
BUSY: InputPin,
DataCommand: OutputPin,
@ -114,7 +121,7 @@ where
///
/// epd4in2.sleep();
/// ```
fn new(interface: ConnectionInterface<SPI, CS, BUSY, DataCommand, RST, Delay>, epd: EPD) -> Result<Self, SPI_Error> {
fn new(interface: ConnectionInterface<SPI, CS, BUSY, DataCommand, RST, Delay>) -> Result<Self, SpiError> {
let width = WIDTH as u16;
let height = HEIGHT as u16;
@ -132,7 +139,7 @@ where
Ok(epd)
}
fn init(&mut self) -> Result<(), SPI_Error> {
fn init(&mut self) -> Result<(), SpiError> {
// reset the device
self.reset();
@ -179,7 +186,7 @@ where
Ok(())
}
fn sleep(&mut self) -> Result<(), SPI_Error> {
fn sleep(&mut self) -> Result<(), SpiError> {
self.send_command(Command::VCOM_AND_DATA_INTERVAL_SETTING)?;
self.send_data(0x17)?; //border floating
self.send_command(Command::VCM_DC_SETTING)?; // VCOM to 0V
@ -208,7 +215,7 @@ where
self.interface.delay_ms(delay)
}
fn update_frame(&mut self, buffer: &[u8]) -> Result<(), SPI_Error> {
fn update_frame(&mut self, buffer: &[u8]) -> Result<(), SpiError> {
let color_value = self.color.get_byte_value();
self.send_resolution()?;
@ -244,7 +251,7 @@ where
y: u16,
width: u16,
height: u16,
) -> Result<(), SPI_Error> {
) -> Result<(), SpiError> {
if buffer.len() as u16 != width / 8 * height {
//TODO: panic!! or sth like that
@ -281,13 +288,13 @@ where
self.send_command(Command::PARTIAL_OUT)
}
fn update_and_display_frame(&mut self, buffer: &[u8]) -> Result<(), SPI_Error>{
fn update_and_display_frame(&mut self, buffer: &[u8]) -> Result<(), SpiError>{
self.update_frame(buffer)?;
self.display_frame()
}
fn display_frame(&mut self) -> Result<(), SPI_Error> {
fn display_frame(&mut self) -> Result<(), SpiError> {
self.send_command(Command::DISPLAY_REFRESH)?;
self.wait_until_idle();
@ -297,7 +304,7 @@ where
// TODO: add this abstraction function
// fn update_and_display_frame(&mut self, buffer: &[u8]) -> Result<(), E>;
fn clear_frame(&mut self) -> Result<(), SPI_Error> {
fn clear_frame(&mut self) -> Result<(), SpiError> {
self.send_resolution()?;
let size = self.width / 8 * self.height;
@ -325,24 +332,24 @@ where
}
}
impl<SPI, CS, BUSY, DC, RST, D, SPI_Error> EPD4in2<SPI, CS, BUSY, DC, RST, D>
impl<SPI, CS, BUSY, DC, RST, D, SpiError> EPD4in2<SPI, CS, BUSY, DC, RST, D>
where
SPI: Write<u8, Error = SPI_Error>,
SPI: Write<u8, Error = SpiError>,
CS: OutputPin,
BUSY: InputPin,
DC: OutputPin,
RST: OutputPin,
D: DelayUs<u16> + DelayMs<u16>,
{
fn send_command(&mut self, command: Command) -> Result<(), SPI_Error> {
fn send_command(&mut self, command: Command) -> Result<(), SpiError> {
self.interface.send_command(command)
}
fn send_data(&mut self, val: u8) -> Result<(), SPI_Error> {
fn send_data(&mut self, val: u8) -> Result<(), SpiError> {
self.interface.send_data(val)
}
fn send_multiple_data(&mut self, data: &[u8]) -> Result<(), SPI_Error> {
fn send_multiple_data(&mut self, data: &[u8]) -> Result<(), SpiError> {
self.interface.send_multiple_data(data)
}
@ -350,7 +357,7 @@ where
self.interface.wait_until_idle(true)
}
fn send_resolution(&mut self) -> Result<(), SPI_Error> {
fn send_resolution(&mut self) -> Result<(), SpiError> {
let w = self.get_width();
let h = self.get_height();
@ -363,7 +370,7 @@ where
/// Fill the look-up table for the EPD
//TODO: make public?
fn set_lut(&mut self) -> Result<(), SPI_Error> {
fn set_lut(&mut self) -> Result<(), SpiError> {
self.set_lut_helper(&LUT_VCOM0, &LUT_WW, &LUT_BW, &LUT_WB, &LUT_BB)
}
@ -372,7 +379,7 @@ where
/// Is automatically done by [EPD4in2::display_frame_quick()](EPD4in2::display_frame_quick())
/// //TODO: make public?
#[cfg(feature = "epd4in2_fast_update")]
fn set_lut_quick(&mut self) -> Result<(), SPI_Error> {
fn set_lut_quick(&mut self) -> Result<(), SpiError> {
self.set_lut_helper(
&LUT_VCOM0_QUICK,
&LUT_WW_QUICK,
@ -389,7 +396,7 @@ where
lut_bw: &[u8],
lut_wb: &[u8],
lut_bb: &[u8],
) -> Result<(), SPI_Error> {
) -> Result<(), SpiError> {
// LUT VCOM
self.send_command(Command::LUT_FOR_VCOM)?;
self.send_multiple_data(lut_vcom)?;

View File

@ -1,4 +1,3 @@
/// A struct containing necessary info about a epd (electronic paper display). E.g:
///
/// - Width
@ -6,7 +5,7 @@
/// ...
///
/// This needs to be implemented by each new Display
pub struct EPD {
pub(crate) struct EPD {
pub(crate) width: u16,
pub(crate) height: u16
//displayrotation?
@ -16,6 +15,4 @@ impl EPD {
pub(crate) fn new(width: u16, height: u16) -> EPD {
EPD {width, height}
}
}

View File

@ -10,7 +10,7 @@ use interface::Command;
/// The Connection Interface of all (?) Waveshare EPD-Devices
///
pub(crate) struct ConnectionInterface<SPI, CS, BUSY, DC, RST, D> {
pub struct ConnectionInterface<SPI, CS, BUSY, DC, RST, D> {
/// SPI
spi: SPI,
/// CS for SPI
@ -35,7 +35,7 @@ where
RST: OutputPin,
Delay: DelayUs<u16> + DelayMs<u16>,
{
pub(crate) fn new(spi: SPI, cs: CS, busy: BUSY, dc: DataCommand, rst: RST, delay: Delay) -> Self {
pub fn new(spi: SPI, cs: CS, busy: BUSY, dc: DataCommand, rst: RST, delay: Delay) -> Self {
ConnectionInterface {spi, cs, busy, dc, rst, delay }
}

View File

@ -7,7 +7,6 @@ use hal::{
};
use core::marker::Sized;
use drawing::color::Color;
/// Interface for the physical connection between display and the controlling device
@ -28,6 +27,8 @@ pub trait Displays {
}
//TODO: add LUT trait with set_fast_lut and set_manual_lut and set_normal_lut or sth like that?
// for partial updates
trait LUTSupport<Error> {
@ -56,7 +57,7 @@ pub trait WaveshareInterface<SPI, CS, BUSY, DataCommand, RST, Delay, Error>
///
/// This already initialises the device. That means [init()](WaveshareInterface::init()) isn't needed directly afterwards
fn new(
interface: ConnectionInterface<SPI, CS, BUSY, DataCommand, RST, Delay>,
interface: ConnectionInterface<SPI, CS, BUSY, DataCommand, RST, Delay>
) -> Result<Self, Error>
where Self: Sized;

View File

@ -53,7 +53,7 @@ use hal::{
pub mod drawing;
pub mod epd4in2;
mod epds;
pub mod epd2in9;
@ -62,7 +62,6 @@ pub mod interface;
pub mod type_a;
//TODO: test spi mode
/// SPI mode -
/// For more infos see [Requirements: SPI](index.html#spi)

View File

@ -91,8 +91,8 @@ mod tests {
fn command_addr() {
assert_eq!(Command::DRIVER_OUTPUT_CONTROL.address(), 0x01);
assert_eq!(Command::SET_RAM_X_ADDRESS_COUNTER.addr(), 0x4E);
assert_eq!(Command::SET_RAM_X_ADDRESS_COUNTER.address(), 0x4E);
assert_eq!(Command::TERMINATE_COMMANDS_AND_FRAME_WRITE.addr(), 0xFF);
assert_eq!(Command::TERMINATE_COMMANDS_AND_FRAME_WRITE.address(), 0xFF);
}
}

View File

@ -28,8 +28,8 @@ use hal::{
digital::*
};
mod constants;
use self::constants::*;
pub(crate) mod luts;
use self::luts::*;
use drawing::color::Color;
@ -40,17 +40,18 @@ use interface::*;
use interface::connection_interface::ConnectionInterface;
use epds::EPD;
pub(crate) const WIDTH: u16 = 128;
pub(crate) const HEIGHT: u16 = 296;
/// EPD2in9 driver
///
pub struct EPD2in9<SPI, CS, BUSY, DataCommand, RST, Delay> {
/// SPI
interface: ConnectionInterface<SPI, CS, BUSY, DataCommand, RST, Delay>,
/// Width
width: u16,
/// Height
height: u16,
/// EPD (width, height)
epd: EPD,
/// Color
background_color: Color,
}
@ -80,24 +81,21 @@ where
{
fn get_width(&self) -> u16 {
self.width
self.epd.width
}
fn get_height(&self) -> u16 {
self.height
self.epd.height
}
fn new(
interface: ConnectionInterface<SPI, CS, BUSY, DataCommand, RST, Delay>,
display: Displays
) -> Result<Self, E> {
let width = WIDTH as u16;
let height = HEIGHT as u16;
interface: ConnectionInterface<SPI, CS, BUSY, DataCommand, RST, Delay>
) -> Result<Self, E> {
let epd = EPD::new(WIDTH, HEIGHT);
let background_color = Color::White;
let mut epd = EPD2in9 {interface, width, height, background_color};
let mut epd = EPD2in9 {interface, epd, background_color};
epd.init()?;
@ -118,8 +116,8 @@ where
// 0.. B[2:0]
// Default Values: A = Height of Screen (0x127), B = 0x00 (GD, SM and TB=0?)
self.interface.send_command(Command::DRIVER_OUTPUT_CONTROL)?;
self.interface.send_data(HEIGHT as u8)?;
self.interface.send_data((HEIGHT >> 8) as u8)?;
self.interface.send_data(self.epd.height as u8)?;
self.interface.send_data((self.epd.height >> 8) as u8)?;
self.interface.send_data(0x00)?;
// 3 Databytes: (and default values from datasheet and arduino)
@ -217,7 +215,7 @@ where
let color = self.background_color.get_byte_value();
self.interface.send_command(Command::WRITE_RAM)?;
self.interface.send_data_x_times(color, WIDTH / 8 * HEIGHT)
self.interface.send_data_x_times(color, self.epd.width / 8 * self.epd.height)
}
/// Sets the backgroundcolor for various commands like [WaveshareInterface::clear_frame()](clear_frame())
@ -241,8 +239,11 @@ where
}
pub(crate) fn use_full_frame(&mut self) -> Result<(), E> {
let width = self.epd.width;
let height = self.epd.height;
// choose full frame/ram
self.set_ram_area(0, 0, WIDTH - 1, HEIGHT - 1)?;
self.set_ram_area(0, 0, width - 1, height - 1)?;
// start from the beginning
self.set_ram_counter(0,0)