Browse Source

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

embedded-hal-1.0
Christoph Groß 7 years ago
parent
commit
6422142133
  1. 6
      README.md
  2. 11
      examples/embedded_linux/src/main.rs
  3. 313
      src/epd1in54/mod.rs
  4. 310
      src/epd2in9/mod.rs
  5. 4
      src/epd4in2/constants.rs
  6. 47
      src/epd4in2/mod.rs
  7. 5
      src/epds.rs
  8. 4
      src/interface/connection_interface.rs
  9. 5
      src/interface/mod.rs
  10. 3
      src/lib.rs
  11. 4
      src/type_a/command.rs
  12. 0
      src/type_a/luts.rs
  13. 37
      src/type_a/mod.rs

6
README.md

@ -2,14 +2,16 @@
This library contains a driver for E-Paper Modules from Waveshare. 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 ## (Supported) Devices
| Device (with Link) | Colors | Flexible Display | Partial Refresh | Supported | Tested | | 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)] | ✔ | ✔ | | [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.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 | ✕ | ✔ | ✔ | | | [2.9 Inch B/W (A)](https://www.waveshare.com/product/2.9inch-e-paper-module.htm) | Black, White | ✕ | ✔ | ✔ | |

11
examples/embedded_linux/src/main.rs

@ -5,7 +5,13 @@ extern crate linux_embedded_hal as lin_hal;
extern crate eink_waveshare_rs; 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::spidev::{self, SpidevOptions};
use lin_hal::{Pin, Spidev}; use lin_hal::{Pin, Spidev};
@ -99,7 +105,8 @@ fn main() {
//TODO: wait for Digital::InputPin //TODO: wait for Digital::InputPin
//fixed currently with the HackInputPin, see further above //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, epd4in2.get_width() / 8 * epd4in2.get_height()];
let mut buffer = [0u8; 15000]; let mut buffer = [0u8; 15000];

313
src/epd1in54/mod.rs

@ -1,3 +1,310 @@
pub(crate) const WIDTH: u16 = 128; //! A simple Driver for the Waveshare 1.54" E-Ink Display via SPI
pub(crate) const HEIGHT: u16 = 296; //!
pub(crate) const DPI: u16 = 184; //!
//! # 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)
}
}

310
src/epd2in9/mod.rs

@ -1,2 +1,308 @@
pub(crate) const WIDTH: u16 = 128; //! A simple Driver for the Waveshare 2.9" E-Ink Display via SPI
pub(crate) const HEIGHT: u16 = 296; //!
//!
//! # 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)
}
}

4
src/epd4in2/constants.rs

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

47
src/epd4in2/mod.rs

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

5
src/epds.rs

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

4
src/interface/connection_interface.rs

@ -10,7 +10,7 @@ use interface::Command;
/// The Connection Interface of all (?) Waveshare EPD-Devices /// 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: SPI, spi: SPI,
/// CS for SPI /// CS for SPI
@ -35,7 +35,7 @@ where
RST: OutputPin, RST: OutputPin,
Delay: DelayUs<u16> + DelayMs<u16>, 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 } ConnectionInterface {spi, cs, busy, dc, rst, delay }
} }

5
src/interface/mod.rs

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

3
src/lib.rs

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

4
src/type_a/command.rs

@ -91,8 +91,8 @@ mod tests {
fn command_addr() { fn command_addr() {
assert_eq!(Command::DRIVER_OUTPUT_CONTROL.address(), 0x01); 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);
} }
} }

0
src/type_a/constants.rs → src/type_a/luts.rs

37
src/type_a/mod.rs

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

Loading…
Cancel
Save