diff --git a/Cargo.toml b/Cargo.toml index 0e7779a..a384076 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,8 +24,6 @@ graphics = ["embedded-graphics"] epd1in54 = [] epd2in9 = [] epd4in2 = [] -# Activates the fast LUT for EPD4in2 -epd4in2_fast_update = [] [dependencies.embedded-graphics] optional = true diff --git a/examples/embedded_linux_epd1in54/src/main.rs b/examples/embedded_linux_epd1in54/src/main.rs index f3325d2..7d9e5b1 100644 --- a/examples/embedded_linux_epd1in54/src/main.rs +++ b/examples/embedded_linux_epd1in54/src/main.rs @@ -133,7 +133,7 @@ fn run() -> Result<(), std::io::Error> { // a quickly moving `Hello World!` display.set_rotation(DisplayRotation::Rotate0); - epd.set_lut_quick(&mut spi).expect("SET LUT QUICK error"); + epd.set_lut(&mut spi, Some(RefreshLUT::QUICK)).expect("SET LUT QUICK error"); let limit = 20; for i in 0..limit { println!("Moving Hello World. Loop {} from {}", (i+1), limit); diff --git a/examples/embedded_linux_epd2in9/src/main.rs b/examples/embedded_linux_epd2in9/src/main.rs index 97d1d84..5288fd4 100644 --- a/examples/embedded_linux_epd2in9/src/main.rs +++ b/examples/embedded_linux_epd2in9/src/main.rs @@ -92,7 +92,7 @@ fn run() -> Result<(), std::io::Error> { let mut buffer = Buffer2in9::default(); let mut display = Display::new(epd.width(), epd.height(), &mut buffer.buffer); epd.update_frame(&mut spi, display.buffer()).unwrap(); - epd.display_frame(&mut spi); + epd.display_frame(&mut spi).expect("display frame x03"); display.set_rotation(DisplayRotation::Rotate0); display.draw( @@ -137,7 +137,7 @@ fn run() -> Result<(), std::io::Error> { // a quickly moving `Hello World!` display.set_rotation(DisplayRotation::Rotate0); - epd.set_lut_quick(&mut spi).expect("SET LUT QUICK error"); + epd.set_lut(&mut spi, Some(RefreshLUT::QUICK)).expect("SET LUT QUICK error"); let limit = 20; for i in 0..limit { println!("Moving Hello World. Loop {} from {}", (i+1), limit); diff --git a/src/epd1in54/mod.rs b/src/epd1in54/mod.rs index 019ca79..6ea0ab1 100644 --- a/src/epd1in54/mod.rs +++ b/src/epd1in54/mod.rs @@ -50,7 +50,7 @@ use type_a::{ use color::Color; -use traits::{WaveshareDisplay}; +use traits::{WaveshareDisplay, RefreshLUT}; use interface::DisplayInterface; @@ -62,10 +62,10 @@ pub use epd1in54::graphics::Buffer1in54BlackWhite as Buffer1in54; pub struct EPD1in54 { /// SPI interface: DisplayInterface, - /// EPD (width, height) - //epd: EPD, /// Color background_color: Color, + /// Refresh LUT + refresh: RefreshLUT, } impl EPD1in54 @@ -110,7 +110,7 @@ where // -> address: x increment, y increment, address counter is updated in x direction self.interface.cmd_with_data(spi, Command::DATA_ENTRY_MODE_SETTING, &[0x03])?; - self.set_lut(spi) + self.set_lut(spi, None) } } @@ -140,6 +140,7 @@ where let mut epd = EPD1in54 { interface, background_color: DEFAULT_BACKGROUND_COLOR, + refresh: RefreshLUT::FULL }; epd.init(spi, delay)?; @@ -217,6 +218,20 @@ where fn background_color(&self) -> &Color { &self.background_color } + + fn set_lut(&mut self, spi: &mut SPI, refresh_rate: Option) -> Result<(), SPI::Error> { + if let Some(refresh_lut) = refresh_rate { + self.refresh = refresh_lut; + } + match self.refresh { + RefreshLUT::FULL => { + self.set_lut_helper(spi, &LUT_FULL_UPDATE) + }, + RefreshLUT::QUICK => { + self.set_lut_helper(spi, &LUT_PARTIAL_UPDATE) + } + } + } } impl EPD1in54 @@ -284,21 +299,6 @@ where Ok(()) } - /// Uses the slower full update - pub fn set_lut(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { - self.set_lut_helper(spi, &LUT_FULL_UPDATE) - } - - /// Uses the quick partial refresh - pub fn set_lut_quick(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { - self.set_lut_helper(spi, &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, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> { assert!(buffer.len() == 30); self.interface.cmd_with_data(spi, Command::WRITE_LUT_REGISTER, buffer) diff --git a/src/epd2in9/mod.rs b/src/epd2in9/mod.rs index dcdf1a7..0383bd4 100644 --- a/src/epd2in9/mod.rs +++ b/src/epd2in9/mod.rs @@ -63,10 +63,10 @@ pub use epd2in9::graphics::Buffer2in9; pub struct EPD2in9 { /// SPI interface: DisplayInterface, - /// EPD (width, height) - //epd: EPD, /// Color background_color: Color, + /// Refresh LUT + refresh: RefreshLUT, } impl EPD2in9 @@ -107,7 +107,7 @@ where // -> address: x increment, y increment, address counter is updated in x direction self.interface.cmd_with_data(spi, Command::DATA_ENTRY_MODE_SETTING, &[0x03])?; - self.set_lut(spi) + self.set_lut(spi, None) } } @@ -137,6 +137,7 @@ where let mut epd = EPD2in9 { interface, background_color: DEFAULT_BACKGROUND_COLOR, + refresh: RefreshLUT::FULL, }; epd.init(spi, delay)?; @@ -206,7 +207,6 @@ where ) } - /// 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; } @@ -214,6 +214,20 @@ where fn background_color(&self) -> &Color { &self.background_color } + + fn set_lut(&mut self, spi: &mut SPI, refresh_rate: Option) -> Result<(), SPI::Error> { + if let Some(refresh_lut) = refresh_rate { + self.refresh = refresh_lut; + } + match self.refresh { + RefreshLUT::FULL => { + self.set_lut_helper(spi, &LUT_FULL_UPDATE) + }, + RefreshLUT::QUICK => { + self.set_lut_helper(spi, &LUT_PARTIAL_UPDATE) + } + } + } } impl EPD2in9 @@ -228,7 +242,7 @@ where self.interface.wait_until_idle(false); } - pub(crate) fn use_full_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { + fn use_full_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { // choose full frame/ram self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1)?; @@ -236,7 +250,7 @@ where self.set_ram_counter(spi, 0, 0) } - pub(crate) fn set_ram_area( + fn set_ram_area( &mut self, spi: &mut SPI, start_x: u32, @@ -261,7 +275,7 @@ where ) } - pub(crate) fn set_ram_counter(&mut self, spi: &mut SPI, x: u32, y: u32) -> Result<(), SPI::Error> { + fn set_ram_counter(&mut self, spi: &mut SPI, x: u32, y: u32) -> Result<(), SPI::Error> { // 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.cmd_with_data(spi, Command::SET_RAM_X_ADDRESS_COUNTER, &[(x >> 3) as u8])?; @@ -273,21 +287,6 @@ where Ok(()) } - /// Uses the slower full update - pub fn set_lut(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { - self.set_lut_helper(spi, &LUT_FULL_UPDATE) - } - - /// Uses the quick partial refresh - pub fn set_lut_quick(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { - self.set_lut_helper(spi, &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, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> { assert!(buffer.len() == 30); self.interface.cmd_with_data(spi, Command::WRITE_LUT_REGISTER, buffer) diff --git a/src/epd4in2/constants.rs b/src/epd4in2/constants.rs index 16423e3..e794d5f 100644 --- a/src/epd4in2/constants.rs +++ b/src/epd4in2/constants.rs @@ -15,8 +15,7 @@ pub(crate) const LUT_VCOM0: [u8; 44] = [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; -#[allow(dead_code)] -#[cfg(feature = "epd4in2_fast_update")] + pub(crate) const LUT_VCOM0_QUICK: [u8; 44] = [ 0x00, 0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -38,8 +37,7 @@ pub(crate) const LUT_WW: [u8; 42] =[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; -#[allow(dead_code)] -#[cfg(feature = "epd4in2_fast_update")] + pub(crate) const LUT_WW_QUICK: [u8; 42] =[ 0xA0, 0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -61,8 +59,7 @@ pub(crate) const LUT_BW: [u8; 42] =[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; -#[allow(dead_code)] -#[cfg(feature = "epd4in2_fast_update")] + pub(crate) const LUT_BW_QUICK: [u8; 42] =[ 0xA0, 0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -84,8 +81,7 @@ pub(crate) const LUT_BB: [u8; 42] =[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; -#[allow(dead_code)] -#[cfg(feature = "epd4in2_fast_update")] + pub(crate) const LUT_BB_QUICK: [u8; 42] =[ 0x50, 0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -107,8 +103,7 @@ pub(crate) const LUT_WB: [u8; 42] =[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; -#[allow(dead_code)] -#[cfg(feature = "epd4in2_fast_update")] + pub(crate) const LUT_WB_QUICK: [u8; 42] =[ 0x50, 0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, diff --git a/src/epd4in2/mod.rs b/src/epd4in2/mod.rs index f45869d..db4e244 100644 --- a/src/epd4in2/mod.rs +++ b/src/epd4in2/mod.rs @@ -51,11 +51,11 @@ use hal::{ digital::*, }; -use traits::{WaveshareDisplay, InternalWiAdditions}; +use traits::{WaveshareDisplay, InternalWiAdditions, RefreshLUT}; use interface::DisplayInterface; //The Lookup Tables for the Display -pub(crate) mod constants; //TODO: Limit to crate::drawing +mod constants; //TODO: Limit to crate::drawing pub use self::constants::*; use color::Color; @@ -74,6 +74,8 @@ pub struct EPD4in2 { interface: DisplayInterface, /// Background Color color: Color, + /// Refresh LUT + refresh: RefreshLUT, } @@ -113,7 +115,7 @@ where // 3A 100HZ 29 150Hz 39 200HZ 31 171HZ DEFAULT: 3c 50Hz self.cmd_with_data(spi, Command::PLL_CONTROL, &[0x3A])?; - self.set_lut(spi)?; + self.set_lut(spi, None)?; Ok(()) } @@ -151,6 +153,7 @@ where let mut epd = EPD4in2 { interface, color, + refresh: RefreshLUT::FULL }; epd.init(spi, delay)?; @@ -270,7 +273,6 @@ where ) } - /// Sets the backgroundcolor for various commands like [WaveshareInterface::clear_frame()](clear_frame()) fn set_background_color(&mut self, color: Color) { self.color = color; } @@ -286,6 +288,27 @@ where fn height(&self) -> u32 { HEIGHT } + + fn set_lut(&mut self, spi: &mut SPI, refresh_rate: Option) -> Result<(), SPI::Error> { + if let Some(refresh_lut) = refresh_rate { + self.refresh = refresh_lut; + } + match self.refresh { + RefreshLUT::FULL => { + self.set_lut_helper(spi, &LUT_VCOM0, &LUT_WW, &LUT_BW, &LUT_WB, &LUT_BB) + }, + RefreshLUT::QUICK => { + self.set_lut_helper( + spi, + &LUT_VCOM0_QUICK, + &LUT_WW_QUICK, + &LUT_BW_QUICK, + &LUT_WB_QUICK, + &LUT_BB_QUICK, + ) + } + } + } } impl EPD4in2 @@ -323,28 +346,6 @@ where self.send_data(spi, &[h as u8]) } - /// Fill the look-up table for the EPD for a full refresh (slower) - pub fn set_lut(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { - self.set_lut_helper(spi, &LUT_VCOM0, &LUT_WW, &LUT_BW, &LUT_WB, &LUT_BB) - } - - /// Fill the look-up table for a quick refresh (partial refresh) - /// - /// WARNING: Might lead to ghosting-effects - #[allow(dead_code)] - #[deprecated(note = "Might lead to ghosting-effects/problems with your display. Use set_lut instead!")] - #[cfg(feature = "epd4in2_fast_update")] - pub fn set_lut_quick(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { - self.set_lut_helper( - spi, - &LUT_VCOM0_QUICK, - &LUT_WW_QUICK, - &LUT_BW_QUICK, - &LUT_WB_QUICK, - &LUT_BB_QUICK, - ) - } - fn set_lut_helper( &mut self, spi: &mut SPI, diff --git a/src/graphics.rs b/src/graphics.rs index 5f42e6a..5a50d1a 100644 --- a/src/graphics.rs +++ b/src/graphics.rs @@ -139,7 +139,7 @@ mod tests { #[test] fn buffer_clear() { - use epd4in2::constants::{WIDTH, HEIGHT}; + use epd4in2::{WIDTH, HEIGHT}; let mut buffer = [Color::Black.get_byte_value(); WIDTH as usize / 8 * HEIGHT as usize]; let mut display = Display::new(WIDTH, HEIGHT, &mut buffer); @@ -158,7 +158,7 @@ mod tests { #[test] fn rotation_overflow() { - use epd4in2::constants::{WIDTH, HEIGHT}; + use epd4in2::{WIDTH, HEIGHT}; let width = WIDTH as u32; let height = HEIGHT as u32; test_rotation_overflow(width, height, DisplayRotation::Rotate0); diff --git a/src/interface.rs b/src/interface.rs index dd8a5da..ed3bfc4 100644 --- a/src/interface.rs +++ b/src/interface.rs @@ -42,8 +42,6 @@ where /// Basic function for sending [Commands](Command). /// /// Enables direct interaction with the device with the help of [data()](DisplayInterface::data()) - /// - /// //TODO: make public? pub(crate) fn cmd(&mut self, spi: &mut SPI, command: T) -> Result<(), SPI::Error> { // low for commands self.dc.set_low(); @@ -55,8 +53,6 @@ where /// Basic function for sending an array of u8-values of data over spi /// /// Enables direct interaction with the device with the help of [command()](EPD4in2::command()) - /// - /// //TODO: make public? pub(crate) fn data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> { // high for data self.dc.set_high(); @@ -67,7 +63,6 @@ where /// Basic function for sending [Commands](Command) and the data belonging to it. /// - /// //TODO: make public? /// TODO: directly use ::write? cs wouldn't needed to be changed twice than pub(crate) fn cmd_with_data(&mut self, spi: &mut SPI, command: T, data: &[u8]) -> Result<(), SPI::Error> { self.cmd(spi, command)?; @@ -78,8 +73,6 @@ where /// Basic function for sending the same byte of data (one u8) multiple times over spi /// /// Enables direct interaction with the device with the help of [command()](ConnectionInterface::command()) - /// - /// //TODO: make public? pub(crate) fn data_x_times( &mut self, spi: &mut SPI, diff --git a/src/lib.rs b/src/lib.rs index 1d5ea1f..36a4a04 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -67,7 +67,7 @@ pub mod epd2in9; pub(crate) mod type_a; pub mod prelude { - pub use traits::{WaveshareDisplay}; + pub use traits::{WaveshareDisplay, RefreshLUT}; pub use color::Color; pub use SPI_MODE; } diff --git a/src/traits.rs b/src/traits.rs index fb395e9..86dc1c2 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -12,12 +12,19 @@ pub(crate) trait Command { fn address(self) -> u8; } -// Trait for using various Waveforms from different LUTs -// E.g. for partial updates -trait LUTSupport { - fn set_lut(&mut self) -> Result<(), ERR>; - fn set_lut_quick(&mut self) -> Result<(), ERR>; - fn set_lut_manual(&mut self, data: &[u8]) -> Result<(), ERR>; +/// Seperates the different LUT for the Display Refresh process +pub enum RefreshLUT { + /// The "normal" full Lookuptable for the Refresh-Sequence + FULL, + /// The quick LUT where not the full refresh sequence is followed. + /// This might lead to some + QUICK +} + +impl Default for RefreshLUT { + fn default() -> Self { + RefreshLUT::FULL + } } pub(crate) trait InternalWiAdditions @@ -71,8 +78,7 @@ where fn sleep(&mut self, spi: &mut SPI) -> Result<(), SPI::Error>; /// Wakes the device up from sleep - fn wake_up>(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error>; - + fn wake_up>(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error>; /// Sets the backgroundcolor for various commands like [clear_frame()](WaveshareInterface::clear_frame()) fn set_background_color(&mut self, color: Color); @@ -91,7 +97,9 @@ where /// Transmits partial data to the SRAM of the EPD /// - /// BUFFER needs to be of size: w / 8 * h ! + /// (x,y) is the top left corner + /// + /// BUFFER needs to be of size: width / 8 * height ! fn update_partial_frame( &mut self, spi: &mut SPI, @@ -108,4 +116,14 @@ where /// Clears the frame buffer on the EPD with the declared background color /// The background color can be changed with [`set_background_color`] fn clear_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error>; + + /// Trait for using various Waveforms from different LUTs + /// E.g. for partial refreshes + /// + /// A full refresh is needed after a certain amount of quick refreshes! + /// + /// WARNING: Quick Refresh might lead to ghosting-effects/problems with your display. Especially for the 4.2in Display! + /// + /// If None is used the old value will be loaded on the LUTs once more + fn set_lut(&mut self, spi: &mut SPI, refresh_rate: Option) -> Result<(), SPI::Error>; }