commit
e5a1e3bf25
|
|
@ -98,9 +98,9 @@ script:
|
|||
- cargo build
|
||||
- cargo build --release
|
||||
- cargo test
|
||||
- cargo test --release
|
||||
- cargo doc --release
|
||||
- cd examples/embedded_linux && cargo build && cd ../../
|
||||
- cargo test --all-features --release
|
||||
- cargo doc --all-features --release
|
||||
- cd examples/embedded_linux_epd4in2 && cargo build && cd ../../
|
||||
#- cd ../f3_stm32f30x && cargo build
|
||||
|
||||
after_success:
|
||||
|
|
|
|||
|
|
@ -5,7 +5,11 @@ authors = ["Christoph Groß <christoph.gross@student.uni-tuebingen.de>"]
|
|||
|
||||
|
||||
[features]
|
||||
default = []
|
||||
default = ["epd1in54", "epd2in9", "epd4in2"]
|
||||
|
||||
epd1in54 = []
|
||||
epd2in9 = []
|
||||
epd4in2 = []
|
||||
# Activates the fast LUT for EPD4in2
|
||||
epd4in2_fast_update = []
|
||||
|
||||
|
|
|
|||
28
README.md
28
README.md
|
|
@ -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 | ✕ | ✔ | ✔ | |
|
||||
|
||||
|
|
@ -34,6 +36,28 @@ It's possible with this driver but might lead to ghosting / burn-in effects ther
|
|||
| RST | External reset pin (Low for reset) |
|
||||
| BUSY | Busy state output pin (Low for busy) |
|
||||
|
||||
### Display Configs
|
||||
|
||||
There are two types of Display Configurations used in Wavedshare EPDs, which also needs to be set on the "new" E-Paper Driver HAT.
|
||||
They are also called A and B, but you shouldn't get confused and mix it with the Type A,B,C and D of the various Displays, which just describe different types (colored variants) or new versions. In the Display Config the seperation is most likely due to included fast partial refresh of the displays. In a Tabular form:
|
||||
|
||||
| Type A | Tybe B |
|
||||
| :---: | :---: |
|
||||
| 1.54in (A) | 1.54in (B) |
|
||||
| 2.13in (A) | 1.54in (C) |
|
||||
| 2.13in (D) | 2.13in (B) |
|
||||
| 2.9in (A) | 2.13in (C) |
|
||||
| | 2.7in (A) |
|
||||
| | 2.7in (B) |
|
||||
| | 2.9in (B) |
|
||||
| | 2.9in (C) |
|
||||
| | 4.2in (A) |
|
||||
| | 4.2in (B) |
|
||||
| | 4.2in (C) |
|
||||
| | 7.5in (A) |
|
||||
| | 7.5in (B) |
|
||||
| | 7.5in (C) |
|
||||
|
||||
## TODO's
|
||||
|
||||
- [ ] add more examples (e.g. for f3)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,12 @@ 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,
|
||||
drawing::{Graphics, color::Color},
|
||||
WaveshareInterface,
|
||||
ConnectionInterface
|
||||
};
|
||||
|
||||
use lin_hal::spidev::{self, SpidevOptions};
|
||||
use lin_hal::{Pin, Spidev};
|
||||
|
|
@ -99,7 +104,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).expect("eink inialize error");
|
||||
|
||||
//let mut buffer = [0u8, epd4in2.get_width() / 8 * epd4in2.get_height()];
|
||||
let mut buffer = [0u8; 15000];
|
||||
|
|
@ -29,9 +29,10 @@ impl Color {
|
|||
/// remember: 1 is white, 0 is black
|
||||
/// Color is the color you want to draw with in the foreground
|
||||
pub(crate) fn get_color(input: u8, pos: u8, color: &Color) -> Color {
|
||||
match Color::is_drawable_pixel(input, pos) {
|
||||
true => Color::normal_color(color),
|
||||
false => Color::inverse_color(color)
|
||||
if Color::is_drawable_pixel(input, pos) {
|
||||
Color::normal_color(color)
|
||||
} else {
|
||||
Color::inverse_color(color)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -65,9 +66,10 @@ impl Color {
|
|||
// - black for pixel to draw
|
||||
//
|
||||
//foreground color is the color you want to have in the foreground
|
||||
match Color::is_drawable_pixel(input, pos) {
|
||||
true => Color::normal_color(foreground_color),
|
||||
false => Color::inverse_color(foreground_color)
|
||||
if Color::is_drawable_pixel(input, pos) {
|
||||
Color::normal_color(foreground_color)
|
||||
} else {
|
||||
Color::inverse_color(foreground_color)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -141,7 +141,7 @@ impl<'a> Graphics<'a> {
|
|||
let mut counter = 0;
|
||||
for input_char in input.chars() {
|
||||
self.draw_char(x0 + counter, y0, input_char, font, color);
|
||||
counter += font.get_char_width(input_char) as u16;
|
||||
counter += u16::from(font.get_char_width(input_char));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -163,7 +163,7 @@ impl<'a> Graphics<'a> {
|
|||
for _ in 0..8 {
|
||||
|
||||
self.draw_pixel(
|
||||
x0 + width_counter as u16,
|
||||
x0 + u16::from(width_counter),
|
||||
y0 + row_counter,
|
||||
&Color::get_color(elem, width_counter % 8, color));
|
||||
|
||||
|
|
@ -183,9 +183,9 @@ impl<'a> Graphics<'a> {
|
|||
pub fn draw_char_8x8(&mut self, x0: u16, y0: u16, input: char, color: &Color) {
|
||||
let mut counter = 0;
|
||||
// includes special draw_char instructions as this one is ordered columnwise and not rowwise (first byte == first 8 pixel columnwise)
|
||||
for &elem in font::bitmap_8x8(input).iter() {
|
||||
for &elem in (&font::bitmap_8x8(input)).iter() {
|
||||
for i in 0..8u8 {
|
||||
self.draw_pixel(x0 + counter, y0 + 7 - i as u16, &Color::convert_color(elem, i, color))
|
||||
self.draw_pixel(x0 + counter, y0 + 7 - u16::from(i), &Color::convert_color(elem, i, color))
|
||||
}
|
||||
counter += 1;
|
||||
}
|
||||
|
|
@ -197,10 +197,8 @@ impl<'a> Graphics<'a> {
|
|||
///
|
||||
/// no autobreak line yet
|
||||
pub fn draw_string_8x8(&mut self, x0: u16, y0: u16, input: &str, color: &Color) {
|
||||
let mut counter = 0;
|
||||
for input_char in input.chars() {
|
||||
self.draw_char_8x8(x0 + counter*8, y0, input_char, color);
|
||||
counter += 1;
|
||||
for (counter, input_char) in input.chars().enumerate() {
|
||||
self.draw_char_8x8(x0 + counter as u16*8, y0, input_char, color);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,306 @@
|
|||
//! 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;
|
||||
const DEFAULT_BACKGROUND_COLOR: Color = Color::White;
|
||||
|
||||
use hal::{
|
||||
blocking::{
|
||||
spi::Write,
|
||||
delay::*
|
||||
},
|
||||
digital::*
|
||||
};
|
||||
|
||||
use type_a::{
|
||||
LUT_FULL_UPDATE,
|
||||
LUT_PARTIAL_UPDATE,
|
||||
command::Command
|
||||
};
|
||||
|
||||
use drawing::color::Color;
|
||||
|
||||
|
||||
|
||||
|
||||
use interface::*;
|
||||
|
||||
use interface::connection_interface::ConnectionInterface;
|
||||
|
||||
|
||||
|
||||
|
||||
/// EPD1in54 driver
|
||||
///
|
||||
pub struct EPD1in54<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> EPD1in54<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 EPD1in54<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 mut epd = EPD1in54 {interface, background_color: DEFAULT_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> EPD1in54<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)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -19,6 +19,9 @@
|
|||
//! epd4in2.sleep();
|
||||
//! ```
|
||||
|
||||
const WIDTH: u16 = 128;
|
||||
const HEIGHT: u16 = 296;
|
||||
const DEFAULT_BACKGROUND_COLOR: Color = Color::White;
|
||||
|
||||
use hal::{
|
||||
blocking::{
|
||||
|
|
@ -28,13 +31,17 @@ use hal::{
|
|||
digital::*
|
||||
};
|
||||
|
||||
mod constants;
|
||||
use self::constants::*;
|
||||
|
||||
use type_a::{
|
||||
LUT_FULL_UPDATE,
|
||||
LUT_PARTIAL_UPDATE,
|
||||
command::Command
|
||||
};
|
||||
|
||||
use drawing::color::Color;
|
||||
|
||||
pub mod command;
|
||||
pub use self::command::Command;
|
||||
|
||||
|
||||
|
||||
use interface::*;
|
||||
|
||||
|
|
@ -42,67 +49,58 @@ use interface::connection_interface::ConnectionInterface;
|
|||
|
||||
|
||||
|
||||
|
||||
/// EPD2in9 driver
|
||||
///
|
||||
pub struct EPD2in9<SPI, CS, BUSY, DC, RST, D> {
|
||||
pub struct EPD2in9<SPI, CS, BUSY, DataCommand, RST, Delay> {
|
||||
/// SPI
|
||||
interface: ConnectionInterface<SPI, CS, BUSY, DC, RST, D>,
|
||||
/// Width
|
||||
width: u16,
|
||||
/// Height
|
||||
height: u16,
|
||||
interface: ConnectionInterface<SPI, CS, BUSY, DataCommand, RST, Delay>,
|
||||
/// EPD (width, height)
|
||||
//epd: EPD,
|
||||
/// Color
|
||||
background_color: Color,
|
||||
}
|
||||
|
||||
impl<SPI, CS, BUSY, DC, RST, D, E> EPD2in9<SPI, CS, BUSY, DC, RST, D>
|
||||
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,
|
||||
DC: OutputPin,
|
||||
DataCommand: OutputPin,
|
||||
RST: OutputPin,
|
||||
D: DelayUs<u16> + DelayMs<u16>
|
||||
Delay: DelayUs<u16> + DelayMs<u16>
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
impl<SPI, CS, BUSY, DC, RST, D, E> WaveshareInterface<SPI, CS, BUSY, DC, RST, D, E> for EPD2in9<SPI, CS, BUSY, DC, RST, D>
|
||||
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,
|
||||
DC: OutputPin,
|
||||
DataCommand: OutputPin,
|
||||
RST: OutputPin,
|
||||
D: DelayUs<u16> + DelayMs<u16>,
|
||||
Delay: DelayUs<u16> + DelayMs<u16>,
|
||||
{
|
||||
|
||||
fn get_width(&self) -> u16 {
|
||||
self.width
|
||||
WIDTH
|
||||
}
|
||||
|
||||
fn get_height(&self) -> u16 {
|
||||
self.height
|
||||
HEIGHT
|
||||
}
|
||||
|
||||
|
||||
fn new(
|
||||
spi: SPI,
|
||||
cs: CS,
|
||||
busy: BUSY,
|
||||
dc: DC,
|
||||
rst: RST,
|
||||
delay: D
|
||||
) -> 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 interface = ConnectionInterface::new(spi, cs, busy, dc, rst, delay);
|
||||
|
||||
let background_color = Color::White;
|
||||
|
||||
let mut epd = EPD2in9 {interface, width, height, background_color};
|
||||
let mut epd = EPD2in9 {interface, background_color: DEFAULT_BACKGROUND_COLOR};
|
||||
|
||||
|
||||
epd.init()?;
|
||||
|
|
@ -297,9 +295,9 @@ where
|
|||
}
|
||||
|
||||
//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_manual(&mut self, buffer: &[u8]) -> Result<(), E> {
|
||||
// self.set_lut_helper(buffer)
|
||||
//}
|
||||
|
||||
|
||||
fn set_lut_helper(&mut self, buffer: &[u8]) -> Result<(), E> {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use interface;
|
|||
#[allow(dead_code)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Command {
|
||||
pub(crate) enum Command {
|
||||
/// Set Resolution, LUT selection, BWR pixels, gate scan direction, source shift direction, booster switch, soft reset
|
||||
PANEL_SETTING = 0x00,
|
||||
/// selecting internal and external power
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@
|
|||
use hal::{
|
||||
blocking::{delay::*, spi::Write},
|
||||
digital::*,
|
||||
spi::{Mode, Phase, Polarity},
|
||||
};
|
||||
|
||||
use interface::{connection_interface::ConnectionInterface, WaveshareInterface};
|
||||
|
|
@ -61,19 +60,13 @@ use self::constants::*;
|
|||
use drawing::color::Color;
|
||||
|
||||
pub mod command;
|
||||
pub use self::command::Command;
|
||||
use self::command::Command;
|
||||
|
||||
//TODO: test spi mode
|
||||
/// SPI mode -
|
||||
/// For more infos see [Requirements: SPI](index.html#spi)
|
||||
pub const SPI_MODE: Mode = Mode {
|
||||
phase: Phase::CaptureOnFirstTransition,
|
||||
polarity: Polarity::IdleLow,
|
||||
};
|
||||
|
||||
/// EPD4in2 driver
|
||||
///
|
||||
pub struct EPD4in2<SPI, CS, BUSY, DC, RST, D> {
|
||||
pub struct EPD4in2<SPI, CS, BUSY, DC, RST, D>
|
||||
{
|
||||
/// Connection Interface
|
||||
interface: ConnectionInterface<SPI, CS, BUSY, DC, RST, D>,
|
||||
/// Width
|
||||
|
|
@ -84,15 +77,17 @@ pub struct EPD4in2<SPI, CS, BUSY, DC, RST, D> {
|
|||
color: Color,
|
||||
}
|
||||
|
||||
impl<SPI, CS, BUSY, DC, RST, D, E> WaveshareInterface<SPI, CS, BUSY, DC, RST, D, E>
|
||||
for EPD4in2<SPI, CS, BUSY, DC, RST, D>
|
||||
where
|
||||
SPI: Write<u8, Error = E>,
|
||||
|
||||
|
||||
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 = SpiError>,
|
||||
CS: OutputPin,
|
||||
BUSY: InputPin,
|
||||
DC: OutputPin,
|
||||
DataCommand: OutputPin,
|
||||
RST: OutputPin,
|
||||
D: DelayUs<u16> + DelayMs<u16>,
|
||||
Delay: DelayUs<u16> + DelayMs<u16>,
|
||||
{
|
||||
fn get_width(&self) -> u16 {
|
||||
self.width
|
||||
|
|
@ -117,11 +112,11 @@ where
|
|||
///
|
||||
/// epd4in2.sleep();
|
||||
/// ```
|
||||
fn new(spi: SPI, cs: CS, busy: BUSY, dc: DC, rst: RST, delay: D) -> Result<Self, E> {
|
||||
fn new(interface: ConnectionInterface<SPI, CS, BUSY, DataCommand, RST, Delay>) -> Result<Self, SpiError> {
|
||||
let width = WIDTH as u16;
|
||||
let height = HEIGHT as u16;
|
||||
|
||||
let interface = ConnectionInterface::new(spi, cs, busy, dc, rst, delay);
|
||||
|
||||
let color = Color::White;
|
||||
let mut epd = EPD4in2 {
|
||||
interface,
|
||||
|
|
@ -135,7 +130,7 @@ where
|
|||
Ok(epd)
|
||||
}
|
||||
|
||||
fn init(&mut self) -> Result<(), E> {
|
||||
fn init(&mut self) -> Result<(), SpiError> {
|
||||
// reset the device
|
||||
self.reset();
|
||||
|
||||
|
|
@ -182,7 +177,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn sleep(&mut self) -> Result<(), E> {
|
||||
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
|
||||
|
|
@ -211,7 +206,7 @@ where
|
|||
self.interface.delay_ms(delay)
|
||||
}
|
||||
|
||||
fn update_frame(&mut self, buffer: &[u8]) -> Result<(), E> {
|
||||
fn update_frame(&mut self, buffer: &[u8]) -> Result<(), SpiError> {
|
||||
let color_value = self.color.get_byte_value();
|
||||
|
||||
self.send_resolution()?;
|
||||
|
|
@ -247,7 +242,8 @@ where
|
|||
y: u16,
|
||||
width: u16,
|
||||
height: u16,
|
||||
) -> Result<(), E> {
|
||||
) -> Result<(), SpiError> {
|
||||
|
||||
if buffer.len() as u16 != width / 8 * height {
|
||||
//TODO: panic!! or sth like that
|
||||
//return Err("Wrong buffersize");
|
||||
|
|
@ -283,13 +279,13 @@ where
|
|||
self.send_command(Command::PARTIAL_OUT)
|
||||
}
|
||||
|
||||
fn update_and_display_frame(&mut self, buffer: &[u8]) -> Result<(), E>{
|
||||
fn update_and_display_frame(&mut self, buffer: &[u8]) -> Result<(), SpiError>{
|
||||
self.update_frame(buffer)?;
|
||||
self.display_frame()
|
||||
}
|
||||
|
||||
|
||||
fn display_frame(&mut self) -> Result<(), E> {
|
||||
fn display_frame(&mut self) -> Result<(), SpiError> {
|
||||
self.send_command(Command::DISPLAY_REFRESH)?;
|
||||
|
||||
self.wait_until_idle();
|
||||
|
|
@ -299,7 +295,7 @@ where
|
|||
// TODO: add this abstraction function
|
||||
// fn update_and_display_frame(&mut self, buffer: &[u8]) -> Result<(), E>;
|
||||
|
||||
fn clear_frame(&mut self) -> Result<(), E> {
|
||||
fn clear_frame(&mut self) -> Result<(), SpiError> {
|
||||
self.send_resolution()?;
|
||||
|
||||
let size = self.width / 8 * self.height;
|
||||
|
|
@ -327,24 +323,24 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<SPI, CS, BUSY, DC, RST, D, E> 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 = E>,
|
||||
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<(), E> {
|
||||
fn send_command(&mut self, command: Command) -> Result<(), SpiError> {
|
||||
self.interface.send_command(command)
|
||||
}
|
||||
|
||||
fn send_data(&mut self, val: u8) -> Result<(), E> {
|
||||
fn send_data(&mut self, val: u8) -> Result<(), SpiError> {
|
||||
self.interface.send_data(val)
|
||||
}
|
||||
|
||||
fn send_multiple_data(&mut self, data: &[u8]) -> Result<(), E> {
|
||||
fn send_multiple_data(&mut self, data: &[u8]) -> Result<(), SpiError> {
|
||||
self.interface.send_multiple_data(data)
|
||||
}
|
||||
|
||||
|
|
@ -352,7 +348,7 @@ where
|
|||
self.interface.wait_until_idle(true)
|
||||
}
|
||||
|
||||
fn send_resolution(&mut self) -> Result<(), E> {
|
||||
fn send_resolution(&mut self) -> Result<(), SpiError> {
|
||||
let w = self.get_width();
|
||||
let h = self.get_height();
|
||||
|
||||
|
|
@ -365,7 +361,7 @@ where
|
|||
|
||||
/// Fill the look-up table for the EPD
|
||||
//TODO: make public?
|
||||
fn set_lut(&mut self) -> Result<(), E> {
|
||||
fn set_lut(&mut self) -> Result<(), SpiError> {
|
||||
self.set_lut_helper(&LUT_VCOM0, &LUT_WW, &LUT_BW, &LUT_WB, &LUT_BB)
|
||||
}
|
||||
|
||||
|
|
@ -374,7 +370,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<(), E> {
|
||||
fn set_lut_quick(&mut self) -> Result<(), SpiError> {
|
||||
self.set_lut_helper(
|
||||
&LUT_VCOM0_QUICK,
|
||||
&LUT_WW_QUICK,
|
||||
|
|
@ -391,7 +387,7 @@ where
|
|||
lut_bw: &[u8],
|
||||
lut_wb: &[u8],
|
||||
lut_bb: &[u8],
|
||||
) -> Result<(), E> {
|
||||
) -> Result<(), SpiError> {
|
||||
// LUT VCOM
|
||||
self.send_command(Command::LUT_FOR_VCOM)?;
|
||||
self.send_multiple_data(lut_vcom)?;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -26,16 +26,16 @@ pub(crate) struct ConnectionInterface<SPI, CS, BUSY, DC, RST, D> {
|
|||
}
|
||||
|
||||
|
||||
impl<SPI, CS, BUSY, DC, RST, D, E> ConnectionInterface<SPI, CS, BUSY, DC, RST, D>
|
||||
impl<SPI, CS, BUSY, DataCommand, RST, Delay, ErrorSpeziale> ConnectionInterface<SPI, CS, BUSY, DataCommand, RST, Delay>
|
||||
where
|
||||
SPI: Write<u8, Error = E>,
|
||||
SPI: Write<u8, Error = ErrorSpeziale>,
|
||||
CS: OutputPin,
|
||||
BUSY: InputPin,
|
||||
DC: OutputPin,
|
||||
DataCommand: OutputPin,
|
||||
RST: OutputPin,
|
||||
D: DelayUs<u16> + DelayMs<u16>,
|
||||
Delay: DelayUs<u16> + DelayMs<u16>,
|
||||
{
|
||||
pub(crate) fn new(spi: SPI, cs: CS, busy: BUSY, dc: DC, rst: RST, delay: D) -> Self {
|
||||
pub fn new(spi: SPI, cs: CS, busy: BUSY, dc: DataCommand, rst: RST, delay: Delay) -> Self {
|
||||
ConnectionInterface {spi, cs, busy, dc, rst, delay }
|
||||
}
|
||||
|
||||
|
|
@ -44,7 +44,7 @@ where
|
|||
/// Enables direct interaction with the device with the help of [send_data()](ConnectionInterface::send_data())
|
||||
/// Should rarely be needed!
|
||||
/// //TODO: make public?
|
||||
pub(crate) fn send_command<T: Command>(&mut self, command: T) -> Result<(), E> {
|
||||
pub(crate) fn send_command<T: Command>(&mut self, command: T) -> Result<(), ErrorSpeziale> {
|
||||
// low for commands
|
||||
self.dc.set_low();
|
||||
|
||||
|
|
@ -60,7 +60,7 @@ where
|
|||
///
|
||||
/// Should rarely be needed!
|
||||
/// //TODO: make public?
|
||||
pub(crate) fn send_data(&mut self, val: u8) -> Result<(), E> {
|
||||
pub(crate) fn send_data(&mut self, val: u8) -> Result<(), ErrorSpeziale> {
|
||||
// high for data
|
||||
self.dc.set_high();
|
||||
|
||||
|
|
@ -76,7 +76,7 @@ where
|
|||
///
|
||||
/// Should rarely be needed!
|
||||
/// //TODO: make public?
|
||||
pub(crate) fn send_data_x_times(&mut self, val: u8, repetitions: u16) -> Result<(), E> {
|
||||
pub(crate) fn send_data_x_times(&mut self, val: u8, repetitions: u16) -> Result<(), ErrorSpeziale> {
|
||||
// high for data
|
||||
self.dc.set_high();
|
||||
|
||||
|
|
@ -95,7 +95,7 @@ where
|
|||
///
|
||||
/// Should rarely be needed!
|
||||
/// //TODO: make public?
|
||||
pub(crate) fn send_multiple_data(&mut self, data: &[u8]) -> Result<(), E> {
|
||||
pub(crate) fn send_multiple_data(&mut self, data: &[u8]) -> Result<(), ErrorSpeziale> {
|
||||
// high for data
|
||||
self.dc.set_high();
|
||||
|
||||
|
|
@ -106,9 +106,9 @@ where
|
|||
}
|
||||
|
||||
// spi write helper/abstraction function
|
||||
pub(crate) fn with_cs<F>(&mut self, f: F) -> Result<(), E>
|
||||
pub(crate) fn with_cs<F>(&mut self, f: F) -> Result<(), ErrorSpeziale>
|
||||
where
|
||||
F: FnOnce(&mut Self) -> Result<(), E>,
|
||||
F: FnOnce(&mut Self) -> Result<(), ErrorSpeziale>,
|
||||
{
|
||||
// activate spi with cs low
|
||||
self.cs.set_low();
|
||||
|
|
@ -129,8 +129,8 @@ where
|
|||
///
|
||||
/// is_busy_low
|
||||
///
|
||||
/// - TRUE for epd4in2, epd1in54, epd2in13, epd2in7, epd5in83, epd7in5
|
||||
/// - FALSE for epd2in9
|
||||
/// - TRUE for epd4in2, epd2in13, epd2in7, epd5in83, epd7in5
|
||||
/// - FALSE for epd2in9, epd1in54 (for all Display Type A ones?)
|
||||
///
|
||||
/// Most likely there was a mistake with the 2in9 busy connection
|
||||
pub(crate) fn wait_until_idle(&mut self, is_busy_low: bool) {
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@ use hal::{
|
|||
};
|
||||
use core::marker::Sized;
|
||||
|
||||
|
||||
use drawing::color::Color;
|
||||
|
||||
/// Interface for the physical connection between display and the controlling device
|
||||
pub mod connection_interface;
|
||||
use self::connection_interface::ConnectionInterface;
|
||||
|
||||
|
||||
/// All commands need to have this trait which gives the address of the command
|
||||
|
|
@ -21,6 +21,8 @@ pub(crate) trait Command {
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//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> {
|
||||
|
|
@ -30,14 +32,14 @@ trait LUTSupport<Error> {
|
|||
}
|
||||
|
||||
|
||||
pub trait WaveshareInterface<SPI, CS, BUSY, DC, RST, D, E>
|
||||
pub trait WaveshareInterface<SPI, CS, BUSY, DataCommand, RST, Delay, Error>
|
||||
where
|
||||
SPI: Write<u8, Error = E>,
|
||||
SPI: Write<u8>,
|
||||
CS: OutputPin,
|
||||
BUSY: InputPin,
|
||||
DC: OutputPin,
|
||||
DataCommand: OutputPin,
|
||||
RST: OutputPin,
|
||||
D: DelayUs<u16> + DelayMs<u16>,
|
||||
Delay: DelayUs<u16> + DelayMs<u16>,
|
||||
{
|
||||
/// Get the width of the display
|
||||
fn get_width(&self) -> u16;
|
||||
|
|
@ -49,13 +51,8 @@ pub trait WaveshareInterface<SPI, CS, BUSY, DC, RST, D, E>
|
|||
///
|
||||
/// This already initialises the device. That means [init()](WaveshareInterface::init()) isn't needed directly afterwards
|
||||
fn new(
|
||||
spi: SPI,
|
||||
cs: CS,
|
||||
busy: BUSY,
|
||||
dc: DC,
|
||||
rst: RST,
|
||||
delay: D
|
||||
) -> Result<Self, E>
|
||||
interface: ConnectionInterface<SPI, CS, BUSY, DataCommand, RST, Delay>
|
||||
) -> Result<Self, Error>
|
||||
where Self: Sized;
|
||||
|
||||
/// This initialises the EPD and powers it up
|
||||
|
|
@ -65,13 +62,13 @@ pub trait WaveshareInterface<SPI, CS, BUSY, DC, RST, D, E>
|
|||
/// This function calls [reset()](WaveshareInterface::reset()),
|
||||
/// so you don't need to call reset your self when trying to wake your device up
|
||||
/// after setting it to sleep.
|
||||
fn init(&mut self) -> Result<(), E>;
|
||||
fn init(&mut self) -> Result<(), Error>;
|
||||
|
||||
|
||||
// void DisplayFrame(const unsigned char* frame_buffer);
|
||||
/// Transmit a full frame to the SRAM of the DPD
|
||||
///
|
||||
fn update_frame(&mut self, buffer: &[u8]) -> Result<(), E>;
|
||||
fn update_frame(&mut self, buffer: &[u8]) -> Result<(), Error>;
|
||||
|
||||
//TODO: is dtm always used?
|
||||
/// Transmit partial data to the SRAM of the EPD,
|
||||
|
|
@ -81,18 +78,18 @@ pub trait WaveshareInterface<SPI, CS, BUSY, DC, RST, D, E>
|
|||
/// Normally it should be dtm2, so use false
|
||||
///
|
||||
/// BUFFER needs to be of size: w / 8 * l !
|
||||
fn update_partial_frame(&mut self, buffer: &[u8], x: u16, y: u16, width: u16, height: u16) -> Result<(), E>;
|
||||
fn update_partial_frame(&mut self, buffer: &[u8], x: u16, y: u16, width: u16, height: u16) -> Result<(), Error>;
|
||||
|
||||
/// Displays the frame data from SRAM
|
||||
fn display_frame(&mut self) -> Result<(), E>;
|
||||
fn display_frame(&mut self) -> Result<(), Error>;
|
||||
|
||||
// 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<(), Error>;
|
||||
|
||||
/// Clears the frame from the buffer
|
||||
///
|
||||
/// Uses the chosen background color
|
||||
fn clear_frame(&mut self) -> Result<(), E>;
|
||||
fn clear_frame(&mut self) -> Result<(), Error>;
|
||||
|
||||
/// Sets the backgroundcolor for various commands like [clear_frame()](WaveshareInterface::clear_frame())
|
||||
fn set_background_color(&mut self, color: Color);
|
||||
|
|
@ -104,7 +101,7 @@ pub trait WaveshareInterface<SPI, CS, BUSY, DC, RST, D, E>
|
|||
/// But you can also use [reset()](WaveshareInterface::reset()) to awaken.
|
||||
/// But as you need to power it up once more anyway you can also just directly use [init()](WaveshareInterface::init()) for resetting
|
||||
/// and initialising which already contains the reset
|
||||
fn sleep(&mut self) -> Result<(), E>;
|
||||
fn sleep(&mut self) -> Result<(), Error>;
|
||||
|
||||
/// Resets the device.
|
||||
///
|
||||
|
|
|
|||
28
src/lib.rs
28
src/lib.rs
|
|
@ -51,14 +51,32 @@ use hal::{
|
|||
};
|
||||
|
||||
pub mod drawing;
|
||||
pub mod epd4in2;
|
||||
|
||||
mod interface;
|
||||
pub use interface::{
|
||||
WaveshareInterface,
|
||||
connection_interface::ConnectionInterface};
|
||||
|
||||
#[cfg(feature="epd4in2")]
|
||||
mod epd4in2;
|
||||
#[cfg(feature="epd4in2")]
|
||||
pub use epd4in2::EPD4in2;
|
||||
|
||||
#[cfg(feature="epd1in54")]
|
||||
mod epd1in54;
|
||||
#[cfg(feature="epd1in54")]
|
||||
pub use epd1in54::EPD1in54;
|
||||
|
||||
|
||||
#[cfg(feature="epd2in9")]
|
||||
mod epd2in9;
|
||||
///2in9 eink
|
||||
#[cfg(feature="epd2in9")]
|
||||
///2in9 eink
|
||||
pub use epd2in9::EPD2in9;
|
||||
|
||||
pub mod epd2in9;
|
||||
|
||||
pub mod interface;
|
||||
|
||||
#[cfg(any(feature="epd1in54", feature="epd2in9"))]
|
||||
pub mod type_a;
|
||||
|
||||
|
||||
//TODO: test spi mode
|
||||
|
|
|
|||
|
|
@ -1,19 +1,17 @@
|
|||
//! SPI Commands for the Waveshare 2.9" E-Ink Display
|
||||
//! SPI Commands for the Waveshare 2.9" and 1.54" E-Ink Display
|
||||
|
||||
use interface;
|
||||
|
||||
|
||||
/// EPD2IN9 commands
|
||||
/// EPD1in54 and EPD2IN9 commands
|
||||
///
|
||||
/// Should rarely (never?) be needed directly.
|
||||
///
|
||||
/// For more infos about the addresses and what they are doing look into the pdfs
|
||||
///
|
||||
/// The description of the single commands is mostly taken from IL0398.pdf
|
||||
//#[allow(dead_code)]
|
||||
#[allow(dead_code)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Command {
|
||||
pub(crate) enum Command {
|
||||
/// Driver Output control
|
||||
/// 3 Databytes:
|
||||
/// A[7:0]
|
||||
|
|
@ -28,6 +26,7 @@ pub enum Command {
|
|||
/// 1.. C[6:0]
|
||||
/// Default: A[7:0] = 0xCF, B[7:0] = 0xCE, C[7:0] = 0x8D
|
||||
BOOSTER_SOFT_START_CONTROL = 0x0C,
|
||||
GATE_SCAN_START_POSITION = 0x0F,
|
||||
//TODO: useful?
|
||||
// GATE_SCAN_START_POSITION = 0x0F,
|
||||
/// Deep Sleep Mode Control
|
||||
|
|
@ -92,8 +91,8 @@ mod tests {
|
|||
fn command_addr() {
|
||||
assert_eq!(Command::DRIVER_OUTPUT_CONTROL.address(), 0x01);
|
||||
|
||||
//assert_eq!(Command::PANEL_SETTING.addr(), 0x00);
|
||||
assert_eq!(Command::SET_RAM_X_ADDRESS_COUNTER.address(), 0x4E);
|
||||
|
||||
//assert_eq!(Command::DISPLAY_REFRESH.addr(), 0x12);
|
||||
assert_eq!(Command::TERMINATE_COMMANDS_AND_FRAME_WRITE.address(), 0xFF);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
pub(crate) const WIDTH: u16 = 128;
|
||||
pub(crate) const HEIGHT: u16 = 296;
|
||||
pub(crate) mod command;
|
||||
|
||||
// Original Waveforms from Waveshare
|
||||
pub(crate) const LUT_FULL_UPDATE: [u8; 30] =[
|
||||
|
|
@ -14,4 +13,4 @@ pub(crate) const LUT_PARTIAL_UPDATE: [u8; 30] =[
|
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x13, 0x14, 0x44, 0x12,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
];
|
||||
];
|
||||
Loading…
Reference in New Issue