From 83878fcca7675b7a6918656fc0f5f05967ff04a9 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Mon, 6 Nov 2023 11:37:50 +0100 Subject: [PATCH] make everything async --- Cargo.toml | 6 +- src/epd1in54/mod.rs | 187 ++++++++++++---------- src/epd1in54_v2/mod.rs | 255 ++++++++++++++++------------- src/epd1in54b/mod.rs | 198 +++++++++++++---------- src/epd1in54c/mod.rs | 134 +++++++++------- src/epd2in13_v2/mod.rs | 262 +++++++++++++++++------------- src/epd2in13bc/mod.rs | 176 ++++++++++++--------- src/epd2in7b/mod.rs | 307 +++++++++++++++++++---------------- src/epd2in9/mod.rs | 176 ++++++++++++--------- src/epd2in9_v2/mod.rs | 243 ++++++++++++++++------------ src/epd2in9bc/mod.rs | 176 ++++++++++++--------- src/epd3in7/mod.rs | 176 ++++++++++++--------- src/epd4in2/mod.rs | 343 +++++++++++++++++++++++----------------- src/epd5in65f/mod.rs | 157 +++++++++--------- src/epd5in83b_v2/mod.rs | 176 +++++++++++---------- src/epd7in5/mod.rs | 132 +++++++++------- src/epd7in5_hd/mod.rs | 137 +++++++++------- src/epd7in5_v2/mod.rs | 132 +++++++++------- src/epd7in5_v3/mod.rs | 169 +++++++++++--------- src/epd7in5b_v2/mod.rs | 155 ++++++++++-------- src/interface.rs | 55 ++++--- src/lib.rs | 3 + src/traits.rs | 50 +++--- 23 files changed, 2167 insertions(+), 1638 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9d1b5971..aafd2b22 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,9 +17,7 @@ edition = "2021" [dependencies] embedded-graphics-core = { version = "0.4", optional = true } - embedded-hal = { version = "1.0.0-rc.1" } -embedded-hal-bus = { version = "0.1.0-rc.1", git="https://github.com/rust-embedded/embedded-hal" } embedded-hal-async = { optional = true, version = "1.0.0-rc.1", git="https://github.com/rust-embedded/embedded-hal" } bit_field = "0.10.1" @@ -58,13 +56,13 @@ required-features = ["linux-dev"] [features] # Remove the linux-dev feature to build the tests on non unix systems -default = ["async", "epd2in13_v3"] #["dep:embedded-hal", "graphics", "linux-dev", "epd2in13_v3"] +default = ["async", "graphics", "linux-dev", "epd2in13_v3"] graphics = ["embedded-graphics-core"] epd2in13_v2 = [] epd2in13_v3 = [] linux-dev = [] -async = ["dep:embedded-hal-async", "embedded-hal-bus/async"] +async = ["dep:embedded-hal-async"] # Offers an alternative fast full lut for type_a displays, but the refreshed screen isnt as clean looking type_a_alternative_faster_lut = [] diff --git a/src/epd1in54/mod.rs b/src/epd1in54/mod.rs index 9bc1b7fe..2cc38e58 100644 --- a/src/epd1in54/mod.rs +++ b/src/epd1in54/mod.rs @@ -54,7 +54,8 @@ pub const DEFAULT_BACKGROUND_COLOR: Color = Color::White; const IS_BUSY_LOW: bool = false; const SINGLE_BYTE_WRITE: bool = true; -use embedded_hal::{delay::*, digital::*, spi::SpiDevice}; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::{delay::DelayUs, spi::SpiDevice}; use crate::type_a::{ command::Command, @@ -96,19 +97,21 @@ where RST: OutputPin, DELAY: DelayUs, { - fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.interface.reset(delay, 10_000, 10_000); + async fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.interface.reset(delay, 10_000, 10_000).await; // 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.cmd_with_data( - spi, - Command::DriverOutputControl, - &[HEIGHT as u8, (HEIGHT >> 8) as u8, 0x00], - )?; + self.interface + .cmd_with_data( + spi, + Command::DriverOutputControl, + &[HEIGHT as u8, (HEIGHT >> 8) as u8, 0x00], + ) + .await?; // 3 Databytes: (and default values from datasheet and arduino) // 1 .. A[6:0] = 0xCF | 0xD7 @@ -116,28 +119,33 @@ where // 1 .. C[6:0] = 0x8D | 0x9D //TODO: test self.interface - .cmd_with_data(spi, Command::BoosterSoftStartControl, &[0xD7, 0xD6, 0x9D])?; + .cmd_with_data(spi, Command::BoosterSoftStartControl, &[0xD7, 0xD6, 0x9D]) + .await?; // One Databyte with value 0xA8 for 7V VCOM self.interface - .cmd_with_data(spi, Command::WriteVcomRegister, &[0xA8])?; + .cmd_with_data(spi, Command::WriteVcomRegister, &[0xA8]) + .await?; // One Databyte with default value 0x1A for 4 dummy lines per gate self.interface - .cmd_with_data(spi, Command::SetDummyLinePeriod, &[0x1A])?; + .cmd_with_data(spi, Command::SetDummyLinePeriod, &[0x1A]) + .await?; // One Databyte with default value 0x08 for 2us per line self.interface - .cmd_with_data(spi, Command::SetGateLineWidth, &[0x08])?; + .cmd_with_data(spi, Command::SetGateLineWidth, &[0x08]) + .await?; // One Databyte with default value 0x03 // -> address: x increment, y increment, address counter is updated in x direction self.interface - .cmd_with_data(spi, Command::DataEntryModeSetting, &[0x03])?; + .cmd_with_data(spi, Command::DataEntryModeSetting, &[0x03]) + .await?; - self.set_lut(spi, delay, None)?; + self.set_lut(spi, delay, None).await?; - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; Ok(()) } } @@ -160,7 +168,7 @@ where HEIGHT } - fn new( + async fn new( spi: &mut SPI, busy: BUSY, dc: DC, @@ -176,39 +184,41 @@ where refresh: RefreshLut::Full, }; - epd.init(spi, delay)?; + epd.init(spi, delay).await?; Ok(epd) } - fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.init(spi, delay) + async fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.init(spi, delay).await } - fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + async fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; // 0x00 for Normal mode (Power on Reset), 0x01 for Deep Sleep Mode //TODO: is 0x00 needed here or would 0x01 be even more efficient? self.interface - .cmd_with_data(spi, Command::DeepSleepMode, &[0x00])?; + .cmd_with_data(spi, Command::DeepSleepMode, &[0x00]) + .await?; Ok(()) } - fn update_frame( + async fn update_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.use_full_frame(spi, delay)?; + self.wait_until_idle(spi, delay).await?; + self.use_full_frame(spi, delay).await?; self.interface - .cmd_with_data(spi, Command::WriteRam, buffer)?; + .cmd_with_data(spi, Command::WriteRam, buffer) + .await?; Ok(()) } //TODO: update description: last 3 bits will be ignored for width and x_pos - fn update_partial_frame( + async fn update_partial_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -218,50 +228,54 @@ where width: u32, height: u32, ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.set_ram_area(spi, delay, x, y, x + width, y + height)?; - self.set_ram_counter(spi, delay, x, y)?; + self.wait_until_idle(spi, delay).await?; + self.set_ram_area(spi, delay, x, y, x + width, y + height) + .await?; + self.set_ram_counter(spi, delay, x, y).await?; self.interface - .cmd_with_data(spi, Command::WriteRam, buffer)?; + .cmd_with_data(spi, Command::WriteRam, buffer) + .await?; Ok(()) } - fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + async fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; // 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 - .cmd_with_data(spi, Command::DisplayUpdateControl2, &[0xC4])?; + .cmd_with_data(spi, Command::DisplayUpdateControl2, &[0xC4]) + .await?; - self.interface.cmd(spi, Command::MasterActivation)?; + self.interface.cmd(spi, Command::MasterActivation).await?; // MASTER Activation should not be interupted to avoid currption of panel images // therefore a terminate command is send - self.interface.cmd(spi, Command::Nop)?; + self.interface.cmd(spi, Command::Nop).await?; Ok(()) } - fn update_and_display_frame( + async fn update_and_display_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.update_frame(spi, buffer, delay)?; - self.display_frame(spi, delay)?; + self.update_frame(spi, buffer, delay).await?; + self.display_frame(spi, delay).await?; Ok(()) } - fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.use_full_frame(spi, delay)?; + async fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; + self.use_full_frame(spi, delay).await?; // clear the ram with the background color let color = self.background_color.get_byte_value(); - self.interface.cmd(spi, Command::WriteRam)?; + self.interface.cmd(spi, Command::WriteRam).await?; self.interface - .data_x_times(spi, color, WIDTH / 8 * HEIGHT)?; + .data_x_times(spi, color, WIDTH / 8 * HEIGHT) + .await?; Ok(()) } @@ -273,7 +287,7 @@ where &self.background_color } - fn set_lut( + async fn set_lut( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -283,13 +297,17 @@ where self.refresh = refresh_lut; } match self.refresh { - RefreshLut::Full => self.set_lut_helper(spi, delay, &LUT_FULL_UPDATE), - RefreshLut::Quick => self.set_lut_helper(spi, delay, &LUT_PARTIAL_UPDATE), + RefreshLut::Full => self.set_lut_helper(spi, delay, &LUT_FULL_UPDATE).await, + RefreshLut::Quick => self.set_lut_helper(spi, delay, &LUT_PARTIAL_UPDATE).await, } } - fn wait_until_idle(&mut self, _spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.interface.wait_until_idle(delay, IS_BUSY_LOW); + async fn wait_until_idle( + &mut self, + _spi: &mut SPI, + delay: &mut DELAY, + ) -> Result<(), SPI::Error> { + let _ = self.interface.wait_until_idle(delay, IS_BUSY_LOW).await; Ok(()) } } @@ -302,19 +320,20 @@ where RST: OutputPin, DELAY: DelayUs, { - pub(crate) fn use_full_frame( + pub(crate) async fn use_full_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, ) -> Result<(), SPI::Error> { // choose full frame/ram - self.set_ram_area(spi, delay, 0, 0, WIDTH - 1, HEIGHT - 1)?; + self.set_ram_area(spi, delay, 0, 0, WIDTH - 1, HEIGHT - 1) + .await?; // start from the beginning - self.set_ram_counter(spi, delay, 0, 0) + self.set_ram_counter(spi, delay, 0, 0).await } - pub(crate) fn set_ram_area( + pub(crate) async fn set_ram_area( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -323,65 +342,73 @@ where end_x: u32, end_y: u32, ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + let _ = self.wait_until_idle(spi, delay).await; 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.cmd_with_data( - spi, - Command::SetRamXAddressStartEndPosition, - &[(start_x >> 3) as u8, (end_x >> 3) as u8], - )?; + self.interface + .cmd_with_data( + spi, + Command::SetRamXAddressStartEndPosition, + &[(start_x >> 3) as u8, (end_x >> 3) as u8], + ) + .await?; // 2 Databytes: A[7:0] & 0..A[8] for each - start and end - self.interface.cmd_with_data( - spi, - Command::SetRamYAddressStartEndPosition, - &[ - start_y as u8, - (start_y >> 8) as u8, - end_y as u8, - (end_y >> 8) as u8, - ], - )?; + self.interface + .cmd_with_data( + spi, + Command::SetRamYAddressStartEndPosition, + &[ + start_y as u8, + (start_y >> 8) as u8, + end_y as u8, + (end_y >> 8) as u8, + ], + ) + .await?; Ok(()) } - pub(crate) fn set_ram_counter( + pub(crate) async fn set_ram_counter( &mut self, spi: &mut SPI, delay: &mut DELAY, x: u32, y: u32, ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; // 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::SetRamXAddressCounter, &[(x >> 3) as u8])?; + .cmd_with_data(spi, Command::SetRamXAddressCounter, &[(x >> 3) as u8]) + .await?; // 2 Databytes: A[7:0] & 0..A[8] - self.interface.cmd_with_data( - spi, - Command::SetRamYAddressCounter, - &[y as u8, (y >> 8) as u8], - )?; + self.interface + .cmd_with_data( + spi, + Command::SetRamYAddressCounter, + &[y as u8, (y >> 8) as u8], + ) + .await?; Ok(()) } - fn set_lut_helper( + async fn set_lut_helper( &mut self, spi: &mut SPI, delay: &mut DELAY, buffer: &[u8], ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; assert!(buffer.len() == 30); self.interface - .cmd_with_data(spi, Command::WriteLutRegister, buffer)?; + .cmd_with_data(spi, Command::WriteLutRegister, buffer) + .await?; Ok(()) } } diff --git a/src/epd1in54_v2/mod.rs b/src/epd1in54_v2/mod.rs index 0f0399f7..8fce171c 100644 --- a/src/epd1in54_v2/mod.rs +++ b/src/epd1in54_v2/mod.rs @@ -11,7 +11,8 @@ pub const DEFAULT_BACKGROUND_COLOR: Color = Color::White; const IS_BUSY_LOW: bool = false; const SINGLE_BYTE_WRITE: bool = true; -use embedded_hal::{delay::*, digital::*, spi::SpiDevice}; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::{delay::DelayUs, spi::SpiDevice}; use crate::type_a::command::Command; @@ -46,43 +47,51 @@ where RST: OutputPin, DELAY: DelayUs, { - fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.interface.reset(delay, 10_000, 10_000); - self.wait_until_idle(spi, delay)?; - self.interface.cmd(spi, Command::SwReset)?; - self.wait_until_idle(spi, delay)?; + async fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.interface.reset(delay, 10_000, 10_000).await; + self.wait_until_idle(spi, delay).await?; + self.interface.cmd(spi, Command::SwReset).await?; + self.wait_until_idle(spi, delay).await?; // 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.cmd_with_data( - spi, - Command::DriverOutputControl, - &[(HEIGHT - 1) as u8, 0x0, 0x00], - )?; + self.interface + .cmd_with_data( + spi, + Command::DriverOutputControl, + &[(HEIGHT - 1) as u8, 0x0, 0x00], + ) + .await?; self.interface - .cmd_with_data(spi, Command::DataEntryModeSetting, &[0x3])?; + .cmd_with_data(spi, Command::DataEntryModeSetting, &[0x3]) + .await?; - self.set_ram_area(spi, delay, 0, 0, WIDTH - 1, HEIGHT - 1)?; + self.set_ram_area(spi, delay, 0, 0, WIDTH - 1, HEIGHT - 1) + .await?; self.interface - .cmd_with_data(spi, Command::BorderWaveformControl, &[0x1])?; + .cmd_with_data(spi, Command::BorderWaveformControl, &[0x1]) + .await?; - self.interface.cmd_with_data( - spi, - Command::TemperatureSensorSelection, - &[0x80], // 0x80: internal temperature sensor - )?; + self.interface + .cmd_with_data( + spi, + Command::TemperatureSensorSelection, + &[0x80], // 0x80: internal temperature sensor + ) + .await?; self.interface - .cmd_with_data(spi, Command::TemperatureSensorControl, &[0xB1, 0x20])?; + .cmd_with_data(spi, Command::TemperatureSensorControl, &[0xB1, 0x20]) + .await?; - self.set_ram_counter(spi, delay, 0, 0)?; + self.set_ram_counter(spi, delay, 0, 0).await?; - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; Ok(()) } } @@ -105,7 +114,7 @@ where HEIGHT } - fn new( + async fn new( spi: &mut SPI, busy: BUSY, dc: DC, @@ -121,37 +130,39 @@ where refresh: RefreshLut::Full, }; - epd.init(spi, delay)?; + epd.init(spi, delay).await?; Ok(epd) } - fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.init(spi, delay) + async fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.init(spi, delay).await } - fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + async fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; self.interface - .cmd_with_data(spi, Command::DeepSleepMode, &[0x01])?; + .cmd_with_data(spi, Command::DeepSleepMode, &[0x01]) + .await?; Ok(()) } - fn update_frame( + async fn update_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.use_full_frame(spi, delay)?; + self.wait_until_idle(spi, delay).await?; + self.use_full_frame(spi, delay).await?; self.interface - .cmd_with_data(spi, Command::WriteRam, buffer)?; + .cmd_with_data(spi, Command::WriteRam, buffer) + .await?; Ok(()) } //TODO: update description: last 3 bits will be ignored for width and x_pos - fn update_partial_frame( + async fn update_partial_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -161,56 +172,62 @@ where width: u32, height: u32, ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.set_ram_area(spi, delay, x, y, x + width, y + height)?; - self.set_ram_counter(spi, delay, x, y)?; + self.wait_until_idle(spi, delay).await?; + self.set_ram_area(spi, delay, x, y, x + width, y + height) + .await?; + self.set_ram_counter(spi, delay, x, y).await?; self.interface - .cmd_with_data(spi, Command::WriteRam, buffer)?; + .cmd_with_data(spi, Command::WriteRam, buffer) + .await?; Ok(()) } - fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + async fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; if self.refresh == RefreshLut::Full { self.interface - .cmd_with_data(spi, Command::DisplayUpdateControl2, &[0xC7])?; + .cmd_with_data(spi, Command::DisplayUpdateControl2, &[0xC7]) + .await?; } else if self.refresh == RefreshLut::Quick { self.interface - .cmd_with_data(spi, Command::DisplayUpdateControl2, &[0xCF])?; + .cmd_with_data(spi, Command::DisplayUpdateControl2, &[0xCF]) + .await?; } - self.interface.cmd(spi, Command::MasterActivation)?; + self.interface.cmd(spi, Command::MasterActivation).await?; // MASTER Activation should not be interupted to avoid currption of panel images // therefore a terminate command is send - self.interface.cmd(spi, Command::Nop)?; + self.interface.cmd(spi, Command::Nop).await?; Ok(()) } - fn update_and_display_frame( + async fn update_and_display_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.update_frame(spi, buffer, delay)?; - self.display_frame(spi, delay)?; + self.update_frame(spi, buffer, delay).await?; + self.display_frame(spi, delay).await?; Ok(()) } - fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.use_full_frame(spi, delay)?; + async fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; + self.use_full_frame(spi, delay).await?; // clear the ram with the background color let color = self.background_color.get_byte_value(); - self.interface.cmd(spi, Command::WriteRam)?; + self.interface.cmd(spi, Command::WriteRam).await?; self.interface - .data_x_times(spi, color, WIDTH / 8 * HEIGHT)?; - self.interface.cmd(spi, Command::WriteRam2)?; + .data_x_times(spi, color, WIDTH / 8 * HEIGHT) + .await?; + self.interface.cmd(spi, Command::WriteRam2).await?; self.interface - .data_x_times(spi, color, WIDTH / 8 * HEIGHT)?; + .data_x_times(spi, color, WIDTH / 8 * HEIGHT) + .await?; Ok(()) } @@ -222,7 +239,7 @@ where &self.background_color } - fn set_lut( + async fn set_lut( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -232,31 +249,39 @@ where self.refresh = refresh_lut; } match self.refresh { - RefreshLut::Full => self.set_lut_helper(spi, delay, &LUT_FULL_UPDATE), - RefreshLut::Quick => self.set_lut_helper(spi, delay, &LUT_PARTIAL_UPDATE), + RefreshLut::Full => self.set_lut_helper(spi, delay, &LUT_FULL_UPDATE).await, + RefreshLut::Quick => self.set_lut_helper(spi, delay, &LUT_PARTIAL_UPDATE).await, }?; // Additional configuration required only for partial updates if self.refresh == RefreshLut::Quick { - self.interface.cmd_with_data( - spi, - Command::WriteOtpSelection, - &[0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x0], - )?; self.interface - .cmd_with_data(spi, Command::BorderWaveformControl, &[0x80])?; + .cmd_with_data( + spi, + Command::WriteOtpSelection, + &[0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x0], + ) + .await?; self.interface - .cmd_with_data(spi, Command::DisplayUpdateControl2, &[0xc0])?; - self.interface.cmd(spi, Command::MasterActivation)?; + .cmd_with_data(spi, Command::BorderWaveformControl, &[0x80]) + .await?; + self.interface + .cmd_with_data(spi, Command::DisplayUpdateControl2, &[0xc0]) + .await?; + self.interface.cmd(spi, Command::MasterActivation).await?; // MASTER Activation should not be interupted to avoid currption of panel images // therefore a terminate command is send - self.interface.cmd(spi, Command::Nop)?; + self.interface.cmd(spi, Command::Nop).await?; } Ok(()) } - fn wait_until_idle(&mut self, _spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.interface.wait_until_idle(delay, IS_BUSY_LOW); + async fn wait_until_idle( + &mut self, + _spi: &mut SPI, + delay: &mut DELAY, + ) -> Result<(), SPI::Error> { + self.interface.wait_until_idle(delay, IS_BUSY_LOW).await; Ok(()) } } @@ -269,19 +294,20 @@ where RST: OutputPin, DELAY: DelayUs, { - pub(crate) fn use_full_frame( + pub(crate) async fn use_full_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, ) -> Result<(), SPI::Error> { // choose full frame/ram - self.set_ram_area(spi, delay, 0, 0, WIDTH - 1, HEIGHT - 1)?; + self.set_ram_area(spi, delay, 0, 0, WIDTH - 1, HEIGHT - 1) + .await?; // start from the beginning - self.set_ram_counter(spi, delay, 0, 0) + self.set_ram_counter(spi, delay, 0, 0).await } - pub(crate) fn set_ram_area( + pub(crate) async fn set_ram_area( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -290,81 +316,94 @@ where end_x: u32, end_y: u32, ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; 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.cmd_with_data( - spi, - Command::SetRamXAddressStartEndPosition, - &[(start_x >> 3) as u8, (end_x >> 3) as u8], - )?; + self.interface + .cmd_with_data( + spi, + Command::SetRamXAddressStartEndPosition, + &[(start_x >> 3) as u8, (end_x >> 3) as u8], + ) + .await?; // 2 Databytes: A[7:0] & 0..A[8] for each - start and end - self.interface.cmd_with_data( - spi, - Command::SetRamYAddressStartEndPosition, - &[ - start_y as u8, - (start_y >> 8) as u8, - end_y as u8, - (end_y >> 8) as u8, - ], - )?; + self.interface + .cmd_with_data( + spi, + Command::SetRamYAddressStartEndPosition, + &[ + start_y as u8, + (start_y >> 8) as u8, + end_y as u8, + (end_y >> 8) as u8, + ], + ) + .await?; Ok(()) } - pub(crate) fn set_ram_counter( + pub(crate) async fn set_ram_counter( &mut self, spi: &mut SPI, delay: &mut DELAY, x: u32, y: u32, ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; // 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::SetRamXAddressCounter, &[(x >> 3) as u8])?; + .cmd_with_data(spi, Command::SetRamXAddressCounter, &[(x >> 3) as u8]) + .await?; // 2 Databytes: A[7:0] & 0..A[8] - self.interface.cmd_with_data( - spi, - Command::SetRamYAddressCounter, - &[y as u8, (y >> 8) as u8], - )?; + self.interface + .cmd_with_data( + spi, + Command::SetRamYAddressCounter, + &[y as u8, (y >> 8) as u8], + ) + .await?; Ok(()) } - fn set_lut_helper( + async fn set_lut_helper( &mut self, spi: &mut SPI, delay: &mut DELAY, buffer: &[u8], ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; assert!(buffer.len() == 159); self.interface - .cmd_with_data(spi, Command::WriteLutRegister, &buffer[0..153])?; + .cmd_with_data(spi, Command::WriteLutRegister, &buffer[0..153]) + .await?; self.interface - .cmd_with_data(spi, Command::WriteLutRegisterEnd, &[buffer[153]])?; + .cmd_with_data(spi, Command::WriteLutRegisterEnd, &[buffer[153]]) + .await?; - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; self.interface - .cmd_with_data(spi, Command::GateDrivingVoltage, &[buffer[154]])?; + .cmd_with_data(spi, Command::GateDrivingVoltage, &[buffer[154]]) + .await?; - self.interface.cmd_with_data( - spi, - Command::SourceDrivingVoltage, - &[buffer[155], buffer[156], buffer[157]], - )?; self.interface - .cmd_with_data(spi, Command::WriteVcomRegister, &[buffer[158]])?; + .cmd_with_data( + spi, + Command::SourceDrivingVoltage, + &[buffer[155], buffer[156], buffer[157]], + ) + .await?; + self.interface + .cmd_with_data(spi, Command::WriteVcomRegister, &[buffer[158]]) + .await?; Ok(()) } diff --git a/src/epd1in54b/mod.rs b/src/epd1in54b/mod.rs index 0a477bf4..2146fd8e 100644 --- a/src/epd1in54b/mod.rs +++ b/src/epd1in54b/mod.rs @@ -1,6 +1,7 @@ //! A simple Driver for the Waveshare 1.54" (B) E-Ink Display via SPI -use embedded_hal::{delay::*, digital::*, spi::SpiDevice}; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::{delay::DelayUs, spi::SpiDevice}; use crate::interface::DisplayInterface; use crate::traits::{ @@ -52,38 +53,44 @@ where RST: OutputPin, DELAY: DelayUs, { - fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.interface.reset(delay, 10_000, 10_000); + async fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.interface.reset(delay, 10_000, 10_000).await; // set the power settings self.interface - .cmd_with_data(spi, Command::PowerSetting, &[0x07, 0x00, 0x08, 0x00])?; + .cmd_with_data(spi, Command::PowerSetting, &[0x07, 0x00, 0x08, 0x00]) + .await?; // start the booster self.interface - .cmd_with_data(spi, Command::BoosterSoftStart, &[0x07, 0x07, 0x07])?; + .cmd_with_data(spi, Command::BoosterSoftStart, &[0x07, 0x07, 0x07]) + .await?; // power on - self.command(spi, Command::PowerOn)?; - delay.delay_us(5000); - self.wait_until_idle(spi, delay)?; + self.command(spi, Command::PowerOn).await?; + delay.delay_us(5000).await; + self.wait_until_idle(spi, delay).await?; // set the panel settings - self.cmd_with_data(spi, Command::PanelSetting, &[0xCF])?; + self.cmd_with_data(spi, Command::PanelSetting, &[0xCF]) + .await?; - self.cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x37])?; + self.cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x37]) + .await?; // PLL - self.cmd_with_data(spi, Command::PllControl, &[0x39])?; + self.cmd_with_data(spi, Command::PllControl, &[0x39]) + .await?; // set resolution - self.send_resolution(spi)?; + self.send_resolution(spi).await?; - self.cmd_with_data(spi, Command::VcmDcSetting, &[0x0E])?; + self.cmd_with_data(spi, Command::VcmDcSetting, &[0x0E]) + .await?; - self.set_lut(spi, delay, None)?; + self.set_lut(spi, delay, None).await?; - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; Ok(()) } @@ -98,43 +105,47 @@ where RST: OutputPin, DELAY: DelayUs, { - fn update_color_frame( + async fn update_color_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, black: &[u8], chromatic: &[u8], ) -> Result<(), SPI::Error> { - self.update_achromatic_frame(spi, delay, black)?; - self.update_chromatic_frame(spi, delay, chromatic) + self.update_achromatic_frame(spi, delay, black).await?; + self.update_chromatic_frame(spi, delay, chromatic).await } - fn update_achromatic_frame( + async fn update_achromatic_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, black: &[u8], ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.send_resolution(spi)?; + self.wait_until_idle(spi, delay).await?; + self.send_resolution(spi).await?; - self.interface.cmd(spi, Command::DataStartTransmission1)?; + self.interface + .cmd(spi, Command::DataStartTransmission1) + .await?; for b in black { let expanded = expand_bits(*b); - self.interface.data(spi, &expanded)?; + self.interface.data(spi, &expanded).await?; } Ok(()) } - fn update_chromatic_frame( + async fn update_chromatic_frame( &mut self, spi: &mut SPI, _delay: &mut DELAY, chromatic: &[u8], ) -> Result<(), SPI::Error> { - self.interface.cmd(spi, Command::DataStartTransmission2)?; - self.interface.data(spi, chromatic)?; + self.interface + .cmd(spi, Command::DataStartTransmission2) + .await?; + self.interface.data(spi, chromatic).await?; Ok(()) } } @@ -149,7 +160,7 @@ where DELAY: DelayUs, { type DisplayColor = Color; - fn new( + async fn new( spi: &mut SPI, busy: BUSY, dc: DC, @@ -162,33 +173,36 @@ where let mut epd = Epd1in54b { interface, color }; - epd.init(spi, delay)?; + epd.init(spi, delay).await?; Ok(epd) } - fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + async fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; self.interface - .cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x17])?; //border floating + .cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x17]) + .await?; //border floating self.interface - .cmd_with_data(spi, Command::VcmDcSetting, &[0x00])?; // Vcom to 0V + .cmd_with_data(spi, Command::VcmDcSetting, &[0x00]) + .await?; // Vcom to 0V self.interface - .cmd_with_data(spi, Command::PowerSetting, &[0x02, 0x00, 0x00, 0x00])?; //VG&VS to 0V fast + .cmd_with_data(spi, Command::PowerSetting, &[0x02, 0x00, 0x00, 0x00]) + .await?; //VG&VS to 0V fast - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; //NOTE: The example code has a 1s delay here - self.command(spi, Command::PowerOff)?; + self.command(spi, Command::PowerOff).await?; Ok(()) } - fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.init(spi, delay) + async fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.init(spi, delay).await } fn set_background_color(&mut self, color: Color) { @@ -207,21 +221,23 @@ where HEIGHT } - fn update_frame( + async fn update_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.send_resolution(spi)?; + self.wait_until_idle(spi, delay).await?; + self.send_resolution(spi).await?; - self.interface.cmd(spi, Command::DataStartTransmission1)?; + self.interface + .cmd(spi, Command::DataStartTransmission1) + .await?; for b in buffer { // Two bits per pixel let expanded = expand_bits(*b); - self.interface.data(spi, &expanded)?; + self.interface.data(spi, &expanded).await?; } //NOTE: Example code has a delay here @@ -230,15 +246,17 @@ where let color = self.color.get_byte_value(); let nbits = WIDTH * (HEIGHT / 8); - self.interface.cmd(spi, Command::DataStartTransmission2)?; - self.interface.data_x_times(spi, color, nbits)?; + self.interface + .cmd(spi, Command::DataStartTransmission2) + .await?; + self.interface.data_x_times(spi, color, nbits).await?; //NOTE: Example code has a delay here Ok(()) } #[allow(unused)] - fn update_partial_frame( + async fn update_partial_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -251,69 +269,89 @@ where unimplemented!() } - fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.command(spi, Command::DisplayRefresh)?; + async fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; + self.command(spi, Command::DisplayRefresh).await?; Ok(()) } - fn update_and_display_frame( + async fn update_and_display_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.update_frame(spi, buffer, delay)?; - self.display_frame(spi, delay)?; + self.update_frame(spi, buffer, delay).await?; + self.display_frame(spi, delay).await?; Ok(()) } - fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.send_resolution(spi)?; + async fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; + self.send_resolution(spi).await?; let color = DEFAULT_BACKGROUND_COLOR.get_byte_value(); // Clear the black - self.interface.cmd(spi, Command::DataStartTransmission1)?; + self.interface + .cmd(spi, Command::DataStartTransmission1) + .await?; // Uses 2 bits per pixel self.interface - .data_x_times(spi, color, 2 * (WIDTH * HEIGHT / 8))?; + .data_x_times(spi, color, 2 * (WIDTH * HEIGHT / 8)) + .await?; // Clear the red - self.interface.cmd(spi, Command::DataStartTransmission2)?; self.interface - .data_x_times(spi, color, WIDTH * HEIGHT / 8)?; + .cmd(spi, Command::DataStartTransmission2) + .await?; + self.interface + .data_x_times(spi, color, WIDTH * HEIGHT / 8) + .await?; Ok(()) } - fn set_lut( + async fn set_lut( &mut self, spi: &mut SPI, _delay: &mut DELAY, _refresh_rate: Option, ) -> Result<(), SPI::Error> { self.interface - .cmd_with_data(spi, Command::LutForVcom, LUT_VCOM0)?; + .cmd_with_data(spi, Command::LutForVcom, LUT_VCOM0) + .await?; self.interface - .cmd_with_data(spi, Command::LutWhiteToWhite, LUT_WHITE_TO_WHITE)?; + .cmd_with_data(spi, Command::LutWhiteToWhite, LUT_WHITE_TO_WHITE) + .await?; self.interface - .cmd_with_data(spi, Command::LutBlackToWhite, LUT_BLACK_TO_WHITE)?; - self.interface.cmd_with_data(spi, Command::LutG0, LUT_G1)?; - self.interface.cmd_with_data(spi, Command::LutG1, LUT_G2)?; + .cmd_with_data(spi, Command::LutBlackToWhite, LUT_BLACK_TO_WHITE) + .await?; self.interface - .cmd_with_data(spi, Command::LutRedVcom, LUT_RED_VCOM)?; + .cmd_with_data(spi, Command::LutG0, LUT_G1) + .await?; self.interface - .cmd_with_data(spi, Command::LutRed0, LUT_RED0)?; + .cmd_with_data(spi, Command::LutG1, LUT_G2) + .await?; self.interface - .cmd_with_data(spi, Command::LutRed1, LUT_RED1)?; + .cmd_with_data(spi, Command::LutRedVcom, LUT_RED_VCOM) + .await?; + self.interface + .cmd_with_data(spi, Command::LutRed0, LUT_RED0) + .await?; + self.interface + .cmd_with_data(spi, Command::LutRed1, LUT_RED1) + .await?; Ok(()) } - fn wait_until_idle(&mut self, _spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.interface.wait_until_idle(delay, IS_BUSY_LOW); + async fn wait_until_idle( + &mut self, + _spi: &mut SPI, + delay: &mut DELAY, + ) -> Result<(), SPI::Error> { + self.interface.wait_until_idle(delay, IS_BUSY_LOW).await; Ok(()) } } @@ -326,32 +364,32 @@ where RST: OutputPin, DELAY: DelayUs, { - fn command(&mut self, spi: &mut SPI, command: Command) -> Result<(), SPI::Error> { - self.interface.cmd(spi, command) + async fn command(&mut self, spi: &mut SPI, command: Command) -> Result<(), SPI::Error> { + self.interface.cmd(spi, command).await } - fn send_data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> { - self.interface.data(spi, data) + async fn send_data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> { + self.interface.data(spi, data).await } - fn cmd_with_data( + async fn cmd_with_data( &mut self, spi: &mut SPI, command: Command, data: &[u8], ) -> Result<(), SPI::Error> { - self.interface.cmd_with_data(spi, command, data) + self.interface.cmd_with_data(spi, command, data).await } - fn send_resolution(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { + async fn send_resolution(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { let w = self.width(); let h = self.height(); - self.command(spi, Command::ResolutionSetting)?; + self.command(spi, Command::ResolutionSetting).await?; - self.send_data(spi, &[w as u8])?; - self.send_data(spi, &[(h >> 8) as u8])?; - self.send_data(spi, &[h as u8]) + self.send_data(spi, &[w as u8]).await?; + self.send_data(spi, &[(h >> 8) as u8]).await?; + self.send_data(spi, &[h as u8]).await } } diff --git a/src/epd1in54c/mod.rs b/src/epd1in54c/mod.rs index 341baf7d..006190f4 100644 --- a/src/epd1in54c/mod.rs +++ b/src/epd1in54c/mod.rs @@ -1,6 +1,7 @@ //! A simple Driver for the Waveshare 1.54" (C) E-Ink Display via SPI -use embedded_hal::{delay::*, digital::*, spi::SpiDevice}; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::{delay::DelayUs, spi::SpiDevice}; use crate::interface::DisplayInterface; use crate::traits::{ @@ -49,28 +50,31 @@ where RST: OutputPin, DELAY: DelayUs, { - fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + async fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { // Based on Reference Program Code from: // https://www.waveshare.com/w/upload/a/ac/1.54inch_e-Paper_Module_C_Specification.pdf // and: // https://github.com/waveshare/e-Paper/blob/master/STM32/STM32-F103ZET6/User/e-Paper/EPD_1in54c.c - self.interface.reset(delay, 10_000, 2_000); + self.interface.reset(delay, 10_000, 2_000).await; // start the booster - self.cmd_with_data(spi, Command::BoosterSoftStart, &[0x17, 0x17, 0x17])?; + self.cmd_with_data(spi, Command::BoosterSoftStart, &[0x17, 0x17, 0x17]) + .await?; // power on - self.command(spi, Command::PowerOn)?; - delay.delay_us(5000); - self.wait_until_idle(spi, delay)?; + self.command(spi, Command::PowerOn).await?; + delay.delay_us(5000).await; + self.wait_until_idle(spi, delay).await?; // set the panel settings - self.cmd_with_data(spi, Command::PanelSetting, &[0x0f, 0x0d])?; + self.cmd_with_data(spi, Command::PanelSetting, &[0x0f, 0x0d]) + .await?; // set resolution - self.send_resolution(spi)?; + self.send_resolution(spi).await?; - self.cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x77])?; + self.cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x77]) + .await?; Ok(()) } @@ -85,37 +89,39 @@ where RST: OutputPin, DELAY: DelayUs, { - fn update_color_frame( + async fn update_color_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, black: &[u8], chromatic: &[u8], ) -> Result<(), SPI::Error> { - self.update_achromatic_frame(spi, delay, black)?; - self.update_chromatic_frame(spi, delay, chromatic) + self.update_achromatic_frame(spi, delay, black).await?; + self.update_chromatic_frame(spi, delay, chromatic).await } - fn update_achromatic_frame( + async fn update_achromatic_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, black: &[u8], ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.cmd_with_data(spi, Command::DataStartTransmission1, black)?; + self.wait_until_idle(spi, delay).await?; + self.cmd_with_data(spi, Command::DataStartTransmission1, black) + .await?; Ok(()) } - fn update_chromatic_frame( + async fn update_chromatic_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, chromatic: &[u8], ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.cmd_with_data(spi, Command::DataStartTransmission2, chromatic)?; + self.wait_until_idle(spi, delay).await?; + self.cmd_with_data(spi, Command::DataStartTransmission2, chromatic) + .await?; Ok(()) } @@ -131,7 +137,7 @@ where DELAY: DelayUs, { type DisplayColor = Color; - fn new( + async fn new( spi: &mut SPI, busy: BUSY, dc: DC, @@ -144,23 +150,23 @@ where let mut epd = Epd1in54c { interface, color }; - epd.init(spi, delay)?; + epd.init(spi, delay).await?; Ok(epd) } - fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + async fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; - self.command(spi, Command::PowerOff)?; - self.wait_until_idle(spi, delay)?; - self.cmd_with_data(spi, Command::DeepSleep, &[0xa5])?; + self.command(spi, Command::PowerOff).await?; + self.wait_until_idle(spi, delay).await?; + self.cmd_with_data(spi, Command::DeepSleep, &[0xa5]).await?; Ok(()) } - fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.init(spi, delay) + async fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.init(spi, delay).await } fn set_background_color(&mut self, color: Color) { @@ -179,25 +185,27 @@ where HEIGHT } - fn update_frame( + async fn update_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.update_achromatic_frame(spi, delay, buffer)?; + self.update_achromatic_frame(spi, delay, buffer).await?; // Clear the chromatic layer let color = self.color.get_byte_value(); - self.command(spi, Command::DataStartTransmission2)?; - self.interface.data_x_times(spi, color, NUM_DISPLAY_BITS)?; + self.command(spi, Command::DataStartTransmission2).await?; + self.interface + .data_x_times(spi, color, NUM_DISPLAY_BITS) + .await?; Ok(()) } #[allow(unused)] - fn update_partial_frame( + async fn update_partial_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -210,41 +218,45 @@ where unimplemented!() } - fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.command(spi, Command::DisplayRefresh)?; - self.wait_until_idle(spi, delay)?; + async fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.command(spi, Command::DisplayRefresh).await?; + self.wait_until_idle(spi, delay).await?; Ok(()) } - fn update_and_display_frame( + async fn update_and_display_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.update_frame(spi, buffer, delay)?; - self.display_frame(spi, delay)?; + self.update_frame(spi, buffer, delay).await?; + self.display_frame(spi, delay).await?; Ok(()) } - fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + async fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; let color = DEFAULT_BACKGROUND_COLOR.get_byte_value(); // Clear the black - self.command(spi, Command::DataStartTransmission1)?; - self.interface.data_x_times(spi, color, NUM_DISPLAY_BITS)?; + self.command(spi, Command::DataStartTransmission1).await?; + self.interface + .data_x_times(spi, color, NUM_DISPLAY_BITS) + .await?; // Clear the chromatic - self.command(spi, Command::DataStartTransmission2)?; - self.interface.data_x_times(spi, color, NUM_DISPLAY_BITS)?; + self.command(spi, Command::DataStartTransmission2).await?; + self.interface + .data_x_times(spi, color, NUM_DISPLAY_BITS) + .await?; Ok(()) } - fn set_lut( + async fn set_lut( &mut self, _spi: &mut SPI, _delay: &mut DELAY, @@ -253,8 +265,12 @@ where Ok(()) } - fn wait_until_idle(&mut self, _spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.interface.wait_until_idle(delay, IS_BUSY_LOW); + async fn wait_until_idle( + &mut self, + _spi: &mut SPI, + delay: &mut DELAY, + ) -> Result<(), SPI::Error> { + self.interface.wait_until_idle(delay, IS_BUSY_LOW).await; Ok(()) } } @@ -267,40 +283,40 @@ where RST: OutputPin, DELAY: DelayUs, { - fn command(&mut self, spi: &mut SPI, command: Command) -> Result<(), SPI::Error> { - self.interface.cmd(spi, command) + async fn command(&mut self, spi: &mut SPI, command: Command) -> Result<(), SPI::Error> { + self.interface.cmd(spi, command).await } - fn send_data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> { - self.interface.data(spi, data) + async fn send_data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> { + self.interface.data(spi, data).await } - fn cmd_with_data( + async fn cmd_with_data( &mut self, spi: &mut SPI, command: Command, data: &[u8], ) -> Result<(), SPI::Error> { - self.interface.cmd_with_data(spi, command, data) + self.interface.cmd_with_data(spi, command, data).await } - fn send_resolution(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { + async fn send_resolution(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { let w = self.width(); let h = self.height(); - self.command(spi, Command::ResolutionSetting)?; + self.command(spi, Command::ResolutionSetting).await?; // | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | // | HRES[7:3] | 0 | 0 | 0 | - self.send_data(spi, &[(w as u8) & 0b1111_1000])?; + self.send_data(spi, &[(w as u8) & 0b1111_1000]).await?; // | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | // | - | - | - | - | - | - | - | VRES[8] | - self.send_data(spi, &[(w >> 8) as u8])?; + self.send_data(spi, &[(w >> 8) as u8]).await?; // | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | // | VRES[7:0] | // Specification shows C/D is zero while sending the last byte, // but upstream code does not implement it like that. So for now // we follow upstream code. - self.send_data(spi, &[h as u8]) + self.send_data(spi, &[h as u8]).await } } diff --git a/src/epd2in13_v2/mod.rs b/src/epd2in13_v2/mod.rs index 7712835d..ad31e97a 100644 --- a/src/epd2in13_v2/mod.rs +++ b/src/epd2in13_v2/mod.rs @@ -15,11 +15,8 @@ //! - [Controller Datasheet SS1780](http://www.e-paper-display.com/download_detail/downloadsId=682.html) //! -use embedded_hal::{ - delay::DelayUs, - digital::{InputPin, OutputPin}, - spi::SpiDevice, -}; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::{delay::DelayUs, spi::SpiDevice}; use crate::buffer_len; use crate::color::Color; @@ -89,15 +86,15 @@ where RST: OutputPin, DELAY: DelayUs, { - fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + async fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { // HW reset - self.interface.reset(delay, 10_000, 10_000); + self.interface.reset(delay, 10_000, 10_000).await; if self.refresh == RefreshLut::Quick { - self.set_vcom_register(spi, (-9).vcom())?; - self.wait_until_idle(spi, delay)?; + self.set_vcom_register(spi, (-9).vcom()).await?; + self.wait_until_idle(spi, delay).await?; - self.set_lut(spi, delay, Some(self.refresh))?; + self.set_lut(spi, delay, Some(self.refresh)).await?; // Python code does this, not sure why // self.cmd_with_data(spi, Command::WriteOtpSelection, &[0, 0, 0, 0, 0x40, 0, 0])?; @@ -107,9 +104,10 @@ where self.set_display_update_control_2( spi, DisplayUpdateControl2::new().enable_analog().enable_clock(), - )?; - self.command(spi, Command::MasterActivation)?; - self.wait_until_idle(spi, delay)?; + ) + .await?; + self.command(spi, Command::MasterActivation).await?; + self.wait_until_idle(spi, delay).await?; self.set_border_waveform( spi, @@ -118,11 +116,12 @@ where fix_level: BorderWaveFormFixLevel::Vss, gs_trans: BorderWaveFormGs::Lut1, }, - )?; + ) + .await?; } else { - self.wait_until_idle(spi, delay)?; - self.command(spi, Command::SwReset)?; - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; + self.command(spi, Command::SwReset).await?; + self.wait_until_idle(spi, delay).await?; self.set_driver_output( spi, @@ -132,17 +131,19 @@ where scan_dir_incr: true, width: (HEIGHT - 1) as u16, }, - )?; + ) + .await?; // These 2 are the reset values - self.set_dummy_line_period(spi, 0x30)?; - self.set_gate_scan_start_position(spi, 0)?; + self.set_dummy_line_period(spi, 0x30).await?; + self.set_gate_scan_start_position(spi, 0).await?; - self.set_data_entry_mode(spi, DataEntryModeIncr::XIncrYIncr, DataEntryModeDir::XDir)?; + self.set_data_entry_mode(spi, DataEntryModeIncr::XIncrYIncr, DataEntryModeDir::XDir) + .await?; // Use simple X/Y auto increase - self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1)?; - self.set_ram_address_counters(spi, delay, 0, 0)?; + self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1).await?; + self.set_ram_address_counters(spi, delay, 0, 0).await?; self.set_border_waveform( spi, @@ -151,24 +152,27 @@ where fix_level: BorderWaveFormFixLevel::Vss, gs_trans: BorderWaveFormGs::Lut3, }, - )?; + ) + .await?; - self.set_vcom_register(spi, (-21).vcom())?; + self.set_vcom_register(spi, (-21).vcom()).await?; - self.set_gate_driving_voltage(spi, 190.gate_driving_decivolt())?; + self.set_gate_driving_voltage(spi, 190.gate_driving_decivolt()) + .await?; self.set_source_driving_voltage( spi, 150.source_driving_decivolt(), 50.source_driving_decivolt(), (-150).source_driving_decivolt(), - )?; + ) + .await?; - self.set_gate_line_width(spi, 10)?; + self.set_gate_line_width(spi, 10).await?; - self.set_lut(spi, delay, Some(self.refresh))?; + self.set_lut(spi, delay, Some(self.refresh)).await?; } - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; Ok(()) } } @@ -183,7 +187,7 @@ where DELAY: DelayUs, { type DisplayColor = Color; - fn new( + async fn new( spi: &mut SPI, busy: BUSY, dc: DC, @@ -198,16 +202,16 @@ where refresh: RefreshLut::Full, }; - epd.init(spi, delay)?; + epd.init(spi, delay).await?; Ok(epd) } - fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.init(spi, delay) + async fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.init(spi, delay).await } - fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + async fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; // All sample code enables and disables analog/clocks... self.set_display_update_control_2( @@ -217,31 +221,33 @@ where .enable_clock() .disable_analog() .disable_clock(), - )?; - self.command(spi, Command::MasterActivation)?; + ) + .await?; + self.command(spi, Command::MasterActivation).await?; - self.set_sleep_mode(spi, self.sleep_mode)?; + self.set_sleep_mode(spi, self.sleep_mode).await?; Ok(()) } - fn update_frame( + async fn update_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { assert!(buffer.len() == buffer_len(WIDTH as usize, HEIGHT as usize)); - self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1)?; - self.set_ram_address_counters(spi, delay, 0, 0)?; + self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1).await?; + self.set_ram_address_counters(spi, delay, 0, 0).await?; - self.cmd_with_data(spi, Command::WriteRam, buffer)?; + self.cmd_with_data(spi, Command::WriteRam, buffer).await?; if self.refresh == RefreshLut::Full { // Always keep the base buffer equal to current if not doing partial refresh. - self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1)?; - self.set_ram_address_counters(spi, delay, 0, 0)?; + self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1).await?; + self.set_ram_address_counters(spi, delay, 0, 0).await?; - self.cmd_with_data(spi, Command::WriteRamRed, buffer)?; + self.cmd_with_data(spi, Command::WriteRamRed, buffer) + .await?; } Ok(()) } @@ -249,7 +255,7 @@ where /// Updating only a part of the frame is not supported when using the /// partial refresh feature. The function will panic if called when set to /// use partial refresh. - fn update_partial_frame( + async fn update_partial_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -269,17 +275,18 @@ where // incorrect. assert!(self.refresh == RefreshLut::Full); - self.set_ram_area(spi, x, y, x + width, y + height)?; - self.set_ram_address_counters(spi, delay, x, y)?; + self.set_ram_area(spi, x, y, x + width, y + height).await?; + self.set_ram_address_counters(spi, delay, x, y).await?; - self.cmd_with_data(spi, Command::WriteRam, buffer)?; + self.cmd_with_data(spi, Command::WriteRam, buffer).await?; if self.refresh == RefreshLut::Full { // Always keep the base buffer equals to current if not doing partial refresh. - self.set_ram_area(spi, x, y, x + width, y + height)?; - self.set_ram_address_counters(spi, delay, x, y)?; + self.set_ram_area(spi, x, y, x + width, y + height).await?; + self.set_ram_address_counters(spi, delay, x, y).await?; - self.cmd_with_data(spi, Command::WriteRamRed, buffer)?; + self.cmd_with_data(spi, Command::WriteRamRed, buffer) + .await?; } Ok(()) @@ -287,7 +294,7 @@ where /// Never use directly this function when using partial refresh, or also /// keep the base buffer in syncd using `set_partial_base_buffer` function. - fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + async fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { if self.refresh == RefreshLut::Full { self.set_display_update_control_2( spi, @@ -297,55 +304,61 @@ where .display() .disable_analog() .disable_clock(), - )?; + ) + .await?; } else { - self.set_display_update_control_2(spi, DisplayUpdateControl2::new().display())?; + self.set_display_update_control_2(spi, DisplayUpdateControl2::new().display()) + .await?; } - self.command(spi, Command::MasterActivation)?; - self.wait_until_idle(spi, delay)?; + self.command(spi, Command::MasterActivation).await?; + self.wait_until_idle(spi, delay).await?; Ok(()) } - fn update_and_display_frame( + async fn update_and_display_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.update_frame(spi, buffer, delay)?; - self.display_frame(spi, delay)?; + self.update_frame(spi, buffer, delay).await?; + self.display_frame(spi, delay).await?; if self.refresh == RefreshLut::Quick { - self.set_partial_base_buffer(spi, delay, buffer)?; + self.set_partial_base_buffer(spi, delay, buffer).await?; } Ok(()) } - fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + async fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { let color = self.background_color.get_byte_value(); - self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1)?; - self.set_ram_address_counters(spi, delay, 0, 0)?; - - self.command(spi, Command::WriteRam)?; - self.interface.data_x_times( - spi, - color, - buffer_len(WIDTH as usize, HEIGHT as usize) as u32, - )?; + self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1).await?; + self.set_ram_address_counters(spi, delay, 0, 0).await?; - // Always keep the base buffer equals to current if not doing partial refresh. - if self.refresh == RefreshLut::Full { - self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1)?; - self.set_ram_address_counters(spi, delay, 0, 0)?; - - self.command(spi, Command::WriteRamRed)?; - self.interface.data_x_times( + self.command(spi, Command::WriteRam).await?; + self.interface + .data_x_times( spi, color, buffer_len(WIDTH as usize, HEIGHT as usize) as u32, - )?; + ) + .await?; + + // Always keep the base buffer equals to current if not doing partial refresh. + if self.refresh == RefreshLut::Full { + self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1).await?; + self.set_ram_address_counters(spi, delay, 0, 0).await?; + + self.command(spi, Command::WriteRamRed).await?; + self.interface + .data_x_times( + spi, + color, + buffer_len(WIDTH as usize, HEIGHT as usize) as u32, + ) + .await?; } Ok(()) } @@ -366,7 +379,7 @@ where HEIGHT } - fn set_lut( + async fn set_lut( &mut self, spi: &mut SPI, _delay: &mut DELAY, @@ -378,10 +391,15 @@ where }; self.cmd_with_data(spi, Command::WriteLutRegister, buffer) + .await } - fn wait_until_idle(&mut self, _spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.interface.wait_until_idle(delay, IS_BUSY_LOW); + async fn wait_until_idle( + &mut self, + _spi: &mut SPI, + delay: &mut DELAY, + ) -> Result<(), SPI::Error> { + self.interface.wait_until_idle(delay, IS_BUSY_LOW).await; Ok(()) } } @@ -396,17 +414,18 @@ where { /// When using partial refresh, the controller uses the provided buffer for /// comparison with new buffer. - pub fn set_partial_base_buffer( + pub async fn set_partial_base_buffer( &mut self, spi: &mut SPI, delay: &mut DELAY, buffer: &[u8], ) -> Result<(), SPI::Error> { assert!(buffer_len(WIDTH as usize, HEIGHT as usize) == buffer.len()); - self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1)?; - self.set_ram_address_counters(spi, delay, 0, 0)?; + self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1).await?; + self.set_ram_address_counters(spi, delay, 0, 0).await?; - self.cmd_with_data(spi, Command::WriteRamRed, buffer)?; + self.cmd_with_data(spi, Command::WriteRamRed, buffer) + .await?; Ok(()) } @@ -417,7 +436,7 @@ where /// Sets the refresh mode. When changing mode, the screen will be /// re-initialized accordingly. - pub fn set_refresh( + pub async fn set_refresh( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -425,12 +444,12 @@ where ) -> Result<(), SPI::Error> { if self.refresh != refresh { self.refresh = refresh; - self.init(spi, delay)?; + self.init(spi, delay).await?; } Ok(()) } - fn set_gate_scan_start_position( + async fn set_gate_scan_start_position( &mut self, spi: &mut SPI, start: u16, @@ -441,9 +460,10 @@ where Command::GateScanStartPosition, &[(start & 0xFF) as u8, ((start >> 8) & 0x1) as u8], ) + .await } - fn set_border_waveform( + async fn set_border_waveform( &mut self, spi: &mut SPI, borderwaveform: BorderWaveForm, @@ -453,35 +473,40 @@ where Command::BorderWaveformControl, &[borderwaveform.to_u8()], ) + .await } - fn set_vcom_register(&mut self, spi: &mut SPI, vcom: Vcom) -> Result<(), SPI::Error> { + async fn set_vcom_register(&mut self, spi: &mut SPI, vcom: Vcom) -> Result<(), SPI::Error> { self.cmd_with_data(spi, Command::WriteVcomRegister, &[vcom.0]) + .await } - fn set_gate_driving_voltage( + async fn set_gate_driving_voltage( &mut self, spi: &mut SPI, voltage: GateDrivingVoltage, ) -> Result<(), SPI::Error> { self.cmd_with_data(spi, Command::GateDrivingVoltageCtrl, &[voltage.0]) + .await } - fn set_dummy_line_period( + async fn set_dummy_line_period( &mut self, spi: &mut SPI, number_of_lines: u8, ) -> Result<(), SPI::Error> { assert!(number_of_lines <= 127); self.cmd_with_data(spi, Command::SetDummyLinePeriod, &[number_of_lines]) + .await } - fn set_gate_line_width(&mut self, spi: &mut SPI, width: u8) -> Result<(), SPI::Error> { + async fn set_gate_line_width(&mut self, spi: &mut SPI, width: u8) -> Result<(), SPI::Error> { self.cmd_with_data(spi, Command::SetGateLineWidth, &[width & 0x0F]) + .await } /// Sets the source driving voltage value - fn set_source_driving_voltage( + async fn set_source_driving_voltage( &mut self, spi: &mut SPI, vsh1: SourceDrivingVoltage, @@ -493,30 +518,42 @@ where Command::SourceDrivingVoltageCtrl, &[vsh1.0, vsh2.0, vsl.0], ) + .await } /// Prepare the actions that the next master activation command will /// trigger. - fn set_display_update_control_2( + async fn set_display_update_control_2( &mut self, spi: &mut SPI, value: DisplayUpdateControl2, ) -> Result<(), SPI::Error> { self.cmd_with_data(spi, Command::DisplayUpdateControl2, &[value.0]) + .await } /// Triggers the deep sleep mode - fn set_sleep_mode(&mut self, spi: &mut SPI, mode: DeepSleepMode) -> Result<(), SPI::Error> { + async fn set_sleep_mode( + &mut self, + spi: &mut SPI, + mode: DeepSleepMode, + ) -> Result<(), SPI::Error> { self.cmd_with_data(spi, Command::DeepSleepMode, &[mode as u8]) + .await } - fn set_driver_output(&mut self, spi: &mut SPI, output: DriverOutput) -> Result<(), SPI::Error> { + async fn set_driver_output( + &mut self, + spi: &mut SPI, + output: DriverOutput, + ) -> Result<(), SPI::Error> { self.cmd_with_data(spi, Command::DriverOutputControl, &output.to_bytes()) + .await } /// Sets the data entry mode (ie. how X and Y positions changes when writing /// data to RAM) - fn set_data_entry_mode( + async fn set_data_entry_mode( &mut self, spi: &mut SPI, counter_incr_mode: DataEntryModeIncr, @@ -524,10 +561,11 @@ where ) -> Result<(), SPI::Error> { let mode = counter_incr_mode as u8 | counter_direction as u8; self.cmd_with_data(spi, Command::DataEntryModeSetting, &[mode]) + .await } /// Sets both X and Y pixels ranges - fn set_ram_area( + async fn set_ram_area( &mut self, spi: &mut SPI, start_x: u32, @@ -539,7 +577,8 @@ where spi, Command::SetRamXAddressStartEndPosition, &[(start_x >> 3) as u8, (end_x >> 3) as u8], - )?; + ) + .await?; self.cmd_with_data( spi, @@ -551,38 +590,41 @@ where (end_y >> 8) as u8, ], ) + .await } /// Sets both X and Y pixels counters when writing data to RAM - fn set_ram_address_counters( + async fn set_ram_address_counters( &mut self, spi: &mut SPI, delay: &mut DELAY, x: u32, y: u32, ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.cmd_with_data(spi, Command::SetRamXAddressCounter, &[(x >> 3) as u8])?; + self.wait_until_idle(spi, delay).await?; + self.cmd_with_data(spi, Command::SetRamXAddressCounter, &[(x >> 3) as u8]) + .await?; self.cmd_with_data( spi, Command::SetRamYAddressCounter, &[y as u8, (y >> 8) as u8], - )?; + ) + .await?; Ok(()) } - fn command(&mut self, spi: &mut SPI, command: Command) -> Result<(), SPI::Error> { - self.interface.cmd(spi, command) + async fn command(&mut self, spi: &mut SPI, command: Command) -> Result<(), SPI::Error> { + self.interface.cmd(spi, command).await } - fn cmd_with_data( + async fn cmd_with_data( &mut self, spi: &mut SPI, command: Command, data: &[u8], ) -> Result<(), SPI::Error> { - self.interface.cmd_with_data(spi, command, data) + self.interface.cmd_with_data(spi, command, data).await } } diff --git a/src/epd2in13bc/mod.rs b/src/epd2in13bc/mod.rs index 280f47a7..7cf83e24 100644 --- a/src/epd2in13bc/mod.rs +++ b/src/epd2in13bc/mod.rs @@ -50,7 +50,8 @@ //!# Ok(()) //!# } //!``` -use embedded_hal::{delay::*, digital::*, spi::SpiDevice}; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::{delay::DelayUs, spi::SpiDevice}; use crate::interface::DisplayInterface; use crate::traits::{ @@ -106,35 +107,39 @@ where RST: OutputPin, DELAY: DelayUs, { - fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + async fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { // Values taken from datasheet and sample code - self.interface.reset(delay, 10_000, 10_000); + self.interface.reset(delay, 10_000, 10_000).await; // start the booster self.interface - .cmd_with_data(spi, Command::BoosterSoftStart, &[0x17, 0x17, 0x17])?; + .cmd_with_data(spi, Command::BoosterSoftStart, &[0x17, 0x17, 0x17]) + .await?; // power on - self.command(spi, Command::PowerOn)?; - delay.delay_us(5000); - self.wait_until_idle(spi, delay)?; + self.command(spi, Command::PowerOn).await?; + delay.delay_us(5000).await; + self.wait_until_idle(spi, delay).await?; // set the panel settings - self.cmd_with_data(spi, Command::PanelSetting, &[0x8F])?; + self.cmd_with_data(spi, Command::PanelSetting, &[0x8F]) + .await?; self.cmd_with_data( spi, Command::VcomAndDataIntervalSetting, &[WHITE_BORDER | VCOM_DATA_INTERVAL], - )?; + ) + .await?; // set resolution - self.send_resolution(spi)?; + self.send_resolution(spi).await?; - self.cmd_with_data(spi, Command::VcmDcSetting, &[0x0A])?; + self.cmd_with_data(spi, Command::VcmDcSetting, &[0x0A]) + .await?; - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; Ok(()) } @@ -149,44 +154,48 @@ where RST: OutputPin, DELAY: DelayUs, { - fn update_color_frame( + async fn update_color_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, black: &[u8], chromatic: &[u8], ) -> Result<(), SPI::Error> { - self.update_achromatic_frame(spi, delay, black)?; - self.update_chromatic_frame(spi, delay, chromatic) + self.update_achromatic_frame(spi, delay, black).await?; + self.update_chromatic_frame(spi, delay, chromatic).await } /// Update only the black/white data of the display. /// /// Finish by calling `update_chromatic_frame`. - fn update_achromatic_frame( + async fn update_achromatic_frame( &mut self, spi: &mut SPI, _delay: &mut DELAY, black: &[u8], ) -> Result<(), SPI::Error> { - self.interface.cmd(spi, Command::DataStartTransmission1)?; - self.interface.data(spi, black)?; + self.interface + .cmd(spi, Command::DataStartTransmission1) + .await?; + self.interface.data(spi, black).await?; Ok(()) } /// Update only chromatic data of the display. /// /// This data takes precedence over the black/white data. - fn update_chromatic_frame( + async fn update_chromatic_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, chromatic: &[u8], ) -> Result<(), SPI::Error> { - self.interface.cmd(spi, Command::DataStartTransmission2)?; - self.interface.data(spi, chromatic)?; + self.interface + .cmd(spi, Command::DataStartTransmission2) + .await?; + self.interface.data(spi, chromatic).await?; - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; Ok(()) } } @@ -201,7 +210,7 @@ where DELAY: DelayUs, { type DisplayColor = TriColor; - fn new( + async fn new( spi: &mut SPI, busy: BUSY, dc: DC, @@ -214,30 +223,32 @@ where let mut epd = Epd2in13bc { interface, color }; - epd.init(spi, delay)?; + epd.init(spi, delay).await?; Ok(epd) } - fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + async fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { // Section 8.2 from datasheet - self.interface.cmd_with_data( - spi, - Command::VcomAndDataIntervalSetting, - &[FLOATING_BORDER | VCOM_DATA_INTERVAL], - )?; - - self.command(spi, Command::PowerOff)?; + self.interface + .cmd_with_data( + spi, + Command::VcomAndDataIntervalSetting, + &[FLOATING_BORDER | VCOM_DATA_INTERVAL], + ) + .await?; + + self.command(spi, Command::PowerOff).await?; // The example STM code from Github has a wait after PowerOff - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; - self.cmd_with_data(spi, Command::DeepSleep, &[0xA5])?; + self.cmd_with_data(spi, Command::DeepSleep, &[0xA5]).await?; Ok(()) } - fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.init(spi, delay) + async fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.init(spi, delay).await } fn set_background_color(&mut self, color: TriColor) { @@ -256,28 +267,34 @@ where HEIGHT } - fn update_frame( + async fn update_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.interface.cmd(spi, Command::DataStartTransmission1)?; + self.interface + .cmd(spi, Command::DataStartTransmission1) + .await?; - self.interface.data(spi, buffer)?; + self.interface.data(spi, buffer).await?; // Clear the chromatic layer let color = self.color.get_byte_value(); - self.interface.cmd(spi, Command::DataStartTransmission2)?; - self.interface.data_x_times(spi, color, NUM_DISPLAY_BITS)?; + self.interface + .cmd(spi, Command::DataStartTransmission2) + .await?; + self.interface + .data_x_times(spi, color, NUM_DISPLAY_BITS) + .await?; - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; Ok(()) } #[allow(unused)] - fn update_partial_frame( + async fn update_partial_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -290,43 +307,51 @@ where Ok(()) } - fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.command(spi, Command::DisplayRefresh)?; + async fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.command(spi, Command::DisplayRefresh).await?; - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; Ok(()) } - fn update_and_display_frame( + async fn update_and_display_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.update_frame(spi, buffer, delay)?; - self.display_frame(spi, delay)?; + self.update_frame(spi, buffer, delay).await?; + self.display_frame(spi, delay).await?; Ok(()) } - fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.send_resolution(spi)?; + async fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.send_resolution(spi).await?; let color = DEFAULT_BACKGROUND_COLOR.get_byte_value(); // Clear the black - self.interface.cmd(spi, Command::DataStartTransmission1)?; + self.interface + .cmd(spi, Command::DataStartTransmission1) + .await?; - self.interface.data_x_times(spi, color, NUM_DISPLAY_BITS)?; + self.interface + .data_x_times(spi, color, NUM_DISPLAY_BITS) + .await?; // Clear the chromatic - self.interface.cmd(spi, Command::DataStartTransmission2)?; - self.interface.data_x_times(spi, color, NUM_DISPLAY_BITS)?; + self.interface + .cmd(spi, Command::DataStartTransmission2) + .await?; + self.interface + .data_x_times(spi, color, NUM_DISPLAY_BITS) + .await?; - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; Ok(()) } - fn set_lut( + async fn set_lut( &mut self, _spi: &mut SPI, _delay: &mut DELAY, @@ -335,8 +360,12 @@ where Ok(()) } - fn wait_until_idle(&mut self, _spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.interface.wait_until_idle(delay, IS_BUSY_LOW); + async fn wait_until_idle( + &mut self, + _spi: &mut SPI, + delay: &mut DELAY, + ) -> Result<(), SPI::Error> { + self.interface.wait_until_idle(delay, IS_BUSY_LOW).await; Ok(()) } } @@ -349,36 +378,40 @@ where RST: OutputPin, DELAY: DelayUs, { - fn command(&mut self, spi: &mut SPI, command: Command) -> Result<(), SPI::Error> { - self.interface.cmd(spi, command) + async fn command(&mut self, spi: &mut SPI, command: Command) -> Result<(), SPI::Error> { + self.interface.cmd(spi, command).await } - fn send_data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> { - self.interface.data(spi, data) + async fn send_data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> { + self.interface.data(spi, data).await } - fn cmd_with_data( + async fn cmd_with_data( &mut self, spi: &mut SPI, command: Command, data: &[u8], ) -> Result<(), SPI::Error> { - self.interface.cmd_with_data(spi, command, data) + self.interface.cmd_with_data(spi, command, data).await } - fn send_resolution(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { + async fn send_resolution(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { let w = self.width(); let h = self.height(); - self.command(spi, Command::ResolutionSetting)?; + self.command(spi, Command::ResolutionSetting).await?; - self.send_data(spi, &[w as u8])?; - self.send_data(spi, &[(h >> 8) as u8])?; - self.send_data(spi, &[h as u8]) + self.send_data(spi, &[w as u8]).await?; + self.send_data(spi, &[(h >> 8) as u8]).await?; + self.send_data(spi, &[h as u8]).await } /// Set the outer border of the display to the chosen color. - pub fn set_border_color(&mut self, spi: &mut SPI, color: TriColor) -> Result<(), SPI::Error> { + pub async fn set_border_color( + &mut self, + spi: &mut SPI, + color: TriColor, + ) -> Result<(), SPI::Error> { let border = match color { TriColor::Black => BLACK_BORDER, TriColor::White => WHITE_BORDER, @@ -389,5 +422,6 @@ where Command::VcomAndDataIntervalSetting, &[border | VCOM_DATA_INTERVAL], ) + .await } } diff --git a/src/epd2in7b/mod.rs b/src/epd2in7b/mod.rs index 941d0393..83110645 100644 --- a/src/epd2in7b/mod.rs +++ b/src/epd2in7b/mod.rs @@ -2,7 +2,8 @@ //! //! [Documentation](https://www.waveshare.com/wiki/2.7inch_e-Paper_HAT_(B)) -use embedded_hal::{delay::*, digital::*, spi::SpiDevice}; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::{delay::DelayUs, spi::SpiDevice}; use crate::interface::DisplayInterface; use crate::traits::{ @@ -56,58 +57,67 @@ where RST: OutputPin, DELAY: DelayUs, { - fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + async fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { // reset the device - self.interface.reset(delay, 10_000, 2_000); + self.interface.reset(delay, 10_000, 2_000).await; // power on - self.command(spi, Command::PowerOn)?; - delay.delay_us(5000); - self.wait_until_idle(spi, delay)?; + self.command(spi, Command::PowerOn).await?; + delay.delay_us(5000).await; + self.wait_until_idle(spi, delay).await?; // set panel settings, 0xbf is bw, 0xaf is multi-color self.interface - .cmd_with_data(spi, Command::PanelSetting, &[0xaf])?; + .cmd_with_data(spi, Command::PanelSetting, &[0xaf]) + .await?; // pll control self.interface - .cmd_with_data(spi, Command::PllControl, &[0x3a])?; + .cmd_with_data(spi, Command::PllControl, &[0x3a]) + .await?; // set the power settings - self.interface.cmd_with_data( - spi, - Command::PowerSetting, - &[0x03, 0x00, 0x2b, 0x2b, 0x09], - )?; + self.interface + .cmd_with_data(spi, Command::PowerSetting, &[0x03, 0x00, 0x2b, 0x2b, 0x09]) + .await?; // start the booster self.interface - .cmd_with_data(spi, Command::BoosterSoftStart, &[0x07, 0x07, 0x17])?; + .cmd_with_data(spi, Command::BoosterSoftStart, &[0x07, 0x07, 0x17]) + .await?; // power optimization self.interface - .cmd_with_data(spi, Command::PowerOptimization, &[0x60, 0xa5])?; + .cmd_with_data(spi, Command::PowerOptimization, &[0x60, 0xa5]) + .await?; self.interface - .cmd_with_data(spi, Command::PowerOptimization, &[0x89, 0xa5])?; + .cmd_with_data(spi, Command::PowerOptimization, &[0x89, 0xa5]) + .await?; self.interface - .cmd_with_data(spi, Command::PowerOptimization, &[0x90, 0x00])?; + .cmd_with_data(spi, Command::PowerOptimization, &[0x90, 0x00]) + .await?; self.interface - .cmd_with_data(spi, Command::PowerOptimization, &[0x93, 0x2a])?; + .cmd_with_data(spi, Command::PowerOptimization, &[0x93, 0x2a]) + .await?; self.interface - .cmd_with_data(spi, Command::PowerOptimization, &[0x73, 0x41])?; + .cmd_with_data(spi, Command::PowerOptimization, &[0x73, 0x41]) + .await?; self.interface - .cmd_with_data(spi, Command::VcmDcSetting, &[0x12])?; + .cmd_with_data(spi, Command::VcmDcSetting, &[0x12]) + .await?; self.interface - .cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x87])?; + .cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x87]) + .await?; - self.set_lut(spi, delay, None)?; + self.set_lut(spi, delay, None).await?; self.interface - .cmd_with_data(spi, Command::PartialDisplayRefresh, &[0x00])?; + .cmd_with_data(spi, Command::PartialDisplayRefresh, &[0x00]) + .await?; - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; Ok(()) } } @@ -122,7 +132,7 @@ where DELAY: DelayUs, { type DisplayColor = Color; - fn new( + async fn new( spi: &mut SPI, busy: BUSY, dc: DC, @@ -135,46 +145,53 @@ where let mut epd = Epd2in7b { interface, color }; - epd.init(spi, delay)?; + epd.init(spi, delay).await?; Ok(epd) } - fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.init(spi, delay) + async fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.init(spi, delay).await } - fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + async fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; self.interface - .cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0xf7])?; + .cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0xf7]) + .await?; - self.command(spi, Command::PowerOff)?; - self.wait_until_idle(spi, delay)?; + self.command(spi, Command::PowerOff).await?; + self.wait_until_idle(spi, delay).await?; self.interface - .cmd_with_data(spi, Command::DeepSleep, &[0xA5])?; + .cmd_with_data(spi, Command::DeepSleep, &[0xA5]) + .await?; Ok(()) } - fn update_frame( + async fn update_frame( &mut self, spi: &mut SPI, buffer: &[u8], _delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.interface.cmd(spi, Command::DataStartTransmission1)?; - self.send_buffer_helper(spi, buffer)?; + self.interface + .cmd(spi, Command::DataStartTransmission1) + .await?; + self.send_buffer_helper(spi, buffer).await?; // Clear chromatic layer since we won't be using it here - self.interface.cmd(spi, Command::DataStartTransmission2)?; self.interface - .data_x_times(spi, !self.color.get_byte_value(), WIDTH * HEIGHT / 8)?; + .cmd(spi, Command::DataStartTransmission2) + .await?; + self.interface + .data_x_times(spi, !self.color.get_byte_value(), WIDTH * HEIGHT / 8) + .await?; - self.interface.cmd(spi, Command::DataStop)?; + self.interface.cmd(spi, Command::DataStop).await?; Ok(()) } - fn update_partial_frame( + async fn update_partial_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -185,54 +202,61 @@ where height: u32, ) -> Result<(), SPI::Error> { self.interface - .cmd(spi, Command::PartialDataStartTransmission1)?; - - self.send_data(spi, &[(x >> 8) as u8])?; - self.send_data(spi, &[(x & 0xf8) as u8])?; - self.send_data(spi, &[(y >> 8) as u8])?; - self.send_data(spi, &[(y & 0xff) as u8])?; - self.send_data(spi, &[(width >> 8) as u8])?; - self.send_data(spi, &[(width & 0xf8) as u8])?; - self.send_data(spi, &[(height >> 8) as u8])?; - self.send_data(spi, &[(height & 0xff) as u8])?; - self.wait_until_idle(spi, delay)?; - - self.send_buffer_helper(spi, buffer)?; - - self.interface.cmd(spi, Command::DataStop) + .cmd(spi, Command::PartialDataStartTransmission1) + .await?; + + self.send_data(spi, &[(x >> 8) as u8]).await?; + self.send_data(spi, &[(x & 0xf8) as u8]).await?; + self.send_data(spi, &[(y >> 8) as u8]).await?; + self.send_data(spi, &[(y & 0xff) as u8]).await?; + self.send_data(spi, &[(width >> 8) as u8]).await?; + self.send_data(spi, &[(width & 0xf8) as u8]).await?; + self.send_data(spi, &[(height >> 8) as u8]).await?; + self.send_data(spi, &[(height & 0xff) as u8]).await?; + self.wait_until_idle(spi, delay).await?; + + self.send_buffer_helper(spi, buffer).await?; + + self.interface.cmd(spi, Command::DataStop).await } - fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.command(spi, Command::DisplayRefresh)?; - self.wait_until_idle(spi, delay)?; + async fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.command(spi, Command::DisplayRefresh).await?; + self.wait_until_idle(spi, delay).await?; Ok(()) } - fn update_and_display_frame( + async fn update_and_display_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.update_frame(spi, buffer, delay)?; - self.command(spi, Command::DisplayRefresh)?; + self.update_frame(spi, buffer, delay).await?; + self.command(spi, Command::DisplayRefresh).await?; Ok(()) } - fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + async fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; let color_value = self.color.get_byte_value(); - self.interface.cmd(spi, Command::DataStartTransmission1)?; self.interface - .data_x_times(spi, color_value, WIDTH * HEIGHT / 8)?; + .cmd(spi, Command::DataStartTransmission1) + .await?; + self.interface + .data_x_times(spi, color_value, WIDTH * HEIGHT / 8) + .await?; - self.interface.cmd(spi, Command::DataStop)?; + self.interface.cmd(spi, Command::DataStop).await?; - self.interface.cmd(spi, Command::DataStartTransmission2)?; self.interface - .data_x_times(spi, color_value, WIDTH * HEIGHT / 8)?; - self.interface.cmd(spi, Command::DataStop)?; + .cmd(spi, Command::DataStartTransmission2) + .await?; + self.interface + .data_x_times(spi, color_value, WIDTH * HEIGHT / 8) + .await?; + self.interface.cmd(spi, Command::DataStop).await?; Ok(()) } @@ -252,23 +276,32 @@ where HEIGHT } - fn set_lut( + async fn set_lut( &mut self, spi: &mut SPI, delay: &mut DELAY, _refresh_rate: Option, ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.cmd_with_data(spi, Command::LutForVcom, &LUT_VCOM_DC)?; - self.cmd_with_data(spi, Command::LutWhiteToWhite, &LUT_WW)?; - self.cmd_with_data(spi, Command::LutBlackToWhite, &LUT_BW)?; - self.cmd_with_data(spi, Command::LutWhiteToBlack, &LUT_WB)?; - self.cmd_with_data(spi, Command::LutBlackToBlack, &LUT_BB)?; + self.wait_until_idle(spi, delay).await?; + self.cmd_with_data(spi, Command::LutForVcom, &LUT_VCOM_DC) + .await?; + self.cmd_with_data(spi, Command::LutWhiteToWhite, &LUT_WW) + .await?; + self.cmd_with_data(spi, Command::LutBlackToWhite, &LUT_BW) + .await?; + self.cmd_with_data(spi, Command::LutWhiteToBlack, &LUT_WB) + .await?; + self.cmd_with_data(spi, Command::LutBlackToBlack, &LUT_BB) + .await?; Ok(()) } - fn wait_until_idle(&mut self, _spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.interface.wait_until_idle(delay, IS_BUSY_LOW); + async fn wait_until_idle( + &mut self, + _spi: &mut SPI, + delay: &mut DELAY, + ) -> Result<(), SPI::Error> { + self.interface.wait_until_idle(delay, IS_BUSY_LOW).await; Ok(()) } } @@ -282,48 +315,52 @@ where RST: OutputPin, DELAY: DelayUs, { - fn update_color_frame( + async fn update_color_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, black: &[u8], chromatic: &[u8], ) -> Result<(), SPI::Error> { - self.update_achromatic_frame(spi, delay, black)?; - self.update_chromatic_frame(spi, delay, chromatic) + self.update_achromatic_frame(spi, delay, black).await?; + self.update_chromatic_frame(spi, delay, chromatic).await } /// Update only the black/white data of the display. /// /// Finish by calling `update_chromatic_frame`. - fn update_achromatic_frame( + async fn update_achromatic_frame( &mut self, spi: &mut SPI, _delay: &mut DELAY, achromatic: &[u8], ) -> Result<(), SPI::Error> { - self.interface.cmd(spi, Command::DataStartTransmission1)?; + self.interface + .cmd(spi, Command::DataStartTransmission1) + .await?; - self.send_buffer_helper(spi, achromatic)?; + self.send_buffer_helper(spi, achromatic).await?; - self.interface.cmd(spi, Command::DataStop) + self.interface.cmd(spi, Command::DataStop).await } /// Update only chromatic data of the display. /// /// This data takes precedence over the black/white data. - fn update_chromatic_frame( + async fn update_chromatic_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, chromatic: &[u8], ) -> Result<(), SPI::Error> { - self.interface.cmd(spi, Command::DataStartTransmission2)?; + self.interface + .cmd(spi, Command::DataStartTransmission2) + .await?; - self.send_buffer_helper(spi, chromatic)?; + self.send_buffer_helper(spi, chromatic).await?; - self.interface.cmd(spi, Command::DataStop)?; - self.wait_until_idle(spi, delay)?; + self.interface.cmd(spi, Command::DataStop).await?; + self.wait_until_idle(spi, delay).await?; Ok(()) } @@ -337,34 +374,34 @@ where RST: OutputPin, DELAY: DelayUs, { - fn command(&mut self, spi: &mut SPI, command: Command) -> Result<(), SPI::Error> { - self.interface.cmd(spi, command) + async fn command(&mut self, spi: &mut SPI, command: Command) -> Result<(), SPI::Error> { + self.interface.cmd(spi, command).await } - fn send_data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> { - self.interface.data(spi, data) + async fn send_data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> { + self.interface.data(spi, data).await } - fn send_buffer_helper(&mut self, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> { + async fn send_buffer_helper(&mut self, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> { // Based on the waveshare implementation, all data for color values is flipped. This helper // method makes that transmission easier for b in buffer.iter() { - self.send_data(spi, &[!b])?; + self.send_data(spi, &[!b]).await?; } Ok(()) } - fn cmd_with_data( + async fn cmd_with_data( &mut self, spi: &mut SPI, command: Command, data: &[u8], ) -> Result<(), SPI::Error> { - self.interface.cmd_with_data(spi, command, data) + self.interface.cmd_with_data(spi, command, data).await } /// Refresh display for partial frame - pub fn display_partial_frame( + pub async fn display_partial_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -373,22 +410,22 @@ where width: u32, height: u32, ) -> Result<(), SPI::Error> { - self.command(spi, Command::PartialDisplayRefresh)?; - self.send_data(spi, &[(x >> 8) as u8])?; - self.send_data(spi, &[(x & 0xf8) as u8])?; - self.send_data(spi, &[(y >> 8) as u8])?; - self.send_data(spi, &[(y & 0xff) as u8])?; - self.send_data(spi, &[(width >> 8) as u8])?; - self.send_data(spi, &[(width & 0xf8) as u8])?; - self.send_data(spi, &[(height >> 8) as u8])?; - self.send_data(spi, &[(height & 0xff) as u8])?; - self.wait_until_idle(spi, delay)?; + self.command(spi, Command::PartialDisplayRefresh).await?; + self.send_data(spi, &[(x >> 8) as u8]).await?; + self.send_data(spi, &[(x & 0xf8) as u8]).await?; + self.send_data(spi, &[(y >> 8) as u8]).await?; + self.send_data(spi, &[(y & 0xff) as u8]).await?; + self.send_data(spi, &[(width >> 8) as u8]).await?; + self.send_data(spi, &[(width & 0xf8) as u8]).await?; + self.send_data(spi, &[(height >> 8) as u8]).await?; + self.send_data(spi, &[(height & 0xff) as u8]).await?; + self.wait_until_idle(spi, delay).await?; Ok(()) } /// Update black/achromatic frame #[allow(clippy::too_many_arguments)] - pub fn update_partial_achromatic_frame( + pub async fn update_partial_achromatic_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -399,20 +436,21 @@ where height: u32, ) -> Result<(), SPI::Error> { self.interface - .cmd(spi, Command::PartialDataStartTransmission1)?; - self.send_data(spi, &[(x >> 8) as u8])?; - self.send_data(spi, &[(x & 0xf8) as u8])?; - self.send_data(spi, &[(y >> 8) as u8])?; - self.send_data(spi, &[(y & 0xff) as u8])?; - self.send_data(spi, &[(width >> 8) as u8])?; - self.send_data(spi, &[(width & 0xf8) as u8])?; - self.send_data(spi, &[(height >> 8) as u8])?; - self.send_data(spi, &[(height & 0xff) as u8])?; - self.wait_until_idle(spi, delay)?; + .cmd(spi, Command::PartialDataStartTransmission1) + .await?; + self.send_data(spi, &[(x >> 8) as u8]).await?; + self.send_data(spi, &[(x & 0xf8) as u8]).await?; + self.send_data(spi, &[(y >> 8) as u8]).await?; + self.send_data(spi, &[(y & 0xff) as u8]).await?; + self.send_data(spi, &[(width >> 8) as u8]).await?; + self.send_data(spi, &[(width & 0xf8) as u8]).await?; + self.send_data(spi, &[(height >> 8) as u8]).await?; + self.send_data(spi, &[(height & 0xff) as u8]).await?; + self.wait_until_idle(spi, delay).await?; for b in achromatic.iter() { // Flipping based on waveshare implementation - self.send_data(spi, &[!b])?; + self.send_data(spi, &[!b]).await?; } Ok(()) @@ -420,7 +458,7 @@ where /// Update partial chromatic/red frame #[allow(clippy::too_many_arguments)] - pub fn update_partial_chromatic_frame( + pub async fn update_partial_chromatic_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -431,20 +469,21 @@ where height: u32, ) -> Result<(), SPI::Error> { self.interface - .cmd(spi, Command::PartialDataStartTransmission2)?; - self.send_data(spi, &[(x >> 8) as u8])?; - self.send_data(spi, &[(x & 0xf8) as u8])?; - self.send_data(spi, &[(y >> 8) as u8])?; - self.send_data(spi, &[(y & 0xff) as u8])?; - self.send_data(spi, &[(width >> 8) as u8])?; - self.send_data(spi, &[(width & 0xf8) as u8])?; - self.send_data(spi, &[(height >> 8) as u8])?; - self.send_data(spi, &[(height & 0xff) as u8])?; - self.wait_until_idle(spi, delay)?; + .cmd(spi, Command::PartialDataStartTransmission2) + .await?; + self.send_data(spi, &[(x >> 8) as u8]).await?; + self.send_data(spi, &[(x & 0xf8) as u8]).await?; + self.send_data(spi, &[(y >> 8) as u8]).await?; + self.send_data(spi, &[(y & 0xff) as u8]).await?; + self.send_data(spi, &[(width >> 8) as u8]).await?; + self.send_data(spi, &[(width & 0xf8) as u8]).await?; + self.send_data(spi, &[(height >> 8) as u8]).await?; + self.send_data(spi, &[(height & 0xff) as u8]).await?; + self.wait_until_idle(spi, delay).await?; for b in chromatic.iter() { // Flipping based on waveshare implementation - self.send_data(spi, &[!b])?; + self.send_data(spi, &[!b]).await?; } Ok(()) diff --git a/src/epd2in9/mod.rs b/src/epd2in9/mod.rs index 6e3e178d..17996fc7 100644 --- a/src/epd2in9/mod.rs +++ b/src/epd2in9/mod.rs @@ -50,7 +50,8 @@ pub const DEFAULT_BACKGROUND_COLOR: Color = Color::White; const IS_BUSY_LOW: bool = false; const SINGLE_BYTE_WRITE: bool = true; -use embedded_hal::{delay::*, digital::*, spi::SpiDevice}; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::{delay::DelayUs, spi::SpiDevice}; use crate::type_a::{ command::Command, @@ -93,10 +94,10 @@ where RST: OutputPin, DELAY: DelayUs, { - fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.interface.reset(delay, 10_000, 10_000); + async fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.interface.reset(delay, 10_000, 10_000).await; - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; // 3 Databytes: // A[7:0] @@ -104,7 +105,8 @@ where // 0.. B[2:0] // Default Values: A = Height of Screen (0x127), B = 0x00 (GD, SM and TB=0?) self.interface - .cmd_with_data(spi, Command::DriverOutputControl, &[0x27, 0x01, 0x00])?; + .cmd_with_data(spi, Command::DriverOutputControl, &[0x27, 0x01, 0x00]) + .await?; // 3 Databytes: (and default values from datasheet and arduino) // 1 .. A[6:0] = 0xCF | 0xD7 @@ -112,26 +114,31 @@ where // 1 .. C[6:0] = 0x8D | 0x9D //TODO: test self.interface - .cmd_with_data(spi, Command::BoosterSoftStartControl, &[0xD7, 0xD6, 0x9D])?; + .cmd_with_data(spi, Command::BoosterSoftStartControl, &[0xD7, 0xD6, 0x9D]) + .await?; // One Databyte with value 0xA8 for 7V VCOM self.interface - .cmd_with_data(spi, Command::WriteVcomRegister, &[0xA8])?; + .cmd_with_data(spi, Command::WriteVcomRegister, &[0xA8]) + .await?; // One Databyte with default value 0x1A for 4 dummy lines per gate self.interface - .cmd_with_data(spi, Command::SetDummyLinePeriod, &[0x1A])?; + .cmd_with_data(spi, Command::SetDummyLinePeriod, &[0x1A]) + .await?; // One Databyte with default value 0x08 for 2us per line self.interface - .cmd_with_data(spi, Command::SetGateLineWidth, &[0x08])?; + .cmd_with_data(spi, Command::SetGateLineWidth, &[0x08]) + .await?; // One Databyte with default value 0x03 // -> address: x increment, y increment, address counter is updated in x direction self.interface - .cmd_with_data(spi, Command::DataEntryModeSetting, &[0x03])?; + .cmd_with_data(spi, Command::DataEntryModeSetting, &[0x03]) + .await?; - self.set_lut(spi, delay, None) + self.set_lut(spi, delay, None).await } } @@ -153,7 +160,7 @@ where HEIGHT } - fn new( + async fn new( spi: &mut SPI, busy: BUSY, dc: DC, @@ -169,42 +176,44 @@ where refresh: RefreshLut::Full, }; - epd.init(spi, delay)?; + epd.init(spi, delay).await?; Ok(epd) } - fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + async fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; // 0x00 for Normal mode (Power on Reset), 0x01 for Deep Sleep Mode //TODO: is 0x00 needed here? (see also epd1in54) self.interface - .cmd_with_data(spi, Command::DeepSleepMode, &[0x00])?; + .cmd_with_data(spi, Command::DeepSleepMode, &[0x00]) + .await?; Ok(()) } - fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.init(spi, delay)?; + async fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; + self.init(spi, delay).await?; Ok(()) } - fn update_frame( + async fn update_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.use_full_frame(spi, delay)?; + self.wait_until_idle(spi, delay).await?; + self.use_full_frame(spi, delay).await?; self.interface - .cmd_with_data(spi, Command::WriteRam, buffer)?; + .cmd_with_data(spi, Command::WriteRam, buffer) + .await?; Ok(()) } //TODO: update description: last 3 bits will be ignored for width and x_pos - fn update_partial_frame( + async fn update_partial_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -214,50 +223,53 @@ where width: u32, height: u32, ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.set_ram_area(spi, x, y, x + width, y + height)?; - self.set_ram_counter(spi, delay, x, y)?; + self.wait_until_idle(spi, delay).await?; + self.set_ram_area(spi, x, y, x + width, y + height).await?; + self.set_ram_counter(spi, delay, x, y).await?; self.interface - .cmd_with_data(spi, Command::WriteRam, buffer)?; + .cmd_with_data(spi, Command::WriteRam, buffer) + .await?; Ok(()) } - fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + async fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; // 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 - .cmd_with_data(spi, Command::DisplayUpdateControl2, &[0xC4])?; + .cmd_with_data(spi, Command::DisplayUpdateControl2, &[0xC4]) + .await?; - self.interface.cmd(spi, Command::MasterActivation)?; + self.interface.cmd(spi, Command::MasterActivation).await?; // MASTER Activation should not be interupted to avoid currption of panel images // therefore a terminate command is send - self.interface.cmd(spi, Command::Nop)?; + self.interface.cmd(spi, Command::Nop).await?; Ok(()) } - fn update_and_display_frame( + async fn update_and_display_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.update_frame(spi, buffer, delay)?; - self.display_frame(spi, delay)?; + self.update_frame(spi, buffer, delay).await?; + self.display_frame(spi, delay).await?; Ok(()) } - fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.use_full_frame(spi, delay)?; + async fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; + self.use_full_frame(spi, delay).await?; // clear the ram with the background color let color = self.background_color.get_byte_value(); - self.interface.cmd(spi, Command::WriteRam)?; + self.interface.cmd(spi, Command::WriteRam).await?; self.interface - .data_x_times(spi, color, WIDTH / 8 * HEIGHT)?; + .data_x_times(spi, color, WIDTH / 8 * HEIGHT) + .await?; Ok(()) } @@ -269,7 +281,7 @@ where &self.background_color } - fn set_lut( + async fn set_lut( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -279,13 +291,17 @@ where self.refresh = refresh_lut; } match self.refresh { - RefreshLut::Full => self.set_lut_helper(spi, delay, &LUT_FULL_UPDATE), - RefreshLut::Quick => self.set_lut_helper(spi, delay, &LUT_PARTIAL_UPDATE), + RefreshLut::Full => self.set_lut_helper(spi, delay, &LUT_FULL_UPDATE).await, + RefreshLut::Quick => self.set_lut_helper(spi, delay, &LUT_PARTIAL_UPDATE).await, } } - fn wait_until_idle(&mut self, _spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.interface.wait_until_idle(delay, IS_BUSY_LOW); + async fn wait_until_idle( + &mut self, + _spi: &mut SPI, + delay: &mut DELAY, + ) -> Result<(), SPI::Error> { + self.interface.wait_until_idle(delay, IS_BUSY_LOW).await; Ok(()) } } @@ -298,15 +314,15 @@ where RST: OutputPin, DELAY: DelayUs, { - fn use_full_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + async fn use_full_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { // choose full frame/ram - self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1)?; + self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1).await?; // start from the beginning - self.set_ram_counter(spi, delay, 0, 0) + self.set_ram_counter(spi, delay, 0, 0).await } - fn set_ram_area( + async fn set_ram_area( &mut self, spi: &mut SPI, start_x: u32, @@ -319,58 +335,66 @@ where // 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::SetRamXAddressStartEndPosition, - &[(start_x >> 3) as u8, (end_x >> 3) as u8], - )?; + self.interface + .cmd_with_data( + spi, + Command::SetRamXAddressStartEndPosition, + &[(start_x >> 3) as u8, (end_x >> 3) as u8], + ) + .await?; // 2 Databytes: A[7:0] & 0..A[8] for each - start and end - self.interface.cmd_with_data( - spi, - Command::SetRamYAddressStartEndPosition, - &[ - start_y as u8, - (start_y >> 8) as u8, - end_y as u8, - (end_y >> 8) as u8, - ], - ) + self.interface + .cmd_with_data( + spi, + Command::SetRamYAddressStartEndPosition, + &[ + start_y as u8, + (start_y >> 8) as u8, + end_y as u8, + (end_y >> 8) as u8, + ], + ) + .await } - fn set_ram_counter( + async fn set_ram_counter( &mut self, spi: &mut SPI, delay: &mut DELAY, x: u32, y: u32, ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; // 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::SetRamXAddressCounter, &[(x >> 3) as u8])?; + .cmd_with_data(spi, Command::SetRamXAddressCounter, &[(x >> 3) as u8]) + .await?; // 2 Databytes: A[7:0] & 0..A[8] - self.interface.cmd_with_data( - spi, - Command::SetRamYAddressCounter, - &[y as u8, (y >> 8) as u8], - )?; + self.interface + .cmd_with_data( + spi, + Command::SetRamYAddressCounter, + &[y as u8, (y >> 8) as u8], + ) + .await?; Ok(()) } /// Set your own LUT, this function is also used internally for set_lut - fn set_lut_helper( + async fn set_lut_helper( &mut self, spi: &mut SPI, delay: &mut DELAY, buffer: &[u8], ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; assert!(buffer.len() == 30); self.interface - .cmd_with_data(spi, Command::WriteLutRegister, buffer)?; + .cmd_with_data(spi, Command::WriteLutRegister, buffer) + .await?; Ok(()) } } diff --git a/src/epd2in9_v2/mod.rs b/src/epd2in9_v2/mod.rs index 7004a77e..624195c9 100644 --- a/src/epd2in9_v2/mod.rs +++ b/src/epd2in9_v2/mod.rs @@ -75,7 +75,8 @@ const LUT_PARTIAL_2IN9: [u8; 159] = [ 0x22, 0x0, 0x0, 0x0, 0x22, 0x17, 0x41, 0xB0, 0x32, 0x36, ]; -use embedded_hal::{delay::*, digital::*, spi::SpiDevice}; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::{delay::DelayUs, spi::SpiDevice}; use crate::type_a::command::Command; @@ -116,12 +117,12 @@ where RST: OutputPin, DELAY: DelayUs, { - fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.interface.reset(delay, 10_000, 2_000); + async fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.interface.reset(delay, 10_000, 2_000).await; - self.wait_until_idle(spi, delay)?; - self.interface.cmd(spi, Command::SwReset)?; - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; + self.interface.cmd(spi, Command::SwReset).await?; + self.wait_until_idle(spi, delay).await?; // 3 Databytes: // A[7:0] @@ -129,21 +130,24 @@ where // 0.. B[2:0] // Default Values: A = Height of Screen (0x127), B = 0x00 (GD, SM and TB=0?) self.interface - .cmd_with_data(spi, Command::DriverOutputControl, &[0x27, 0x01, 0x00])?; + .cmd_with_data(spi, Command::DriverOutputControl, &[0x27, 0x01, 0x00]) + .await?; // One Databyte with default value 0x03 // -> address: x increment, y increment, address counter is updated in x direction self.interface - .cmd_with_data(spi, Command::DataEntryModeSetting, &[0x03])?; + .cmd_with_data(spi, Command::DataEntryModeSetting, &[0x03]) + .await?; - self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1)?; + self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1).await?; self.interface - .cmd_with_data(spi, Command::DisplayUpdateControl1, &[0x00, 0x80])?; + .cmd_with_data(spi, Command::DisplayUpdateControl1, &[0x00, 0x80]) + .await?; - self.set_ram_counter(spi, delay, 0, 0)?; + self.set_ram_counter(spi, delay, 0, 0).await?; - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; Ok(()) } } @@ -166,7 +170,7 @@ where HEIGHT } - fn new( + async fn new( spi: &mut SPI, busy: BUSY, dc: DC, @@ -182,35 +186,38 @@ where refresh: RefreshLut::Full, }; - epd.init(spi, delay)?; + epd.init(spi, delay).await?; Ok(epd) } - fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + async fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; // 0x00 for Normal mode (Power on Reset), 0x01 for Deep Sleep Mode self.interface - .cmd_with_data(spi, Command::DeepSleepMode, &[0x01])?; + .cmd_with_data(spi, Command::DeepSleepMode, &[0x01]) + .await?; Ok(()) } - fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.init(spi, delay)?; + async fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.init(spi, delay).await?; Ok(()) } - fn update_frame( + async fn update_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.interface.cmd_with_data(spi, Command::WriteRam, buffer) + self.wait_until_idle(spi, delay).await?; + self.interface + .cmd_with_data(spi, Command::WriteRam, buffer) + .await } - fn update_partial_frame( + async fn update_partial_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -221,48 +228,53 @@ where height: u32, ) -> Result<(), SPI::Error> { //TODO This is copied from epd2in9 but it seems not working. Partial refresh supported by version 2? - self.wait_until_idle(spi, delay)?; - self.set_ram_area(spi, x, y, x + width, y + height)?; - self.set_ram_counter(spi, delay, x, y)?; + self.wait_until_idle(spi, delay).await?; + self.set_ram_area(spi, x, y, x + width, y + height).await?; + self.set_ram_counter(spi, delay, x, y).await?; self.interface - .cmd_with_data(spi, Command::WriteRam, buffer)?; + .cmd_with_data(spi, Command::WriteRam, buffer) + .await?; Ok(()) } /// actually is the "Turn on Display" sequence - fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + async fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; // Enable clock signal, Enable Analog, Load temperature value, DISPLAY with DISPLAY Mode 1, Disable Analog, Disable OSC self.interface - .cmd_with_data(spi, Command::DisplayUpdateControl2, &[0xF7])?; - self.interface.cmd(spi, Command::MasterActivation)?; - self.wait_until_idle(spi, delay)?; + .cmd_with_data(spi, Command::DisplayUpdateControl2, &[0xF7]) + .await?; + self.interface.cmd(spi, Command::MasterActivation).await?; + self.wait_until_idle(spi, delay).await?; Ok(()) } - fn update_and_display_frame( + async fn update_and_display_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.update_frame(spi, buffer, delay)?; - self.display_frame(spi, delay)?; + self.update_frame(spi, buffer, delay).await?; + self.display_frame(spi, delay).await?; Ok(()) } - fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + async fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; // clear the ram with the background color let color = self.background_color.get_byte_value(); - self.interface.cmd(spi, Command::WriteRam)?; + self.interface.cmd(spi, Command::WriteRam).await?; + self.interface + .data_x_times(spi, color, WIDTH / 8 * HEIGHT) + .await?; + self.interface.cmd(spi, Command::WriteRam2).await?; self.interface - .data_x_times(spi, color, WIDTH / 8 * HEIGHT)?; - self.interface.cmd(spi, Command::WriteRam2)?; - self.interface.data_x_times(spi, color, WIDTH / 8 * HEIGHT) + .data_x_times(spi, color, WIDTH / 8 * HEIGHT) + .await } fn set_background_color(&mut self, background_color: Color) { @@ -273,7 +285,7 @@ where &self.background_color } - fn set_lut( + async fn set_lut( &mut self, _spi: &mut SPI, _delay: &mut DELAY, @@ -285,8 +297,12 @@ where Ok(()) } - fn wait_until_idle(&mut self, _spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.interface.wait_until_idle(delay, IS_BUSY_LOW); + async fn wait_until_idle( + &mut self, + _spi: &mut SPI, + delay: &mut DELAY, + ) -> Result<(), SPI::Error> { + self.interface.wait_until_idle(delay, IS_BUSY_LOW).await; Ok(()) } } @@ -299,15 +315,15 @@ where RST: OutputPin, DELAY: DelayUs, { - fn use_full_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + async fn use_full_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { // choose full frame/ram - self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1)?; + self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1).await?; // start from the beginning - self.set_ram_counter(spi, delay, 0, 0) + self.set_ram_counter(spi, delay, 0, 0).await } - fn set_ram_area( + async fn set_ram_area( &mut self, spi: &mut SPI, start_x: u32, @@ -320,58 +336,66 @@ where // 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::SetRamXAddressStartEndPosition, - &[(start_x >> 3) as u8, (end_x >> 3) as u8], - )?; + self.interface + .cmd_with_data( + spi, + Command::SetRamXAddressStartEndPosition, + &[(start_x >> 3) as u8, (end_x >> 3) as u8], + ) + .await?; // 2 Databytes: A[7:0] & 0..A[8] for each - start and end - self.interface.cmd_with_data( - spi, - Command::SetRamYAddressStartEndPosition, - &[ - start_y as u8, - (start_y >> 8) as u8, - end_y as u8, - (end_y >> 8) as u8, - ], - ) + self.interface + .cmd_with_data( + spi, + Command::SetRamYAddressStartEndPosition, + &[ + start_y as u8, + (start_y >> 8) as u8, + end_y as u8, + (end_y >> 8) as u8, + ], + ) + .await } - fn set_ram_counter( + async fn set_ram_counter( &mut self, spi: &mut SPI, delay: &mut DELAY, x: u32, y: u32, ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; // 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::SetRamXAddressCounter, &[x as u8])?; + .cmd_with_data(spi, Command::SetRamXAddressCounter, &[x as u8]) + .await?; // 2 Databytes: A[7:0] & 0..A[8] - self.interface.cmd_with_data( - spi, - Command::SetRamYAddressCounter, - &[y as u8, (y >> 8) as u8], - )?; + self.interface + .cmd_with_data( + spi, + Command::SetRamYAddressCounter, + &[y as u8, (y >> 8) as u8], + ) + .await?; Ok(()) } /// Set your own LUT, this function is also used internally for set_lut - fn set_lut_helper( + async fn set_lut_helper( &mut self, spi: &mut SPI, delay: &mut DELAY, buffer: &[u8], ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; self.interface - .cmd_with_data(spi, Command::WriteLutRegister, buffer)?; - self.wait_until_idle(spi, delay)?; + .cmd_with_data(spi, Command::WriteLutRegister, buffer) + .await?; + self.wait_until_idle(spi, delay).await?; Ok(()) } } @@ -386,73 +410,84 @@ where DELAY: DelayUs, { /// To be followed immediately by `update_new_frame`. - fn update_old_frame( + async fn update_old_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; self.interface .cmd_with_data(spi, Command::WriteRam2, buffer) + .await } /// To be used immediately after `update_old_frame`. - fn update_new_frame( + async fn update_new_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.interface.reset(delay, 10_000, 2_000); - - self.set_lut_helper(spi, delay, &LUT_PARTIAL_2IN9)?; - self.interface.cmd_with_data( - spi, - Command::WriteOtpSelection, - &[0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00], - )?; + self.wait_until_idle(spi, delay).await?; + self.interface.reset(delay, 10_000, 2_000).await; + + self.set_lut_helper(spi, delay, &LUT_PARTIAL_2IN9).await?; self.interface - .cmd_with_data(spi, Command::BorderWaveformControl, &[0x80])?; + .cmd_with_data( + spi, + Command::WriteOtpSelection, + &[0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00], + ) + .await?; self.interface - .cmd_with_data(spi, Command::DisplayUpdateControl2, &[0xC0])?; - self.interface.cmd(spi, Command::MasterActivation)?; + .cmd_with_data(spi, Command::BorderWaveformControl, &[0x80]) + .await?; + self.interface + .cmd_with_data(spi, Command::DisplayUpdateControl2, &[0xC0]) + .await?; + self.interface.cmd(spi, Command::MasterActivation).await?; - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; - self.use_full_frame(spi, delay)?; + self.use_full_frame(spi, delay).await?; self.interface - .cmd_with_data(spi, Command::WriteRam, buffer)?; + .cmd_with_data(spi, Command::WriteRam, buffer) + .await?; Ok(()) } /// For a quick refresh of the new updated frame. To be used immediately after `update_new_frame` - fn display_new_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + async fn display_new_frame( + &mut self, + spi: &mut SPI, + delay: &mut DELAY, + ) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; self.interface - .cmd_with_data(spi, Command::DisplayUpdateControl2, &[0x0F])?; - self.interface.cmd(spi, Command::MasterActivation)?; - self.wait_until_idle(spi, delay)?; + .cmd_with_data(spi, Command::DisplayUpdateControl2, &[0x0F]) + .await?; + self.interface.cmd(spi, Command::MasterActivation).await?; + self.wait_until_idle(spi, delay).await?; Ok(()) } /// Updates and displays the new frame. - fn update_and_display_new_frame( + async fn update_and_display_new_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.update_new_frame(spi, buffer, delay)?; - self.display_new_frame(spi, delay)?; + self.update_new_frame(spi, buffer, delay).await?; + self.display_new_frame(spi, delay).await?; Ok(()) } /// Partial quick refresh not supported yet #[allow(unused)] - fn update_partial_old_frame( + async fn update_partial_old_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -468,7 +503,7 @@ where /// Partial quick refresh not supported yet #[allow(unused)] - fn update_partial_new_frame( + async fn update_partial_new_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -484,7 +519,7 @@ where /// Partial quick refresh not supported yet #[allow(unused)] - fn clear_partial_frame( + async fn clear_partial_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, diff --git a/src/epd2in9bc/mod.rs b/src/epd2in9bc/mod.rs index 121c5680..fb1c1732 100644 --- a/src/epd2in9bc/mod.rs +++ b/src/epd2in9bc/mod.rs @@ -54,7 +54,8 @@ //!# Ok(()) //!# } //!``` -use embedded_hal::{delay::*, digital::*, spi::SpiDevice}; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::{delay::DelayUs, spi::SpiDevice}; use crate::interface::DisplayInterface; use crate::traits::{ @@ -110,35 +111,39 @@ where RST: OutputPin, DELAY: DelayUs, { - fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + async fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { // Values taken from datasheet and sample code - self.interface.reset(delay, 10_000, 10_000); + self.interface.reset(delay, 10_000, 10_000).await; // start the booster self.interface - .cmd_with_data(spi, Command::BoosterSoftStart, &[0x17, 0x17, 0x17])?; + .cmd_with_data(spi, Command::BoosterSoftStart, &[0x17, 0x17, 0x17]) + .await?; // power on - self.command(spi, Command::PowerOn)?; - delay.delay_us(5000); - self.wait_until_idle(spi, delay)?; + self.command(spi, Command::PowerOn).await?; + delay.delay_us(5000).await; + self.wait_until_idle(spi, delay).await?; // set the panel settings - self.cmd_with_data(spi, Command::PanelSetting, &[0x8F])?; + self.cmd_with_data(spi, Command::PanelSetting, &[0x8F]) + .await?; self.cmd_with_data( spi, Command::VcomAndDataIntervalSetting, &[WHITE_BORDER | VCOM_DATA_INTERVAL], - )?; + ) + .await?; // set resolution - self.send_resolution(spi)?; + self.send_resolution(spi).await?; - self.cmd_with_data(spi, Command::VcmDcSetting, &[0x0A])?; + self.cmd_with_data(spi, Command::VcmDcSetting, &[0x0A]) + .await?; - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; Ok(()) } @@ -153,44 +158,48 @@ where RST: OutputPin, DELAY: DelayUs, { - fn update_color_frame( + async fn update_color_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, black: &[u8], chromatic: &[u8], ) -> Result<(), SPI::Error> { - self.update_achromatic_frame(spi, delay, black)?; - self.update_chromatic_frame(spi, delay, chromatic) + self.update_achromatic_frame(spi, delay, black).await?; + self.update_chromatic_frame(spi, delay, chromatic).await } /// Update only the black/white data of the display. /// /// Finish by calling `update_chromatic_frame`. - fn update_achromatic_frame( + async fn update_achromatic_frame( &mut self, spi: &mut SPI, _delay: &mut DELAY, black: &[u8], ) -> Result<(), SPI::Error> { - self.interface.cmd(spi, Command::DataStartTransmission1)?; - self.interface.data(spi, black)?; + self.interface + .cmd(spi, Command::DataStartTransmission1) + .await?; + self.interface.data(spi, black).await?; Ok(()) } /// Update only chromatic data of the display. /// /// This data takes precedence over the black/white data. - fn update_chromatic_frame( + async fn update_chromatic_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, chromatic: &[u8], ) -> Result<(), SPI::Error> { - self.interface.cmd(spi, Command::DataStartTransmission2)?; - self.interface.data(spi, chromatic)?; + self.interface + .cmd(spi, Command::DataStartTransmission2) + .await?; + self.interface.data(spi, chromatic).await?; - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; Ok(()) } } @@ -205,7 +214,7 @@ where DELAY: DelayUs, { type DisplayColor = Color; - fn new( + async fn new( spi: &mut SPI, busy: BUSY, dc: DC, @@ -218,30 +227,32 @@ where let mut epd = Epd2in9bc { interface, color }; - epd.init(spi, delay)?; + epd.init(spi, delay).await?; Ok(epd) } - fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + async fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { // Section 8.2 from datasheet - self.interface.cmd_with_data( - spi, - Command::VcomAndDataIntervalSetting, - &[FLOATING_BORDER | VCOM_DATA_INTERVAL], - )?; - - self.command(spi, Command::PowerOff)?; + self.interface + .cmd_with_data( + spi, + Command::VcomAndDataIntervalSetting, + &[FLOATING_BORDER | VCOM_DATA_INTERVAL], + ) + .await?; + + self.command(spi, Command::PowerOff).await?; // The example STM code from Github has a wait after PowerOff - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; - self.cmd_with_data(spi, Command::DeepSleep, &[0xA5])?; + self.cmd_with_data(spi, Command::DeepSleep, &[0xA5]).await?; Ok(()) } - fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.init(spi, delay) + async fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.init(spi, delay).await } fn set_background_color(&mut self, color: Color) { @@ -260,28 +271,34 @@ where HEIGHT } - fn update_frame( + async fn update_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.interface.cmd(spi, Command::DataStartTransmission1)?; + self.interface + .cmd(spi, Command::DataStartTransmission1) + .await?; - self.interface.data(spi, buffer)?; + self.interface.data(spi, buffer).await?; // Clear the chromatic layer let color = self.color.get_byte_value(); - self.interface.cmd(spi, Command::DataStartTransmission2)?; - self.interface.data_x_times(spi, color, NUM_DISPLAY_BITS)?; + self.interface + .cmd(spi, Command::DataStartTransmission2) + .await?; + self.interface + .data_x_times(spi, color, NUM_DISPLAY_BITS) + .await?; - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; Ok(()) } #[allow(unused)] - fn update_partial_frame( + async fn update_partial_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -294,43 +311,51 @@ where Ok(()) } - fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.command(spi, Command::DisplayRefresh)?; + async fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.command(spi, Command::DisplayRefresh).await?; - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; Ok(()) } - fn update_and_display_frame( + async fn update_and_display_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.update_frame(spi, buffer, delay)?; - self.display_frame(spi, delay)?; + self.update_frame(spi, buffer, delay).await?; + self.display_frame(spi, delay).await?; Ok(()) } - fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.send_resolution(spi)?; + async fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.send_resolution(spi).await?; let color = DEFAULT_BACKGROUND_COLOR.get_byte_value(); // Clear the black - self.interface.cmd(spi, Command::DataStartTransmission1)?; + self.interface + .cmd(spi, Command::DataStartTransmission1) + .await?; - self.interface.data_x_times(spi, color, NUM_DISPLAY_BITS)?; + self.interface + .data_x_times(spi, color, NUM_DISPLAY_BITS) + .await?; // Clear the chromatic - self.interface.cmd(spi, Command::DataStartTransmission2)?; - self.interface.data_x_times(spi, color, NUM_DISPLAY_BITS)?; + self.interface + .cmd(spi, Command::DataStartTransmission2) + .await?; + self.interface + .data_x_times(spi, color, NUM_DISPLAY_BITS) + .await?; - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; Ok(()) } - fn set_lut( + async fn set_lut( &mut self, _spi: &mut SPI, _delay: &mut DELAY, @@ -339,8 +364,12 @@ where Ok(()) } - fn wait_until_idle(&mut self, _spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.interface.wait_until_idle(delay, IS_BUSY_LOW); + async fn wait_until_idle( + &mut self, + _spi: &mut SPI, + delay: &mut DELAY, + ) -> Result<(), SPI::Error> { + self.interface.wait_until_idle(delay, IS_BUSY_LOW).await; Ok(()) } } @@ -353,36 +382,40 @@ where RST: OutputPin, DELAY: DelayUs, { - fn command(&mut self, spi: &mut SPI, command: Command) -> Result<(), SPI::Error> { - self.interface.cmd(spi, command) + async fn command(&mut self, spi: &mut SPI, command: Command) -> Result<(), SPI::Error> { + self.interface.cmd(spi, command).await } - fn send_data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> { - self.interface.data(spi, data) + async fn send_data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> { + self.interface.data(spi, data).await } - fn cmd_with_data( + async fn cmd_with_data( &mut self, spi: &mut SPI, command: Command, data: &[u8], ) -> Result<(), SPI::Error> { - self.interface.cmd_with_data(spi, command, data) + self.interface.cmd_with_data(spi, command, data).await } - fn send_resolution(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { + async fn send_resolution(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { let w = self.width(); let h = self.height(); - self.command(spi, Command::ResolutionSetting)?; + self.command(spi, Command::ResolutionSetting).await?; - self.send_data(spi, &[w as u8])?; - self.send_data(spi, &[(h >> 8) as u8])?; - self.send_data(spi, &[h as u8]) + self.send_data(spi, &[w as u8]).await?; + self.send_data(spi, &[(h >> 8) as u8]).await?; + self.send_data(spi, &[h as u8]).await } /// Set the outer border of the display to the chosen color. - pub fn set_border_color(&mut self, spi: &mut SPI, color: TriColor) -> Result<(), SPI::Error> { + pub async fn set_border_color( + &mut self, + spi: &mut SPI, + color: TriColor, + ) -> Result<(), SPI::Error> { let border = match color { TriColor::Black => BLACK_BORDER, TriColor::White => WHITE_BORDER, @@ -393,5 +426,6 @@ where Command::VcomAndDataIntervalSetting, &[border | VCOM_DATA_INTERVAL], ) + .await } } diff --git a/src/epd3in7/mod.rs b/src/epd3in7/mod.rs index c7f06855..973abb46 100644 --- a/src/epd3in7/mod.rs +++ b/src/epd3in7/mod.rs @@ -2,11 +2,8 @@ //! //! //! Build with the help of documentation/code from [Waveshare](https://www.waveshare.com/wiki/3.7inch_e-Paper_HAT), -use embedded_hal::{ - delay::DelayUs, - digital::{InputPin, OutputPin}, - spi::SpiDevice, -}; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::{delay::DelayUs, spi::SpiDevice}; pub(crate) mod command; mod constants; @@ -59,66 +56,84 @@ where RST: OutputPin, DELAY: DelayUs, { - fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + async fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { // reset the device - self.interface.reset(delay, 30, 10); + self.interface.reset(delay, 30, 10).await; - self.interface.cmd(spi, Command::SwReset)?; - delay.delay_us(300000u32); + self.interface.cmd(spi, Command::SwReset).await?; + delay.delay_us(300000u32).await; self.interface - .cmd_with_data(spi, Command::AutoWriteRedRamRegularPattern, &[0xF7])?; - self.interface.wait_until_idle(delay, IS_BUSY_LOW); + .cmd_with_data(spi, Command::AutoWriteRedRamRegularPattern, &[0xF7]) + .await?; + self.interface.wait_until_idle(delay, IS_BUSY_LOW).await; self.interface - .cmd_with_data(spi, Command::AutoWriteBwRamRegularPattern, &[0xF7])?; - self.interface.wait_until_idle(delay, IS_BUSY_LOW); + .cmd_with_data(spi, Command::AutoWriteBwRamRegularPattern, &[0xF7]) + .await?; + self.interface.wait_until_idle(delay, IS_BUSY_LOW).await; self.interface - .cmd_with_data(spi, Command::GateSetting, &[0xDF, 0x01, 0x00])?; + .cmd_with_data(spi, Command::GateSetting, &[0xDF, 0x01, 0x00]) + .await?; self.interface - .cmd_with_data(spi, Command::GateVoltage, &[0x00])?; + .cmd_with_data(spi, Command::GateVoltage, &[0x00]) + .await?; self.interface - .cmd_with_data(spi, Command::GateVoltageSource, &[0x41, 0xA8, 0x32])?; + .cmd_with_data(spi, Command::GateVoltageSource, &[0x41, 0xA8, 0x32]) + .await?; self.interface - .cmd_with_data(spi, Command::DataEntrySequence, &[0x03])?; + .cmd_with_data(spi, Command::DataEntrySequence, &[0x03]) + .await?; self.interface - .cmd_with_data(spi, Command::BorderWaveformControl, &[0x03])?; + .cmd_with_data(spi, Command::BorderWaveformControl, &[0x03]) + .await?; - self.interface.cmd_with_data( - spi, - Command::BoosterSoftStartControl, - &[0xAE, 0xC7, 0xC3, 0xC0, 0xC0], - )?; + self.interface + .cmd_with_data( + spi, + Command::BoosterSoftStartControl, + &[0xAE, 0xC7, 0xC3, 0xC0, 0xC0], + ) + .await?; + + self.interface + .cmd_with_data(spi, Command::TemperatureSensorSelection, &[0x80]) + .await?; self.interface - .cmd_with_data(spi, Command::TemperatureSensorSelection, &[0x80])?; + .cmd_with_data(spi, Command::WriteVcomRegister, &[0x44]) + .await?; self.interface - .cmd_with_data(spi, Command::WriteVcomRegister, &[0x44])?; - - self.interface.cmd_with_data( - spi, - Command::DisplayOption, - &[0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x4F, 0xFF, 0xFF, 0xFF, 0xFF], - )?; - - self.interface.cmd_with_data( - spi, - Command::SetRamXAddressStartEndPosition, - &[0x00, 0x00, 0x17, 0x01], - )?; - self.interface.cmd_with_data( - spi, - Command::SetRamYAddressStartEndPosition, - &[0x00, 0x00, 0xDF, 0x01], - )?; + .cmd_with_data( + spi, + Command::DisplayOption, + &[0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x4F, 0xFF, 0xFF, 0xFF, 0xFF], + ) + .await?; + + self.interface + .cmd_with_data( + spi, + Command::SetRamXAddressStartEndPosition, + &[0x00, 0x00, 0x17, 0x01], + ) + .await?; + self.interface + .cmd_with_data( + spi, + Command::SetRamYAddressStartEndPosition, + &[0x00, 0x00, 0xDF, 0x01], + ) + .await?; self.interface - .cmd_with_data(spi, Command::DisplayUpdateSequenceSetting, &[0xCF])?; + .cmd_with_data(spi, Command::DisplayUpdateSequenceSetting, &[0xCF]) + .await?; - self.set_lut(spi, delay, Some(RefreshLut::Full))?; + self.set_lut(spi, delay, Some(RefreshLut::Full)).await?; Ok(()) } } @@ -134,7 +149,7 @@ where { type DisplayColor = Color; - fn new( + async fn new( spi: &mut SPI, busy: BUSY, dc: DC, @@ -147,19 +162,22 @@ where background_color: DEFAULT_BACKGROUND_COLOR, }; - epd.init(spi, delay)?; + epd.init(spi, delay).await?; Ok(epd) } - fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.init(spi, delay) + async fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.init(spi, delay).await } - fn sleep(&mut self, spi: &mut SPI, _delay: &mut DELAY) -> Result<(), SPI::Error> { - self.interface.cmd_with_data(spi, Command::Sleep, &[0xF7])?; - self.interface.cmd(spi, Command::PowerOff)?; + async fn sleep(&mut self, spi: &mut SPI, _delay: &mut DELAY) -> Result<(), SPI::Error> { self.interface - .cmd_with_data(spi, Command::Sleep2, &[0xA5])?; + .cmd_with_data(spi, Command::Sleep, &[0xF7]) + .await?; + self.interface.cmd(spi, Command::PowerOff).await?; + self.interface + .cmd_with_data(spi, Command::Sleep2, &[0xA5]) + .await?; Ok(()) } @@ -179,7 +197,7 @@ where HEIGHT } - fn update_frame( + async fn update_frame( &mut self, spi: &mut SPI, buffer: &[u8], @@ -187,18 +205,21 @@ where ) -> Result<(), SPI::Error> { assert!(buffer.len() == buffer_len(WIDTH as usize, HEIGHT as usize)); self.interface - .cmd_with_data(spi, Command::SetRamXAddressCounter, &[0x00, 0x00])?; + .cmd_with_data(spi, Command::SetRamXAddressCounter, &[0x00, 0x00]) + .await?; self.interface - .cmd_with_data(spi, Command::SetRamYAddressCounter, &[0x00, 0x00])?; + .cmd_with_data(spi, Command::SetRamYAddressCounter, &[0x00, 0x00]) + .await?; self.interface - .cmd_with_data(spi, Command::WriteRam, buffer)?; + .cmd_with_data(spi, Command::WriteRam, buffer) + .await?; Ok(()) } #[allow(unused)] - fn update_partial_frame( + async fn update_partial_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -211,39 +232,45 @@ where todo!() } - fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + async fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { //self.interface // .cmd_with_data(spi, Command::WRITE_LUT_REGISTER, &LUT_1GRAY_GC)?; - self.interface.cmd(spi, Command::DisplayUpdateSequence)?; - self.interface.wait_until_idle(delay, IS_BUSY_LOW); + self.interface + .cmd(spi, Command::DisplayUpdateSequence) + .await?; + self.interface.wait_until_idle(delay, IS_BUSY_LOW).await; Ok(()) } - fn update_and_display_frame( + async fn update_and_display_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.update_frame(spi, buffer, delay)?; - self.display_frame(spi, delay)?; + self.update_frame(spi, buffer, delay).await?; + self.display_frame(spi, delay).await?; Ok(()) } - fn clear_frame(&mut self, spi: &mut SPI, _delay: &mut DELAY) -> Result<(), SPI::Error> { + async fn clear_frame(&mut self, spi: &mut SPI, _delay: &mut DELAY) -> Result<(), SPI::Error> { self.interface - .cmd_with_data(spi, Command::SetRamXAddressCounter, &[0x00, 0x00])?; + .cmd_with_data(spi, Command::SetRamXAddressCounter, &[0x00, 0x00]) + .await?; self.interface - .cmd_with_data(spi, Command::SetRamYAddressCounter, &[0x00, 0x00])?; + .cmd_with_data(spi, Command::SetRamYAddressCounter, &[0x00, 0x00]) + .await?; let color = self.background_color.get_byte_value(); - self.interface.cmd(spi, Command::WriteRam)?; - self.interface.data_x_times(spi, color, WIDTH * HEIGHT)?; + self.interface.cmd(spi, Command::WriteRam).await?; + self.interface + .data_x_times(spi, color, WIDTH * HEIGHT) + .await?; Ok(()) } - fn set_lut( + async fn set_lut( &mut self, spi: &mut SPI, _delay: &mut DELAY, @@ -255,12 +282,17 @@ where }; self.interface - .cmd_with_data(spi, Command::WriteLutRegister, buffer)?; + .cmd_with_data(spi, Command::WriteLutRegister, buffer) + .await?; Ok(()) } - fn wait_until_idle(&mut self, _spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.interface.wait_until_idle(delay, IS_BUSY_LOW); + async fn wait_until_idle( + &mut self, + _spi: &mut SPI, + delay: &mut DELAY, + ) -> Result<(), SPI::Error> { + self.interface.wait_until_idle(delay, IS_BUSY_LOW).await; Ok(()) } } diff --git a/src/epd4in2/mod.rs b/src/epd4in2/mod.rs index fe43d0ef..8d6b5828 100644 --- a/src/epd4in2/mod.rs +++ b/src/epd4in2/mod.rs @@ -49,7 +49,8 @@ //! //! BE CAREFUL! The screen can get ghosting/burn-ins through the Partial Fast Update Drawing. -use embedded_hal::{delay::*, digital::*, spi::SpiDevice}; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::{delay::DelayUs, spi::SpiDevice}; use crate::interface::DisplayInterface; use crate::traits::{InternalWiAdditions, QuickRefresh, RefreshLut, WaveshareDisplay}; @@ -103,47 +104,50 @@ where RST: OutputPin, DELAY: DelayUs, { - fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + async fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { // reset the device - self.interface.reset(delay, 10_000, 10_000); + self.interface.reset(delay, 10_000, 10_000).await; // set the power settings - self.interface.cmd_with_data( - spi, - Command::PowerSetting, - &[0x03, 0x00, 0x2b, 0x2b, 0xff], - )?; + self.interface + .cmd_with_data(spi, Command::PowerSetting, &[0x03, 0x00, 0x2b, 0x2b, 0xff]) + .await?; // start the booster self.interface - .cmd_with_data(spi, Command::BoosterSoftStart, &[0x17, 0x17, 0x17])?; + .cmd_with_data(spi, Command::BoosterSoftStart, &[0x17, 0x17, 0x17]) + .await?; // power on - self.command(spi, Command::PowerOn)?; - delay.delay_us(5000); - self.wait_until_idle(spi, delay)?; + self.command(spi, Command::PowerOn).await?; + delay.delay_us(5000).await; + self.wait_until_idle(spi, delay).await?; // set the panel settings - self.cmd_with_data(spi, Command::PanelSetting, &[0x3F])?; + self.cmd_with_data(spi, Command::PanelSetting, &[0x3F]) + .await?; // Set Frequency, 200 Hz didn't work on my board // 150Hz and 171Hz wasn't tested yet // TODO: Test these other frequencies // 3A 100HZ 29 150Hz 39 200HZ 31 171HZ DEFAULT: 3c 50Hz - self.cmd_with_data(spi, Command::PllControl, &[0x3A])?; + self.cmd_with_data(spi, Command::PllControl, &[0x3A]) + .await?; - self.send_resolution(spi)?; + self.send_resolution(spi).await?; self.interface - .cmd_with_data(spi, Command::VcmDcSetting, &[0x12])?; + .cmd_with_data(spi, Command::VcmDcSetting, &[0x12]) + .await?; //VBDF 17|D7 VBDW 97 VBDB 57 VBDF F7 VBDW 77 VBDB 37 VBDR B7 self.interface - .cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x97])?; + .cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x97]) + .await?; - self.set_lut(spi, delay, None)?; + self.set_lut(spi, delay, None).await?; - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; Ok(()) } } @@ -158,7 +162,7 @@ where DELAY: DelayUs, { type DisplayColor = Color; - fn new( + async fn new( spi: &mut SPI, busy: BUSY, dc: DC, @@ -175,32 +179,34 @@ where refresh: RefreshLut::Full, }; - epd.init(spi, delay)?; + epd.init(spi, delay).await?; Ok(epd) } - fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + async fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; self.interface - .cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x17])?; //border floating - self.command(spi, Command::VcmDcSetting)?; // VCOM to 0V - self.command(spi, Command::PanelSetting)?; + .cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x17]) + .await?; //border floating + self.command(spi, Command::VcmDcSetting).await?; // VCOM to 0V + self.command(spi, Command::PanelSetting).await?; - self.command(spi, Command::PowerSetting)?; //VG&VS to 0V fast + self.command(spi, Command::PowerSetting).await?; //VG&VS to 0V fast for _ in 0..4 { - self.send_data(spi, &[0x00])?; + self.send_data(spi, &[0x00]).await?; } - self.command(spi, Command::PowerOff)?; - self.wait_until_idle(spi, delay)?; + self.command(spi, Command::PowerOff).await?; + self.wait_until_idle(spi, delay).await?; self.interface - .cmd_with_data(spi, Command::DeepSleep, &[0xA5])?; + .cmd_with_data(spi, Command::DeepSleep, &[0xA5]) + .await?; Ok(()) } - fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.init(spi, delay) + async fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.init(spi, delay).await } fn set_background_color(&mut self, color: Color) { @@ -219,25 +225,29 @@ where HEIGHT } - fn update_frame( + async fn update_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; let color_value = self.color.get_byte_value(); - self.interface.cmd(spi, Command::DataStartTransmission1)?; self.interface - .data_x_times(spi, color_value, WIDTH / 8 * HEIGHT)?; + .cmd(spi, Command::DataStartTransmission1) + .await?; + self.interface + .data_x_times(spi, color_value, WIDTH / 8 * HEIGHT) + .await?; self.interface - .cmd_with_data(spi, Command::DataStartTransmission2, buffer)?; + .cmd_with_data(spi, Command::DataStartTransmission2, buffer) + .await?; Ok(()) } - fn update_partial_frame( + async fn update_partial_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -247,77 +257,84 @@ where width: u32, height: u32, ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; if buffer.len() as u32 != width / 8 * height { //TODO: panic!! or sth like that //return Err("Wrong buffersize"); } - self.command(spi, Command::PartialIn)?; - self.command(spi, Command::PartialWindow)?; - self.send_data(spi, &[(x >> 8) as u8])?; + self.command(spi, Command::PartialIn).await?; + self.command(spi, Command::PartialWindow).await?; + self.send_data(spi, &[(x >> 8) as u8]).await?; let tmp = x & 0xf8; - self.send_data(spi, &[tmp as u8])?; // x should be the multiple of 8, the last 3 bit will always be ignored + self.send_data(spi, &[tmp as u8]).await?; // x should be the multiple of 8, the last 3 bit will always be ignored let tmp = tmp + width - 1; - self.send_data(spi, &[(tmp >> 8) as u8])?; - self.send_data(spi, &[(tmp | 0x07) as u8])?; + self.send_data(spi, &[(tmp >> 8) as u8]).await?; + self.send_data(spi, &[(tmp | 0x07) as u8]).await?; - self.send_data(spi, &[(y >> 8) as u8])?; - self.send_data(spi, &[y as u8])?; + self.send_data(spi, &[(y >> 8) as u8]).await?; + self.send_data(spi, &[y as u8]).await?; - self.send_data(spi, &[((y + height - 1) >> 8) as u8])?; - self.send_data(spi, &[(y + height - 1) as u8])?; + self.send_data(spi, &[((y + height - 1) >> 8) as u8]) + .await?; + self.send_data(spi, &[(y + height - 1) as u8]).await?; - self.send_data(spi, &[0x01])?; // Gates scan both inside and outside of the partial window. (default) + self.send_data(spi, &[0x01]).await?; // Gates scan both inside and outside of the partial window. (default) //TODO: handle dtm somehow let is_dtm1 = false; if is_dtm1 { - self.command(spi, Command::DataStartTransmission1)? //TODO: check if data_start transmission 1 also needs "old"/background data here + self.command(spi, Command::DataStartTransmission1).await?; //TODO: check if data_start transmission 1 also needs "old"/background data here } else { - self.command(spi, Command::DataStartTransmission2)? + self.command(spi, Command::DataStartTransmission2).await?; } - self.send_data(spi, buffer)?; + self.send_data(spi, buffer).await?; - self.command(spi, Command::PartialOut)?; + self.command(spi, Command::PartialOut).await?; Ok(()) } - fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.command(spi, Command::DisplayRefresh)?; + async fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; + self.command(spi, Command::DisplayRefresh).await?; Ok(()) } - fn update_and_display_frame( + async fn update_and_display_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.update_frame(spi, buffer, delay)?; - self.command(spi, Command::DisplayRefresh)?; + self.update_frame(spi, buffer, delay).await?; + self.command(spi, Command::DisplayRefresh).await?; Ok(()) } - fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.send_resolution(spi)?; + async fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; + self.send_resolution(spi).await?; let color_value = self.color.get_byte_value(); - self.interface.cmd(spi, Command::DataStartTransmission1)?; self.interface - .data_x_times(spi, color_value, WIDTH / 8 * HEIGHT)?; + .cmd(spi, Command::DataStartTransmission1) + .await?; + self.interface + .data_x_times(spi, color_value, WIDTH / 8 * HEIGHT) + .await?; - self.interface.cmd(spi, Command::DataStartTransmission2)?; self.interface - .data_x_times(spi, color_value, WIDTH / 8 * HEIGHT)?; + .cmd(spi, Command::DataStartTransmission2) + .await?; + self.interface + .data_x_times(spi, color_value, WIDTH / 8 * HEIGHT) + .await?; Ok(()) } - fn set_lut( + async fn set_lut( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -329,21 +346,29 @@ where match self.refresh { RefreshLut::Full => { self.set_lut_helper(spi, delay, &LUT_VCOM0, &LUT_WW, &LUT_BW, &LUT_WB, &LUT_BB) + .await + } + RefreshLut::Quick => { + self.set_lut_helper( + spi, + delay, + &LUT_VCOM0_QUICK, + &LUT_WW_QUICK, + &LUT_BW_QUICK, + &LUT_WB_QUICK, + &LUT_BB_QUICK, + ) + .await } - RefreshLut::Quick => self.set_lut_helper( - spi, - delay, - &LUT_VCOM0_QUICK, - &LUT_WW_QUICK, - &LUT_BW_QUICK, - &LUT_WB_QUICK, - &LUT_BB_QUICK, - ), } } - fn wait_until_idle(&mut self, _spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.interface.wait_until_idle(delay, IS_BUSY_LOW); + async fn wait_until_idle( + &mut self, + _spi: &mut SPI, + delay: &mut DELAY, + ) -> Result<(), SPI::Error> { + self.interface.wait_until_idle(delay, IS_BUSY_LOW).await; Ok(()) } } @@ -356,36 +381,36 @@ where RST: OutputPin, DELAY: DelayUs, { - fn command(&mut self, spi: &mut SPI, command: Command) -> Result<(), SPI::Error> { - self.interface.cmd(spi, command) + async fn command(&mut self, spi: &mut SPI, command: Command) -> Result<(), SPI::Error> { + self.interface.cmd(spi, command).await } - fn send_data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> { - self.interface.data(spi, data) + async fn send_data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> { + self.interface.data(spi, data).await } - fn cmd_with_data( + async fn cmd_with_data( &mut self, spi: &mut SPI, command: Command, data: &[u8], ) -> Result<(), SPI::Error> { - self.interface.cmd_with_data(spi, command, data) + self.interface.cmd_with_data(spi, command, data).await } - fn send_resolution(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { + async fn send_resolution(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { let w = self.width(); let h = self.height(); - self.command(spi, Command::ResolutionSetting)?; - self.send_data(spi, &[(w >> 8) as u8])?; - self.send_data(spi, &[w as u8])?; - self.send_data(spi, &[(h >> 8) as u8])?; - self.send_data(spi, &[h as u8]) + self.command(spi, Command::ResolutionSetting).await?; + self.send_data(spi, &[(w >> 8) as u8]).await?; + self.send_data(spi, &[w as u8]).await?; + self.send_data(spi, &[(h >> 8) as u8]).await?; + self.send_data(spi, &[h as u8]).await } #[allow(clippy::too_many_arguments)] - fn set_lut_helper( + async fn set_lut_helper( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -395,27 +420,32 @@ where lut_wb: &[u8], lut_bb: &[u8], ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; // LUT VCOM - self.cmd_with_data(spi, Command::LutForVcom, lut_vcom)?; + self.cmd_with_data(spi, Command::LutForVcom, lut_vcom) + .await?; // LUT WHITE to WHITE - self.cmd_with_data(spi, Command::LutWhiteToWhite, lut_ww)?; + self.cmd_with_data(spi, Command::LutWhiteToWhite, lut_ww) + .await?; // LUT BLACK to WHITE - self.cmd_with_data(spi, Command::LutBlackToWhite, lut_bw)?; + self.cmd_with_data(spi, Command::LutBlackToWhite, lut_bw) + .await?; // LUT WHITE to BLACK - self.cmd_with_data(spi, Command::LutWhiteToBlack, lut_wb)?; + self.cmd_with_data(spi, Command::LutWhiteToBlack, lut_wb) + .await?; // LUT BLACK to BLACK - self.cmd_with_data(spi, Command::LutBlackToBlack, lut_bb)?; + self.cmd_with_data(spi, Command::LutBlackToBlack, lut_bb) + .await?; Ok(()) } /// Helper function. Sets up the display to send pixel data to a custom /// starting point. - pub fn shift_display( + pub async fn shift_display( &mut self, spi: &mut SPI, x: u32, @@ -423,20 +453,21 @@ where width: u32, height: u32, ) -> Result<(), SPI::Error> { - self.send_data(spi, &[(x >> 8) as u8])?; + self.send_data(spi, &[(x >> 8) as u8]).await?; let tmp = x & 0xf8; - self.send_data(spi, &[tmp as u8])?; // x should be the multiple of 8, the last 3 bit will always be ignored + self.send_data(spi, &[tmp as u8]).await?; // x should be the multiple of 8, the last 3 bit will always be ignored let tmp = tmp + width - 1; - self.send_data(spi, &[(tmp >> 8) as u8])?; - self.send_data(spi, &[(tmp | 0x07) as u8])?; + self.send_data(spi, &[(tmp >> 8) as u8]).await?; + self.send_data(spi, &[(tmp | 0x07) as u8]).await?; - self.send_data(spi, &[(y >> 8) as u8])?; - self.send_data(spi, &[y as u8])?; + self.send_data(spi, &[(y >> 8) as u8]).await?; + self.send_data(spi, &[y as u8]).await?; - self.send_data(spi, &[((y + height - 1) >> 8) as u8])?; - self.send_data(spi, &[(y + height - 1) as u8])?; + self.send_data(spi, &[((y + height - 1) >> 8) as u8]) + .await?; + self.send_data(spi, &[(y + height - 1) as u8]).await?; - self.send_data(spi, &[0x01])?; // Gates scan both inside and outside of the partial window. (default) + self.send_data(spi, &[0x01]).await?; // Gates scan both inside and outside of the partial window. (default) Ok(()) } @@ -452,59 +483,67 @@ where DELAY: DelayUs, { /// To be followed immediately after by `update_old_frame`. - fn update_old_frame( + async fn update_old_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; - self.interface.cmd(spi, Command::DataStartTransmission1)?; + self.interface + .cmd(spi, Command::DataStartTransmission1) + .await?; - self.interface.data(spi, buffer)?; + self.interface.data(spi, buffer).await?; Ok(()) } /// To be used immediately after `update_old_frame`. - fn update_new_frame( + async fn update_new_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - // self.send_resolution(spi)?; + self.wait_until_idle(spi, delay).await?; + // self.send_resolution(spi).await?; - self.interface.cmd(spi, Command::DataStartTransmission2)?; + self.interface + .cmd(spi, Command::DataStartTransmission2) + .await?; - self.interface.data(spi, buffer)?; + self.interface.data(spi, buffer).await?; Ok(()) } /// This is a wrapper around `display_frame` for using this device as a true /// `QuickRefresh` device. - fn display_new_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.display_frame(spi, delay) + async fn display_new_frame( + &mut self, + spi: &mut SPI, + delay: &mut DELAY, + ) -> Result<(), SPI::Error> { + self.display_frame(spi, delay).await } /// This is wrapper around `update_new_frame` and `display_frame` for using /// this device as a true `QuickRefresh` device. /// /// To be used immediately after `update_old_frame`. - fn update_and_display_new_frame( + async fn update_and_display_new_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.update_new_frame(spi, buffer, delay)?; - self.display_frame(spi, delay) + self.update_new_frame(spi, buffer, delay).await?; + self.display_frame(spi, delay).await } - fn update_partial_old_frame( + async fn update_partial_old_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -514,28 +553,30 @@ where width: u32, height: u32, ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; if buffer.len() as u32 != width / 8 * height { //TODO: panic!! or sth like that //return Err("Wrong buffersize"); } - self.interface.cmd(spi, Command::PartialIn)?; - self.interface.cmd(spi, Command::PartialWindow)?; + self.interface.cmd(spi, Command::PartialIn).await?; + self.interface.cmd(spi, Command::PartialWindow).await?; - self.shift_display(spi, x, y, width, height)?; + self.shift_display(spi, x, y, width, height).await?; - self.interface.cmd(spi, Command::DataStartTransmission1)?; + self.interface + .cmd(spi, Command::DataStartTransmission1) + .await?; - self.interface.data(spi, buffer)?; + self.interface.data(spi, buffer).await?; Ok(()) } /// Always call `update_partial_old_frame` before this, with buffer-updating code /// between the calls. - fn update_partial_new_frame( + async fn update_partial_new_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -545,23 +586,25 @@ where width: u32, height: u32, ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; if buffer.len() as u32 != width / 8 * height { //TODO: panic!! or sth like that //return Err("Wrong buffersize"); } - self.shift_display(spi, x, y, width, height)?; + self.shift_display(spi, x, y, width, height).await?; - self.interface.cmd(spi, Command::DataStartTransmission2)?; + self.interface + .cmd(spi, Command::DataStartTransmission2) + .await?; - self.interface.data(spi, buffer)?; + self.interface.data(spi, buffer).await?; - self.interface.cmd(spi, Command::PartialOut)?; + self.interface.cmd(spi, Command::PartialOut).await?; Ok(()) } - fn clear_partial_frame( + async fn clear_partial_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -570,25 +613,31 @@ where width: u32, height: u32, ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.send_resolution(spi)?; + self.wait_until_idle(spi, delay).await?; + self.send_resolution(spi).await?; let color_value = self.color.get_byte_value(); - self.interface.cmd(spi, Command::PartialIn)?; - self.interface.cmd(spi, Command::PartialWindow)?; + self.interface.cmd(spi, Command::PartialIn).await?; + self.interface.cmd(spi, Command::PartialWindow).await?; - self.shift_display(spi, x, y, width, height)?; + self.shift_display(spi, x, y, width, height).await?; - self.interface.cmd(spi, Command::DataStartTransmission1)?; self.interface - .data_x_times(spi, color_value, width / 8 * height)?; + .cmd(spi, Command::DataStartTransmission1) + .await?; + self.interface + .data_x_times(spi, color_value, width / 8 * height) + .await?; - self.interface.cmd(spi, Command::DataStartTransmission2)?; self.interface - .data_x_times(spi, color_value, width / 8 * height)?; + .cmd(spi, Command::DataStartTransmission2) + .await?; + self.interface + .data_x_times(spi, color_value, width / 8 * height) + .await?; - self.interface.cmd(spi, Command::PartialOut)?; + self.interface.cmd(spi, Command::PartialOut).await?; Ok(()) } } diff --git a/src/epd5in65f/mod.rs b/src/epd5in65f/mod.rs index 6233955b..c348dd07 100644 --- a/src/epd5in65f/mod.rs +++ b/src/epd5in65f/mod.rs @@ -6,11 +6,8 @@ //! - [Waveshare C driver](https://github.com/waveshare/e-Paper/blob/master/RaspberryPi%26JetsonNano/c/lib/e-Paper/EPD_5in65f.c) //! - [Waveshare Python driver](https://github.com/waveshare/e-Paper/blob/master/RaspberryPi%26JetsonNano/python/lib/waveshare_epd/epd5in65f.py) -use embedded_hal::{ - delay::DelayUs, - digital::{InputPin, OutputPin}, - spi::SpiDevice, -}; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::{delay::DelayUs, spi::SpiDevice}; use crate::color::OctColor; use crate::interface::DisplayInterface; @@ -57,25 +54,32 @@ where RST: OutputPin, DELAY: DelayUs, { - fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + async fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { // Reset the device - self.interface.reset(delay, 10_000, 2_000); - - self.cmd_with_data(spi, Command::PanelSetting, &[0xEF, 0x08])?; - self.cmd_with_data(spi, Command::PowerSetting, &[0x37, 0x00, 0x23, 0x23])?; - self.cmd_with_data(spi, Command::PowerOffSequenceSetting, &[0x00])?; - self.cmd_with_data(spi, Command::BoosterSoftStart, &[0xC7, 0xC7, 0x1D])?; - self.cmd_with_data(spi, Command::PllControl, &[0x3C])?; - self.cmd_with_data(spi, Command::TemperatureSensor, &[0x00])?; - self.update_vcom(spi)?; - self.cmd_with_data(spi, Command::TconSetting, &[0x22])?; - self.send_resolution(spi)?; - - self.cmd_with_data(spi, Command::FlashMode, &[0xAA])?; - - delay.delay_us(100_000); - - self.update_vcom(spi)?; + self.interface.reset(delay, 10_000, 2_000).await; + + self.cmd_with_data(spi, Command::PanelSetting, &[0xEF, 0x08]) + .await?; + self.cmd_with_data(spi, Command::PowerSetting, &[0x37, 0x00, 0x23, 0x23]) + .await?; + self.cmd_with_data(spi, Command::PowerOffSequenceSetting, &[0x00]) + .await?; + self.cmd_with_data(spi, Command::BoosterSoftStart, &[0xC7, 0xC7, 0x1D]) + .await?; + self.cmd_with_data(spi, Command::PllControl, &[0x3C]) + .await?; + self.cmd_with_data(spi, Command::TemperatureSensor, &[0x00]) + .await?; + self.update_vcom(spi).await?; + self.cmd_with_data(spi, Command::TconSetting, &[0x22]) + .await?; + self.send_resolution(spi).await?; + + self.cmd_with_data(spi, Command::FlashMode, &[0xAA]).await?; + + delay.delay_us(100_000).await; + + self.update_vcom(spi).await?; Ok(()) } } @@ -90,7 +94,7 @@ where DELAY: DelayUs, { type DisplayColor = OctColor; - fn new( + async fn new( spi: &mut SPI, busy: BUSY, dc: DC, @@ -103,34 +107,35 @@ where let mut epd = Epd5in65f { interface, color }; - epd.init(spi, delay)?; + epd.init(spi, delay).await?; Ok(epd) } - fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.init(spi, delay) + async fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.init(spi, delay).await } - fn sleep(&mut self, spi: &mut SPI, _delay: &mut DELAY) -> Result<(), SPI::Error> { - self.cmd_with_data(spi, Command::DeepSleep, &[0xA5])?; + async fn sleep(&mut self, spi: &mut SPI, _delay: &mut DELAY) -> Result<(), SPI::Error> { + self.cmd_with_data(spi, Command::DeepSleep, &[0xA5]).await?; Ok(()) } - fn update_frame( + async fn update_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.update_vcom(spi)?; - self.send_resolution(spi)?; - self.cmd_with_data(spi, Command::DataStartTransmission1, buffer)?; + self.wait_until_idle(spi, delay).await?; + self.update_vcom(spi).await?; + self.send_resolution(spi).await?; + self.cmd_with_data(spi, Command::DataStartTransmission1, buffer) + .await?; Ok(()) } - fn update_partial_frame( + async fn update_partial_frame( &mut self, _spi: &mut SPI, _delay: &mut DELAY, @@ -143,36 +148,38 @@ where unimplemented!(); } - fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.command(spi, Command::PowerOn)?; - self.wait_until_idle(spi, delay)?; - self.command(spi, Command::DisplayRefresh)?; - self.wait_until_idle(spi, delay)?; - self.command(spi, Command::PowerOff)?; - self.wait_busy_low(delay); + async fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; + self.command(spi, Command::PowerOn).await?; + self.wait_until_idle(spi, delay).await?; + self.command(spi, Command::DisplayRefresh).await?; + self.wait_until_idle(spi, delay).await?; + self.command(spi, Command::PowerOff).await?; + self.wait_busy_low(delay).await; Ok(()) } - fn update_and_display_frame( + async fn update_and_display_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.update_frame(spi, buffer, delay)?; - self.display_frame(spi, delay)?; + self.update_frame(spi, buffer, delay).await?; + self.display_frame(spi, delay).await?; Ok(()) } - fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + async fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { let bg = OctColor::colors_byte(self.color, self.color); - self.wait_until_idle(spi, delay)?; - self.update_vcom(spi)?; - self.send_resolution(spi)?; - self.command(spi, Command::DataStartTransmission1)?; - self.interface.data_x_times(spi, bg, WIDTH * HEIGHT / 2)?; - self.display_frame(spi, delay)?; + self.wait_until_idle(spi, delay).await?; + self.update_vcom(spi).await?; + self.send_resolution(spi).await?; + self.command(spi, Command::DataStartTransmission1).await?; + self.interface + .data_x_times(spi, bg, WIDTH * HEIGHT / 2) + .await?; + self.display_frame(spi, delay).await?; Ok(()) } @@ -192,7 +199,7 @@ where HEIGHT } - fn set_lut( + async fn set_lut( &mut self, _spi: &mut SPI, _delay: &mut DELAY, @@ -201,8 +208,12 @@ where unimplemented!(); } - fn wait_until_idle(&mut self, _spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.interface.wait_until_idle(delay, true); + async fn wait_until_idle( + &mut self, + _spi: &mut SPI, + delay: &mut DELAY, + ) -> Result<(), SPI::Error> { + self.interface.wait_until_idle(delay, true).await; Ok(()) } } @@ -215,40 +226,42 @@ where RST: OutputPin, DELAY: DelayUs, { - fn command(&mut self, spi: &mut SPI, command: Command) -> Result<(), SPI::Error> { - self.interface.cmd(spi, command) + async fn command(&mut self, spi: &mut SPI, command: Command) -> Result<(), SPI::Error> { + self.interface.cmd(spi, command).await } - fn send_data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> { - self.interface.data(spi, data) + async fn send_data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> { + self.interface.data(spi, data).await } - fn cmd_with_data( + async fn cmd_with_data( &mut self, spi: &mut SPI, command: Command, data: &[u8], ) -> Result<(), SPI::Error> { - self.interface.cmd_with_data(spi, command, data) + self.interface.cmd_with_data(spi, command, data).await } - fn wait_busy_low(&mut self, delay: &mut DELAY) { - self.interface.wait_until_idle(delay, false); + async fn wait_busy_low(&mut self, delay: &mut DELAY) { + self.interface.wait_until_idle(delay, false).await; } - fn send_resolution(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { + + async fn send_resolution(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { let w = self.width(); let h = self.height(); - self.command(spi, Command::TconResolution)?; - self.send_data(spi, &[(w >> 8) as u8])?; - self.send_data(spi, &[w as u8])?; - self.send_data(spi, &[(h >> 8) as u8])?; - self.send_data(spi, &[h as u8]) + self.command(spi, Command::TconResolution).await?; + self.send_data(spi, &[(w >> 8) as u8]).await?; + self.send_data(spi, &[w as u8]).await?; + self.send_data(spi, &[(h >> 8) as u8]).await?; + self.send_data(spi, &[h as u8]).await } - fn update_vcom(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { + async fn update_vcom(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { let bg_color = (self.color.get_nibble() & 0b111) << 5; - self.cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x17 | bg_color])?; + self.cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x17 | bg_color]) + .await?; Ok(()) } } diff --git a/src/epd5in83b_v2/mod.rs b/src/epd5in83b_v2/mod.rs index d1df524e..ac1c542b 100644 --- a/src/epd5in83b_v2/mod.rs +++ b/src/epd5in83b_v2/mod.rs @@ -6,11 +6,8 @@ //! - [Waveshare C driver](https://github.com/waveshare/e-Paper/blob/master/RaspberryPi_JetsonNano/c/lib/e-Paper/EPD_5in83b_V2.c) //! - [Waveshare Python driver](https://github.com/waveshare/e-Paper/blob/master/RaspberryPi_JetsonNano/python/lib/waveshare_epd/epd5in83b_V2.py) -use embedded_hal::{ - delay::DelayUs, - digital::{InputPin, OutputPin}, - spi::SpiDevice, -}; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::{delay::DelayUs, spi::SpiDevice}; use crate::color::Color; use crate::interface::DisplayInterface; @@ -59,37 +56,42 @@ where RST: OutputPin, DELAY: DelayUs, { - fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + async fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { // Reset the device - self.interface.reset(delay, 10_000, 10_000); + self.interface.reset(delay, 10_000, 10_000).await; // Start the booster - self.cmd_with_data(spi, Command::BoosterSoftStart, &[0x17, 0x17, 0x1e, 0x17])?; + self.cmd_with_data(spi, Command::BoosterSoftStart, &[0x17, 0x17, 0x1e, 0x17]) + .await?; // Set the power settings: VGH=20V,VGL=-20V,VDH=15V,VDL=-15V - self.cmd_with_data(spi, Command::PowerSetting, &[0x07, 0x07, 0x3F, 0x3F])?; + self.cmd_with_data(spi, Command::PowerSetting, &[0x07, 0x07, 0x3F, 0x3F]) + .await?; // Power on - self.command(spi, Command::PowerOn)?; - delay.delay_us(5000); - self.wait_until_idle(spi, delay)?; + self.command(spi, Command::PowerOn).await?; + delay.delay_us(5000).await; + self.wait_until_idle(spi, delay).await?; // Set the panel settings: BWROTP - self.cmd_with_data(spi, Command::PanelSetting, &[0x0F])?; + self.cmd_with_data(spi, Command::PanelSetting, &[0x0F]) + .await?; // Set the real resolution - self.send_resolution(spi)?; + self.send_resolution(spi).await?; // Disable dual SPI - self.cmd_with_data(spi, Command::DualSPI, &[0x00])?; + self.cmd_with_data(spi, Command::DualSPI, &[0x00]).await?; // Set Vcom and data interval - self.cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x11, 0x07])?; + self.cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x11, 0x07]) + .await?; // Set S2G and G2S non-overlap periods to 12 (default) - self.cmd_with_data(spi, Command::TconSetting, &[0x22])?; + self.cmd_with_data(spi, Command::TconSetting, &[0x22]) + .await?; - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; Ok(()) } } @@ -103,37 +105,39 @@ where RST: OutputPin, DELAY: DelayUs, { - fn update_color_frame( + async fn update_color_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, black: &[u8], chromatic: &[u8], ) -> Result<(), SPI::Error> { - self.update_achromatic_frame(spi, delay, black)?; - self.update_chromatic_frame(spi, delay, chromatic)?; + self.update_achromatic_frame(spi, delay, black).await?; + self.update_chromatic_frame(spi, delay, chromatic).await?; Ok(()) } - fn update_achromatic_frame( + async fn update_achromatic_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, black: &[u8], ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.cmd_with_data(spi, Command::DataStartTransmission1, black)?; + self.wait_until_idle(spi, delay).await?; + self.cmd_with_data(spi, Command::DataStartTransmission1, black) + .await?; Ok(()) } - fn update_chromatic_frame( + async fn update_chromatic_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, chromatic: &[u8], ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.cmd_with_data(spi, Command::DataStartTransmission2, chromatic)?; + self.wait_until_idle(spi, delay).await?; + self.cmd_with_data(spi, Command::DataStartTransmission2, chromatic) + .await?; Ok(()) } } @@ -148,7 +152,7 @@ where DELAY: DelayUs, { type DisplayColor = Color; - fn new( + async fn new( spi: &mut SPI, busy: BUSY, dc: DC, @@ -161,21 +165,21 @@ where let mut epd = Epd5in83 { interface, color }; - epd.init(spi, delay)?; + epd.init(spi, delay).await?; Ok(epd) } - fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.command(spi, Command::PowerOff)?; - self.wait_until_idle(spi, delay)?; - self.cmd_with_data(spi, Command::DeepSleep, &[0xA5])?; + async fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; + self.command(spi, Command::PowerOff).await?; + self.wait_until_idle(spi, delay).await?; + self.cmd_with_data(spi, Command::DeepSleep, &[0xA5]).await?; Ok(()) } - fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.init(spi, delay) + async fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.init(spi, delay).await } fn set_background_color(&mut self, color: Color) { @@ -194,21 +198,23 @@ where HEIGHT } - fn update_frame( + async fn update_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.update_achromatic_frame(spi, delay, buffer)?; + self.wait_until_idle(spi, delay).await?; + self.update_achromatic_frame(spi, delay, buffer).await?; let color = self.color.get_byte_value(); - self.command(spi, Command::DataStartTransmission2)?; - self.interface.data_x_times(spi, color, NUM_DISPLAY_BITS)?; + self.command(spi, Command::DataStartTransmission2).await?; + self.interface + .data_x_times(spi, color, NUM_DISPLAY_BITS) + .await?; Ok(()) } - fn update_partial_frame( + async fn update_partial_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -218,7 +224,7 @@ where width: u32, height: u32, ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; if buffer.len() as u32 != width / 8 * height { //TODO panic or error } @@ -233,61 +239,67 @@ where let vred_lower = (y + height) as u8; let pt_scan = 0x01; // Gates scan both inside and outside of the partial window. (default) - self.command(spi, Command::PartialIn)?; - self.command(spi, Command::PartialWindow)?; + self.command(spi, Command::PartialIn).await?; + self.command(spi, Command::PartialWindow).await?; self.send_data( spi, &[ hrst_upper, hrst_lower, hred_upper, hred_lower, vrst_upper, vrst_lower, vred_upper, vred_lower, pt_scan, ], - )?; - self.command(spi, Command::DataStartTransmission1)?; - self.send_data(spi, buffer)?; + ) + .await?; + self.command(spi, Command::DataStartTransmission1).await?; + self.send_data(spi, buffer).await?; let color = TriColor::Black.get_byte_value(); //We need it black, so red channel will be rendered transparent - self.command(spi, Command::DataStartTransmission2)?; + self.command(spi, Command::DataStartTransmission2).await?; self.interface - .data_x_times(spi, color, width * height / 8)?; + .data_x_times(spi, color, width * height / 8) + .await?; - self.command(spi, Command::DisplayRefresh)?; - self.wait_until_idle(spi, delay)?; + self.command(spi, Command::DisplayRefresh).await?; + self.wait_until_idle(spi, delay).await?; - self.command(spi, Command::PartialOut)?; + self.command(spi, Command::PartialOut).await?; Ok(()) } - fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.command(spi, Command::DisplayRefresh)?; - self.wait_until_idle(spi, delay)?; + async fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.command(spi, Command::DisplayRefresh).await?; + self.wait_until_idle(spi, delay).await?; Ok(()) } - fn update_and_display_frame( + async fn update_and_display_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.update_frame(spi, buffer, delay)?; - self.display_frame(spi, delay)?; + self.update_frame(spi, buffer, delay).await?; + self.display_frame(spi, delay).await?; Ok(()) } - fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + async fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; // The Waveshare controllers all implement clear using 0x33 - self.command(spi, Command::DataStartTransmission1)?; - self.interface.data_x_times(spi, 0xFF, NUM_DISPLAY_BITS)?; + self.command(spi, Command::DataStartTransmission1).await?; + self.interface + .data_x_times(spi, 0xFF, NUM_DISPLAY_BITS) + .await?; - self.command(spi, Command::DataStartTransmission2)?; - self.interface.data_x_times(spi, 0x00, NUM_DISPLAY_BITS)?; + self.command(spi, Command::DataStartTransmission2).await?; + self.interface + .data_x_times(spi, 0x00, NUM_DISPLAY_BITS) + .await?; Ok(()) } - fn set_lut( + async fn set_lut( &mut self, _spi: &mut SPI, _delay: &mut DELAY, @@ -296,8 +308,12 @@ where unimplemented!(); } - fn wait_until_idle(&mut self, _spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.interface.wait_until_idle(delay, IS_BUSY_LOW); + async fn wait_until_idle( + &mut self, + _spi: &mut SPI, + delay: &mut DELAY, + ) -> Result<(), SPI::Error> { + self.interface.wait_until_idle(delay, IS_BUSY_LOW).await; Ok(()) } } @@ -310,32 +326,32 @@ where RST: OutputPin, DELAY: DelayUs, { - fn command(&mut self, spi: &mut SPI, command: Command) -> Result<(), SPI::Error> { - self.interface.cmd(spi, command) + async fn command(&mut self, spi: &mut SPI, command: Command) -> Result<(), SPI::Error> { + self.interface.cmd(spi, command).await } - fn send_data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> { - self.interface.data(spi, data) + async fn send_data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> { + self.interface.data(spi, data).await } - fn cmd_with_data( + async fn cmd_with_data( &mut self, spi: &mut SPI, command: Command, data: &[u8], ) -> Result<(), SPI::Error> { - self.interface.cmd_with_data(spi, command, data) + self.interface.cmd_with_data(spi, command, data).await } - fn send_resolution(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { + async fn send_resolution(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { let w = self.width(); let h = self.height(); - self.command(spi, Command::TconResolution)?; - self.send_data(spi, &[(w >> 8) as u8])?; - self.send_data(spi, &[w as u8])?; - self.send_data(spi, &[(h >> 8) as u8])?; - self.send_data(spi, &[h as u8]) + self.command(spi, Command::TconResolution).await?; + self.send_data(spi, &[(w >> 8) as u8]).await?; + self.send_data(spi, &[w as u8]).await?; + self.send_data(spi, &[(h >> 8) as u8]).await?; + self.send_data(spi, &[h as u8]).await } } diff --git a/src/epd7in5/mod.rs b/src/epd7in5/mod.rs index 5b89e1a1..37fa337c 100644 --- a/src/epd7in5/mod.rs +++ b/src/epd7in5/mod.rs @@ -6,11 +6,8 @@ //! - [Waveshare C driver](https://github.com/waveshare/e-Paper/blob/702def06bcb75983c98b0f9d25d43c552c248eb0/RaspberryPi%26JetsonNano/c/lib/e-Paper/EPD_7in5.c) //! - [Waveshare Python driver](https://github.com/waveshare/e-Paper/blob/702def06bcb75983c98b0f9d25d43c552c248eb0/RaspberryPi%26JetsonNano/python/lib/waveshare_epd/epd7in5.py) -use embedded_hal::{ - delay::DelayUs, - digital::{InputPin, OutputPin}, - spi::SpiDevice, -}; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::{delay::DelayUs, spi::SpiDevice}; use crate::color::Color; use crate::interface::DisplayInterface; @@ -57,48 +54,56 @@ where RST: OutputPin, DELAY: DelayUs, { - fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + async fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { // Reset the device - self.interface.reset(delay, 10_000, 10_000); + self.interface.reset(delay, 10_000, 10_000).await; // Set the power settings - self.cmd_with_data(spi, Command::PowerSetting, &[0x37, 0x00])?; + self.cmd_with_data(spi, Command::PowerSetting, &[0x37, 0x00]) + .await?; // Set the panel settings: // - 600 x 448 // - Using LUT from external flash - self.cmd_with_data(spi, Command::PanelSetting, &[0xCF, 0x08])?; + self.cmd_with_data(spi, Command::PanelSetting, &[0xCF, 0x08]) + .await?; // Start the booster - self.cmd_with_data(spi, Command::BoosterSoftStart, &[0xC7, 0xCC, 0x28])?; + self.cmd_with_data(spi, Command::BoosterSoftStart, &[0xC7, 0xCC, 0x28]) + .await?; // Power on - self.command(spi, Command::PowerOn)?; - delay.delay_us(5000); - self.wait_until_idle(spi, delay)?; + self.command(spi, Command::PowerOn).await?; + delay.delay_us(5000).await; + self.wait_until_idle(spi, delay).await?; // Set the clock frequency to 50Hz (default) - self.cmd_with_data(spi, Command::PllControl, &[0x3C])?; + self.cmd_with_data(spi, Command::PllControl, &[0x3C]) + .await?; // Select internal temperature sensor (default) - self.cmd_with_data(spi, Command::TemperatureCalibration, &[0x00])?; + self.cmd_with_data(spi, Command::TemperatureCalibration, &[0x00]) + .await?; // Set Vcom and data interval to 10 (default), border output to white - self.cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x77])?; + self.cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x77]) + .await?; // Set S2G and G2S non-overlap periods to 12 (default) - self.cmd_with_data(spi, Command::TconSetting, &[0x22])?; + self.cmd_with_data(spi, Command::TconSetting, &[0x22]) + .await?; // Set the real resolution - self.send_resolution(spi)?; + self.send_resolution(spi).await?; // Set VCOM_DC to -1.5V - self.cmd_with_data(spi, Command::VcmDcSetting, &[0x1E])?; + self.cmd_with_data(spi, Command::VcmDcSetting, &[0x1E]) + .await?; // This is in all the Waveshare controllers for Epd7in5 - self.cmd_with_data(spi, Command::FlashMode, &[0x03])?; + self.cmd_with_data(spi, Command::FlashMode, &[0x03]).await?; - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; Ok(()) } } @@ -113,7 +118,7 @@ where DELAY: DelayUs, { type DisplayColor = Color; - fn new( + async fn new( spi: &mut SPI, busy: BUSY, dc: DC, @@ -126,21 +131,21 @@ where let mut epd = Epd7in5 { interface, color }; - epd.init(spi, delay)?; + epd.init(spi, delay).await?; Ok(epd) } - fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.command(spi, Command::PowerOff)?; - self.wait_until_idle(spi, delay)?; - self.cmd_with_data(spi, Command::DeepSleep, &[0xA5])?; + async fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; + self.command(spi, Command::PowerOff).await?; + self.wait_until_idle(spi, delay).await?; + self.cmd_with_data(spi, Command::DeepSleep, &[0xA5]).await?; Ok(()) } - fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.init(spi, delay) + async fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.init(spi, delay).await } fn set_background_color(&mut self, color: Color) { @@ -159,14 +164,14 @@ where HEIGHT } - fn update_frame( + async fn update_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.command(spi, Command::DataStartTransmission1)?; + self.wait_until_idle(spi, delay).await?; + self.command(spi, Command::DataStartTransmission1).await?; for byte in buffer { let mut temp = *byte; for _ in 0..4 { @@ -175,13 +180,13 @@ where temp <<= 1; data |= if temp & 0x80 == 0 { 0x00 } else { 0x03 }; temp <<= 1; - self.send_data(spi, &[data])?; + self.send_data(spi, &[data]).await?; } } Ok(()) } - fn update_partial_frame( + async fn update_partial_frame( &mut self, _spi: &mut SPI, _delay: &mut DELAY, @@ -194,35 +199,36 @@ where unimplemented!(); } - fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.command(spi, Command::DisplayRefresh)?; + async fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; + self.command(spi, Command::DisplayRefresh).await?; Ok(()) } - fn update_and_display_frame( + async fn update_and_display_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.update_frame(spi, buffer, delay)?; - self.command(spi, Command::DisplayRefresh)?; + self.update_frame(spi, buffer, delay).await?; + self.command(spi, Command::DisplayRefresh).await?; Ok(()) } - fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.send_resolution(spi)?; + async fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; + self.send_resolution(spi).await?; // The Waveshare controllers all implement clear using 0x33 - self.command(spi, Command::DataStartTransmission1)?; + self.command(spi, Command::DataStartTransmission1).await?; self.interface - .data_x_times(spi, 0x33, WIDTH / 8 * HEIGHT * 4)?; + .data_x_times(spi, 0x33, WIDTH / 8 * HEIGHT * 4) + .await?; Ok(()) } - fn set_lut( + async fn set_lut( &mut self, _spi: &mut SPI, _delay: &mut DELAY, @@ -231,8 +237,12 @@ where unimplemented!(); } - fn wait_until_idle(&mut self, _spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.interface.wait_until_idle(delay, IS_BUSY_LOW); + async fn wait_until_idle( + &mut self, + _spi: &mut SPI, + delay: &mut DELAY, + ) -> Result<(), SPI::Error> { + self.interface.wait_until_idle(delay, IS_BUSY_LOW).await; Ok(()) } } @@ -245,32 +255,32 @@ where RST: OutputPin, DELAY: DelayUs, { - fn command(&mut self, spi: &mut SPI, command: Command) -> Result<(), SPI::Error> { - self.interface.cmd(spi, command) + async fn command(&mut self, spi: &mut SPI, command: Command) -> Result<(), SPI::Error> { + self.interface.cmd(spi, command).await } - fn send_data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> { - self.interface.data(spi, data) + async fn send_data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> { + self.interface.data(spi, data).await } - fn cmd_with_data( + async fn cmd_with_data( &mut self, spi: &mut SPI, command: Command, data: &[u8], ) -> Result<(), SPI::Error> { - self.interface.cmd_with_data(spi, command, data) + self.interface.cmd_with_data(spi, command, data).await } - fn send_resolution(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { + async fn send_resolution(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { let w = self.width(); let h = self.height(); - self.command(spi, Command::TconResolution)?; - self.send_data(spi, &[(w >> 8) as u8])?; - self.send_data(spi, &[w as u8])?; - self.send_data(spi, &[(h >> 8) as u8])?; - self.send_data(spi, &[h as u8]) + self.command(spi, Command::TconResolution).await?; + self.send_data(spi, &[(w >> 8) as u8]).await?; + self.send_data(spi, &[w as u8]).await?; + self.send_data(spi, &[(h >> 8) as u8]).await?; + self.send_data(spi, &[h as u8]).await } } diff --git a/src/epd7in5_hd/mod.rs b/src/epd7in5_hd/mod.rs index 5ef9cd47..740eb30d 100644 --- a/src/epd7in5_hd/mod.rs +++ b/src/epd7in5_hd/mod.rs @@ -9,11 +9,8 @@ //! - [Datasheet](https://www.waveshare.com/w/upload/2/27/7inch_HD_e-Paper_Specification.pdf) //! - [Waveshare Python driver](https://github.com/waveshare/e-Paper/blob/master/RaspberryPi_JetsonNano/python/lib/waveshare_epd/epd7in5_HD.py) //! -use embedded_hal::{ - delay::DelayUs, - digital::{InputPin, OutputPin}, - spi::SpiDevice, -}; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::{delay::DelayUs, spi::SpiDevice}; use crate::color::Color; use crate::interface::DisplayInterface; @@ -60,44 +57,55 @@ where RST: OutputPin, DELAY: DelayUs, { - fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + async fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { // Reset the device - self.interface.reset(delay, 10_000, 2_000); + self.interface.reset(delay, 10_000, 2_000).await; // HD procedure as described here: // https://github.com/waveshare/e-Paper/blob/master/RaspberryPi_JetsonNano/python/lib/waveshare_epd/epd7in5_HD.py // and as per specs: // https://www.waveshare.com/w/upload/2/27/7inch_HD_e-Paper_Specification.pdf - self.wait_until_idle(spi, delay)?; - self.command(spi, Command::SwReset)?; - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; + self.command(spi, Command::SwReset).await?; + self.wait_until_idle(spi, delay).await?; - self.cmd_with_data(spi, Command::AutoWriteRed, &[0xF7])?; - self.wait_until_idle(spi, delay)?; - self.cmd_with_data(spi, Command::AutoWriteBw, &[0xF7])?; - self.wait_until_idle(spi, delay)?; + self.cmd_with_data(spi, Command::AutoWriteRed, &[0xF7]) + .await?; + self.wait_until_idle(spi, delay).await?; + self.cmd_with_data(spi, Command::AutoWriteBw, &[0xF7]) + .await?; + self.wait_until_idle(spi, delay).await?; - self.cmd_with_data(spi, Command::SoftStart, &[0xAE, 0xC7, 0xC3, 0xC0, 0x40])?; + self.cmd_with_data(spi, Command::SoftStart, &[0xAE, 0xC7, 0xC3, 0xC0, 0x40]) + .await?; - self.cmd_with_data(spi, Command::DriverOutputControl, &[0xAF, 0x02, 0x01])?; + self.cmd_with_data(spi, Command::DriverOutputControl, &[0xAF, 0x02, 0x01]) + .await?; - self.cmd_with_data(spi, Command::DataEntry, &[0x01])?; + self.cmd_with_data(spi, Command::DataEntry, &[0x01]).await?; - self.cmd_with_data(spi, Command::SetRamXStartEnd, &[0x00, 0x00, 0x6F, 0x03])?; - self.cmd_with_data(spi, Command::SetRamYStartEnd, &[0xAF, 0x02, 0x00, 0x00])?; + self.cmd_with_data(spi, Command::SetRamXStartEnd, &[0x00, 0x00, 0x6F, 0x03]) + .await?; + self.cmd_with_data(spi, Command::SetRamYStartEnd, &[0xAF, 0x02, 0x00, 0x00]) + .await?; - self.cmd_with_data(spi, Command::VbdControl, &[0x05])?; + self.cmd_with_data(spi, Command::VbdControl, &[0x05]) + .await?; - self.cmd_with_data(spi, Command::TemperatureSensorControl, &[0x80])?; + self.cmd_with_data(spi, Command::TemperatureSensorControl, &[0x80]) + .await?; - self.cmd_with_data(spi, Command::DisplayUpdateControl2, &[0xB1])?; + self.cmd_with_data(spi, Command::DisplayUpdateControl2, &[0xB1]) + .await?; - self.command(spi, Command::MasterActivation)?; - self.wait_until_idle(spi, delay)?; + self.command(spi, Command::MasterActivation).await?; + self.wait_until_idle(spi, delay).await?; - self.cmd_with_data(spi, Command::SetRamXAc, &[0x00, 0x00])?; - self.cmd_with_data(spi, Command::SetRamYAc, &[0x00, 0x00])?; + self.cmd_with_data(spi, Command::SetRamXAc, &[0x00, 0x00]) + .await?; + self.cmd_with_data(spi, Command::SetRamYAc, &[0x00, 0x00]) + .await?; Ok(()) } @@ -113,7 +121,7 @@ where DELAY: DelayUs, { type DisplayColor = Color; - fn new( + async fn new( spi: &mut SPI, busy: BUSY, dc: DC, @@ -126,35 +134,37 @@ where let mut epd = Epd7in5 { interface, color }; - epd.init(spi, delay)?; + epd.init(spi, delay).await?; Ok(epd) } - fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.init(spi, delay) + async fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.init(spi, delay).await } - fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.cmd_with_data(spi, Command::DeepSleep, &[0x01])?; + async fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; + self.cmd_with_data(spi, Command::DeepSleep, &[0x01]).await?; Ok(()) } - fn update_frame( + async fn update_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.cmd_with_data(spi, Command::SetRamYAc, &[0x00, 0x00])?; - self.cmd_with_data(spi, Command::WriteRamBw, buffer)?; - self.cmd_with_data(spi, Command::DisplayUpdateControl2, &[0xF7])?; + self.wait_until_idle(spi, delay).await?; + self.cmd_with_data(spi, Command::SetRamYAc, &[0x00, 0x00]) + .await?; + self.cmd_with_data(spi, Command::WriteRamBw, buffer).await?; + self.cmd_with_data(spi, Command::DisplayUpdateControl2, &[0xF7]) + .await?; Ok(()) } - fn update_partial_frame( + async fn update_partial_frame( &mut self, _spi: &mut SPI, _delay: &mut DELAY, @@ -167,39 +177,42 @@ where unimplemented!(); } - fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.command(spi, Command::MasterActivation)?; - self.wait_until_idle(spi, delay)?; + async fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.command(spi, Command::MasterActivation).await?; + self.wait_until_idle(spi, delay).await?; Ok(()) } - fn update_and_display_frame( + async fn update_and_display_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.update_frame(spi, buffer, delay)?; - self.display_frame(spi, delay)?; + self.update_frame(spi, buffer, delay).await?; + self.display_frame(spi, delay).await?; Ok(()) } - fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + async fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { let pixel_count = WIDTH * HEIGHT / 8; let background_color_byte = self.color.get_byte_value(); - self.wait_until_idle(spi, delay)?; - self.cmd_with_data(spi, Command::SetRamYAc, &[0x00, 0x00])?; + self.wait_until_idle(spi, delay).await?; + self.cmd_with_data(spi, Command::SetRamYAc, &[0x00, 0x00]) + .await?; for cmd in &[Command::WriteRamBw, Command::WriteRamRed] { - self.command(spi, *cmd)?; + self.command(spi, *cmd).await?; self.interface - .data_x_times(spi, background_color_byte, pixel_count)?; + .data_x_times(spi, background_color_byte, pixel_count) + .await?; } - self.cmd_with_data(spi, Command::DisplayUpdateControl2, &[0xF7])?; - self.command(spi, Command::MasterActivation)?; - self.wait_until_idle(spi, delay)?; + self.cmd_with_data(spi, Command::DisplayUpdateControl2, &[0xF7]) + .await?; + self.command(spi, Command::MasterActivation).await?; + self.wait_until_idle(spi, delay).await?; Ok(()) } @@ -219,7 +232,7 @@ where HEIGHT } - fn set_lut( + async fn set_lut( &mut self, _spi: &mut SPI, _delay: &mut DELAY, @@ -228,8 +241,12 @@ where unimplemented!(); } - fn wait_until_idle(&mut self, _spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.interface.wait_until_idle(delay, IS_BUSY_LOW); + async fn wait_until_idle( + &mut self, + _spi: &mut SPI, + delay: &mut DELAY, + ) -> Result<(), SPI::Error> { + self.interface.wait_until_idle(delay, IS_BUSY_LOW).await; Ok(()) } } @@ -242,17 +259,17 @@ where RST: OutputPin, DELAY: DelayUs, { - fn command(&mut self, spi: &mut SPI, command: Command) -> Result<(), SPI::Error> { - self.interface.cmd(spi, command) + async fn command(&mut self, spi: &mut SPI, command: Command) -> Result<(), SPI::Error> { + self.interface.cmd(spi, command).await } - fn cmd_with_data( + async fn cmd_with_data( &mut self, spi: &mut SPI, command: Command, data: &[u8], ) -> Result<(), SPI::Error> { - self.interface.cmd_with_data(spi, command, data) + self.interface.cmd_with_data(spi, command, data).await } } diff --git a/src/epd7in5_v2/mod.rs b/src/epd7in5_v2/mod.rs index f971bf43..f199cee7 100644 --- a/src/epd7in5_v2/mod.rs +++ b/src/epd7in5_v2/mod.rs @@ -10,11 +10,8 @@ //! Revision V2 has been released on 2019.11, the resolution is upgraded to 800×480, from 640×384 of V1. //! The hardware and interface of V2 are compatible with V1, however, the related software should be updated. -use embedded_hal::{ - delay::DelayUs, - digital::{InputPin, OutputPin}, - spi::SpiDevice, -}; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::{delay::DelayUs, spi::SpiDevice}; use crate::color::Color; use crate::interface::DisplayInterface; @@ -61,26 +58,33 @@ where RST: OutputPin, DELAY: DelayUs, { - fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + async fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { // Reset the device - self.interface.reset(delay, 10_000, 2_000); + self.interface.reset(delay, 10_000, 2_000).await; // V2 procedure as described here: // https://github.com/waveshare/e-Paper/blob/master/RaspberryPi%26JetsonNano/python/lib/waveshare_epd/epd7in5bc_V2.py // and as per specs: // https://www.waveshare.com/w/upload/6/60/7.5inch_e-Paper_V2_Specification.pdf - self.cmd_with_data(spi, Command::BoosterSoftStart, &[0x17, 0x17, 0x27, 0x17])?; - self.cmd_with_data(spi, Command::PowerSetting, &[0x07, 0x17, 0x3F, 0x3F])?; - self.command(spi, Command::PowerOn)?; - self.wait_until_idle(spi, delay)?; - self.cmd_with_data(spi, Command::PanelSetting, &[0x1F])?; - self.cmd_with_data(spi, Command::PllControl, &[0x06])?; - self.cmd_with_data(spi, Command::TconResolution, &[0x03, 0x20, 0x01, 0xE0])?; - self.cmd_with_data(spi, Command::DualSpi, &[0x00])?; - self.cmd_with_data(spi, Command::TconSetting, &[0x22])?; - self.cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x10, 0x07])?; - self.wait_until_idle(spi, delay)?; + self.cmd_with_data(spi, Command::BoosterSoftStart, &[0x17, 0x17, 0x27, 0x17]) + .await?; + self.cmd_with_data(spi, Command::PowerSetting, &[0x07, 0x17, 0x3F, 0x3F]) + .await?; + self.command(spi, Command::PowerOn).await?; + self.wait_until_idle(spi, delay).await?; + self.cmd_with_data(spi, Command::PanelSetting, &[0x1F]) + .await?; + self.cmd_with_data(spi, Command::PllControl, &[0x06]) + .await?; + self.cmd_with_data(spi, Command::TconResolution, &[0x03, 0x20, 0x01, 0xE0]) + .await?; + self.cmd_with_data(spi, Command::DualSpi, &[0x00]).await?; + self.cmd_with_data(spi, Command::TconSetting, &[0x22]) + .await?; + self.cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x10, 0x07]) + .await?; + self.wait_until_idle(spi, delay).await?; Ok(()) } } @@ -95,7 +99,7 @@ where DELAY: DelayUs, { type DisplayColor = Color; - fn new( + async fn new( spi: &mut SPI, busy: BUSY, dc: DC, @@ -108,35 +112,36 @@ where let mut epd = Epd7in5 { interface, color }; - epd.init(spi, delay)?; + epd.init(spi, delay).await?; Ok(epd) } - fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.init(spi, delay) + async fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.init(spi, delay).await } - fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.command(spi, Command::PowerOff)?; - self.wait_until_idle(spi, delay)?; - self.cmd_with_data(spi, Command::DeepSleep, &[0xA5])?; + async fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; + self.command(spi, Command::PowerOff).await?; + self.wait_until_idle(spi, delay).await?; + self.cmd_with_data(spi, Command::DeepSleep, &[0xA5]).await?; Ok(()) } - fn update_frame( + async fn update_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.cmd_with_data(spi, Command::DataStartTransmission2, buffer)?; + self.wait_until_idle(spi, delay).await?; + self.cmd_with_data(spi, Command::DataStartTransmission2, buffer) + .await?; Ok(()) } - fn update_partial_frame( + async fn update_partial_frame( &mut self, _spi: &mut SPI, _delay: &mut DELAY, @@ -149,34 +154,38 @@ where unimplemented!(); } - fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.command(spi, Command::DisplayRefresh)?; + async fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; + self.command(spi, Command::DisplayRefresh).await?; Ok(()) } - fn update_and_display_frame( + async fn update_and_display_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.update_frame(spi, buffer, delay)?; - self.command(spi, Command::DisplayRefresh)?; + self.update_frame(spi, buffer, delay).await?; + self.command(spi, Command::DisplayRefresh).await?; Ok(()) } - fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.send_resolution(spi)?; + async fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; + self.send_resolution(spi).await?; - self.command(spi, Command::DataStartTransmission1)?; - self.interface.data_x_times(spi, 0x00, WIDTH * HEIGHT / 8)?; + self.command(spi, Command::DataStartTransmission1).await?; + self.interface + .data_x_times(spi, 0x00, WIDTH * HEIGHT / 8) + .await?; - self.command(spi, Command::DataStartTransmission2)?; - self.interface.data_x_times(spi, 0x00, WIDTH * HEIGHT / 8)?; + self.command(spi, Command::DataStartTransmission2).await?; + self.interface + .data_x_times(spi, 0x00, WIDTH * HEIGHT / 8) + .await?; - self.command(spi, Command::DisplayRefresh)?; + self.command(spi, Command::DisplayRefresh).await?; Ok(()) } @@ -196,7 +205,7 @@ where HEIGHT } - fn set_lut( + async fn set_lut( &mut self, _spi: &mut SPI, _delay: &mut DELAY, @@ -205,9 +214,14 @@ where unimplemented!(); } - fn wait_until_idle(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + async fn wait_until_idle( + &mut self, + spi: &mut SPI, + delay: &mut DELAY, + ) -> Result<(), SPI::Error> { self.interface .wait_until_idle_with_cmd(spi, delay, IS_BUSY_LOW, Command::GetStatus) + .await } } @@ -219,32 +233,32 @@ where RST: OutputPin, DELAY: DelayUs, { - fn command(&mut self, spi: &mut SPI, command: Command) -> Result<(), SPI::Error> { - self.interface.cmd(spi, command) + async fn command(&mut self, spi: &mut SPI, command: Command) -> Result<(), SPI::Error> { + self.interface.cmd(spi, command).await } - fn send_data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> { - self.interface.data(spi, data) + async fn send_data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> { + self.interface.data(spi, data).await } - fn cmd_with_data( + async fn cmd_with_data( &mut self, spi: &mut SPI, command: Command, data: &[u8], ) -> Result<(), SPI::Error> { - self.interface.cmd_with_data(spi, command, data) + self.interface.cmd_with_data(spi, command, data).await } - fn send_resolution(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { + async fn send_resolution(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { let w = self.width(); let h = self.height(); - self.command(spi, Command::TconResolution)?; - self.send_data(spi, &[(w >> 8) as u8])?; - self.send_data(spi, &[w as u8])?; - self.send_data(spi, &[(h >> 8) as u8])?; - self.send_data(spi, &[h as u8]) + self.command(spi, Command::TconResolution).await?; + self.send_data(spi, &[(w >> 8) as u8]).await?; + self.send_data(spi, &[w as u8]).await?; + self.send_data(spi, &[(h >> 8) as u8]).await?; + self.send_data(spi, &[h as u8]).await } } diff --git a/src/epd7in5_v3/mod.rs b/src/epd7in5_v3/mod.rs index 962924af..afa97fd2 100644 --- a/src/epd7in5_v3/mod.rs +++ b/src/epd7in5_v3/mod.rs @@ -7,11 +7,8 @@ //! - [Waveshare Python driver](https://github.com/waveshare/e-Paper/blob/702def0/RaspberryPi%26JetsonNano/python/lib/waveshare_epd/epd7in5_V2.py) //! -use embedded_hal::{ - delay::DelayUs, - digital::{InputPin, OutputPin}, - spi::SpiDevice, -}; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::{delay::DelayUs, spi::SpiDevice}; use crate::color::TriColor; use crate::interface::DisplayInterface; @@ -65,27 +62,33 @@ where RST: OutputPin, DELAY: DelayUs, { - fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + async fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { // Reset the device - self.interface.reset(delay, 200_000, 4_000); + self.interface.reset(delay, 200_000, 4_000).await; // V2 procedure as described here: // https://github.com/waveshare/e-Paper/blob/master/RaspberryPi%26JetsonNano/python/lib/waveshare_epd/epd7in5bc_V2.py // and as per specs: // https://www.waveshare.com/w/upload/6/60/7.5inch_e-Paper_V2_Specification.pdf - //self.cmd_with_data(spi, Command::BoosterSoftStart, &[0x17, 0x17, 0x27, 0x17])?; - self.cmd_with_data(spi, Command::PowerSetting, &[0x07, 0x07, 0x3F, 0x3F])?; - self.command(spi, Command::PowerOn)?; - self.wait_until_idle(spi, delay)?; - self.cmd_with_data(spi, Command::PanelSetting, &[0x0F])?; - //self.cmd_with_data(spi, Command::PllControl, &[0x06])?; - self.cmd_with_data(spi, Command::TconResolution, &[0x03, 0x20, 0x01, 0xE0])?; - self.cmd_with_data(spi, Command::DualSpi, &[0x00])?; - self.cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x11, 0x07])?; - self.cmd_with_data(spi, Command::TconSetting, &[0x22])?; - self.cmd_with_data(spi, Command::SpiFlashControl, &[0x00, 0x00, 0x00, 0x00])?; - self.wait_until_idle(spi, delay)?; + //self.cmd_with_data(spi, Command::BoosterSoftStart, &[0x17, 0x17, 0x27, 0x17]).await?; + self.cmd_with_data(spi, Command::PowerSetting, &[0x07, 0x07, 0x3F, 0x3F]) + .await?; + self.command(spi, Command::PowerOn).await?; + self.wait_until_idle(spi, delay).await?; + self.cmd_with_data(spi, Command::PanelSetting, &[0x0F]) + .await?; + //self.cmd_with_data(spi, Command::PllControl, &[0x06]).await?; + self.cmd_with_data(spi, Command::TconResolution, &[0x03, 0x20, 0x01, 0xE0]) + .await?; + self.cmd_with_data(spi, Command::DualSpi, &[0x00]).await?; + self.cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x11, 0x07]) + .await?; + self.cmd_with_data(spi, Command::TconSetting, &[0x22]) + .await?; + self.cmd_with_data(spi, Command::SpiFlashControl, &[0x00, 0x00, 0x00, 0x00]) + .await?; + self.wait_until_idle(spi, delay).await?; Ok(()) } } @@ -99,44 +102,48 @@ where RST: OutputPin, DELAY: DelayUs, { - fn update_color_frame( + async fn update_color_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, black: &[u8], chromatic: &[u8], ) -> Result<(), SPI::Error> { - self.update_achromatic_frame(spi, delay, black)?; - self.update_chromatic_frame(spi, delay, chromatic) + self.update_achromatic_frame(spi, delay, black).await?; + self.update_chromatic_frame(spi, delay, chromatic).await } /// Update only the black/white data of the display. /// /// Finish by calling `update_chromatic_frame`. - fn update_achromatic_frame( + async fn update_achromatic_frame( &mut self, spi: &mut SPI, _delay: &mut DELAY, black: &[u8], ) -> Result<(), SPI::Error> { - self.interface.cmd(spi, Command::DataStartTransmission1)?; - self.interface.data(spi, black)?; + self.interface + .cmd(spi, Command::DataStartTransmission1) + .await?; + self.interface.data(spi, black).await?; Ok(()) } /// Update only chromatic data of the display. /// /// This data takes precedence over the black/white data. - fn update_chromatic_frame( + async fn update_chromatic_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, chromatic: &[u8], ) -> Result<(), SPI::Error> { - self.interface.cmd(spi, Command::DataStartTransmission2)?; - self.interface.data(spi, chromatic)?; + self.interface + .cmd(spi, Command::DataStartTransmission2) + .await?; + self.interface.data(spi, chromatic).await?; - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; Ok(()) } } @@ -151,7 +158,7 @@ where DELAY: DelayUs, { type DisplayColor = TriColor; - fn new( + async fn new( spi: &mut SPI, busy: BUSY, dc: DC, @@ -164,46 +171,51 @@ where let mut epd = Epd7in5 { interface, color }; - epd.init(spi, delay)?; + epd.init(spi, delay).await?; Ok(epd) } - fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.init(spi, delay) + async fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.init(spi, delay).await } - fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.command(spi, Command::PowerOff)?; - self.wait_until_idle(spi, delay)?; - self.cmd_with_data(spi, Command::DeepSleep, &[0xA5])?; + async fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; + self.command(spi, Command::PowerOff).await?; + self.wait_until_idle(spi, delay).await?; + self.cmd_with_data(spi, Command::DeepSleep, &[0xA5]).await?; Ok(()) } - fn update_frame( + async fn update_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.cmd_with_data(spi, Command::DataStartTransmission2, buffer)?; + self.wait_until_idle(spi, delay).await?; + self.cmd_with_data(spi, Command::DataStartTransmission2, buffer) + .await?; - self.interface.data(spi, buffer)?; + self.interface.data(spi, buffer).await?; // Clear the chromatic layer let color = self.color.get_byte_value(); - self.interface.cmd(spi, Command::DataStartTransmission2)?; - self.interface.data_x_times(spi, color, NUM_DISPLAY_BITS)?; + self.interface + .cmd(spi, Command::DataStartTransmission2) + .await?; + self.interface + .data_x_times(spi, color, NUM_DISPLAY_BITS) + .await?; - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; Ok(()) } - fn update_partial_frame( + async fn update_partial_frame( &mut self, _spi: &mut SPI, _delay: &mut DELAY, @@ -216,34 +228,38 @@ where unimplemented!(); } - fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.command(spi, Command::DisplayRefresh)?; + async fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; + self.command(spi, Command::DisplayRefresh).await?; Ok(()) } - fn update_and_display_frame( + async fn update_and_display_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.update_frame(spi, buffer, delay)?; - self.command(spi, Command::DisplayRefresh)?; + self.update_frame(spi, buffer, delay).await?; + self.command(spi, Command::DisplayRefresh).await?; Ok(()) } - fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.send_resolution(spi)?; + async fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; + self.send_resolution(spi).await?; - self.command(spi, Command::DataStartTransmission1)?; - self.interface.data_x_times(spi, 0x00, WIDTH * HEIGHT / 8)?; + self.command(spi, Command::DataStartTransmission1).await?; + self.interface + .data_x_times(spi, 0x00, WIDTH * HEIGHT / 8) + .await?; - self.command(spi, Command::DataStartTransmission2)?; - self.interface.data_x_times(spi, 0x00, WIDTH * HEIGHT / 8)?; + self.command(spi, Command::DataStartTransmission2).await?; + self.interface + .data_x_times(spi, 0x00, WIDTH * HEIGHT / 8) + .await?; - self.command(spi, Command::DisplayRefresh)?; + self.command(spi, Command::DisplayRefresh).await?; Ok(()) } @@ -263,7 +279,7 @@ where HEIGHT } - fn set_lut( + async fn set_lut( &mut self, _spi: &mut SPI, _delay: &mut DELAY, @@ -272,9 +288,14 @@ where unimplemented!(); } - fn wait_until_idle(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + async fn wait_until_idle( + &mut self, + spi: &mut SPI, + delay: &mut DELAY, + ) -> Result<(), SPI::Error> { self.interface .wait_until_idle_with_cmd(spi, delay, IS_BUSY_LOW, Command::GetStatus) + .await } } @@ -286,32 +307,32 @@ where RST: OutputPin, DELAY: DelayUs, { - fn command(&mut self, spi: &mut SPI, command: Command) -> Result<(), SPI::Error> { - self.interface.cmd(spi, command) + async fn command(&mut self, spi: &mut SPI, command: Command) -> Result<(), SPI::Error> { + self.interface.cmd(spi, command).await } - fn send_data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> { - self.interface.data(spi, data) + async fn send_data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> { + self.interface.data(spi, data).await } - fn cmd_with_data( + async fn cmd_with_data( &mut self, spi: &mut SPI, command: Command, data: &[u8], ) -> Result<(), SPI::Error> { - self.interface.cmd_with_data(spi, command, data) + self.interface.cmd_with_data(spi, command, data).await } - fn send_resolution(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { + async fn send_resolution(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { let w = self.width(); let h = self.height(); - self.command(spi, Command::TconResolution)?; - self.send_data(spi, &[(w >> 8) as u8])?; - self.send_data(spi, &[w as u8])?; - self.send_data(spi, &[(h >> 8) as u8])?; - self.send_data(spi, &[h as u8]) + self.command(spi, Command::TconResolution).await?; + self.send_data(spi, &[(w >> 8) as u8]).await?; + self.send_data(spi, &[w as u8]).await?; + self.send_data(spi, &[(h >> 8) as u8]).await?; + self.send_data(spi, &[h as u8]).await } } diff --git a/src/epd7in5b_v2/mod.rs b/src/epd7in5b_v2/mod.rs index c71d030c..5d20477c 100644 --- a/src/epd7in5b_v2/mod.rs +++ b/src/epd7in5b_v2/mod.rs @@ -10,11 +10,8 @@ //! Revision V2 has been released on 2019.11, the resolution is upgraded to 800×480, from 640×384 of V1. //! The hardware and interface of V2 are compatible with V1, however, the related software should be updated. -use embedded_hal::{ - delay::DelayUs, - digital::{InputPin, OutputPin}, - spi::SpiDevice, -}; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::{delay::DelayUs, spi::SpiDevice}; use crate::color::TriColor; use crate::interface::DisplayInterface; @@ -63,28 +60,31 @@ where RST: OutputPin, DELAY: DelayUs, { - fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + async fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { // Reset the device // C driver does 200/2 original rust driver does 10/2 - self.interface.reset(delay, 200_000, 2_000); + self.interface.reset(delay, 200_000, 2_000).await; // V2 procedure as described here: // https://github.com/waveshare/e-Paper/blob/master/RaspberryPi%26JetsonNano/python/lib/waveshare_epd/epd7in5bc_V2.py // and as per specs: // https://www.waveshare.com/w/upload/6/60/7.5inch_e-Paper_V2_Specification.pdf - self.cmd_with_data(spi, Command::PowerSetting, &[0x07, 0x07, 0x3F, 0x3F])?; - self.command(spi, Command::PowerOn)?; + self.cmd_with_data(spi, Command::PowerSetting, &[0x07, 0x07, 0x3F, 0x3F]) + .await?; + self.command(spi, Command::PowerOn).await?; // C driver adds a static 100ms delay here - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; // Done, but this is also the default // 0x1F = B/W mode ? doesnt seem to work - self.cmd_with_data(spi, Command::PanelSetting, &[0x0F])?; + self.cmd_with_data(spi, Command::PanelSetting, &[0x0F]) + .await?; // Not done in C driver, this is the default - //self.cmd_with_data(spi, Command::PllControl, &[0x06])?; - self.cmd_with_data(spi, Command::TconResolution, &[0x03, 0x20, 0x01, 0xE0])?; + //self.cmd_with_data(spi, Command::PllControl, &[0x06]).await?; + self.cmd_with_data(spi, Command::TconResolution, &[0x03, 0x20, 0x01, 0xE0]) + .await?; // Documentation removed in v3 but done in v2 and works in v3 - self.cmd_with_data(spi, Command::DualSpi, &[0x00])?; + self.cmd_with_data(spi, Command::DualSpi, &[0x00]).await?; // 0x10 in BW mode (Work ?) V // 0x12 in BW mode to disable new/old thing // 0x01 -> Black border @@ -93,12 +93,15 @@ where // 0x31 -> don't touch border // the second nibble can change polarity (may be easier for default // display initialization) V - self.cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x11, 0x07])?; + self.cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x11, 0x07]) + .await?; // This is the default - self.cmd_with_data(spi, Command::TconSetting, &[0x22])?; - self.cmd_with_data(spi, Command::SpiFlashControl, &[0x00, 0x00, 0x00, 0x00])?; + self.cmd_with_data(spi, Command::TconSetting, &[0x22]) + .await?; + self.cmd_with_data(spi, Command::SpiFlashControl, &[0x00, 0x00, 0x00, 0x00]) + .await?; // Not in C driver - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; Ok(()) } } @@ -113,7 +116,7 @@ where DELAY: DelayUs, { type DisplayColor = TriColor; - fn new( + async fn new( spi: &mut SPI, busy: BUSY, dc: DC, @@ -126,45 +129,47 @@ where let mut epd = Epd7in5 { interface, color }; - epd.init(spi, delay)?; + epd.init(spi, delay).await?; Ok(epd) } - fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.init(spi, delay) + async fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.init(spi, delay).await } - fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.command(spi, Command::PowerOff)?; - self.wait_until_idle(spi, delay)?; - self.cmd_with_data(spi, Command::DeepSleep, &[0xA5])?; + async fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; + self.command(spi, Command::PowerOff).await?; + self.wait_until_idle(spi, delay).await?; + self.cmd_with_data(spi, Command::DeepSleep, &[0xA5]).await?; Ok(()) } - fn update_frame( + async fn update_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; // (B) version sends one buffer for black and one for red self.cmd_with_data( spi, Command::DataStartTransmission1, &buffer[..NUM_DISPLAY_BYTES], - )?; + ) + .await?; self.cmd_with_data( spi, Command::DataStartTransmission2, &buffer[NUM_DISPLAY_BYTES..], - )?; + ) + .await?; Ok(()) } - fn update_partial_frame( + async fn update_partial_frame( &mut self, _spi: &mut SPI, _delay: &mut DELAY, @@ -177,34 +182,38 @@ where unimplemented!() } - fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.command(spi, Command::DisplayRefresh)?; + async fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; + self.command(spi, Command::DisplayRefresh).await?; Ok(()) } - fn update_and_display_frame( + async fn update_and_display_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.update_frame(spi, buffer, delay)?; - self.command(spi, Command::DisplayRefresh)?; + self.update_frame(spi, buffer, delay).await?; + self.command(spi, Command::DisplayRefresh).await?; Ok(()) } - fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; - self.send_resolution(spi)?; + async fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.wait_until_idle(spi, delay).await?; + self.send_resolution(spi).await?; - self.command(spi, Command::DataStartTransmission1)?; - self.interface.data_x_times(spi, 0xFF, WIDTH * HEIGHT / 8)?; + self.command(spi, Command::DataStartTransmission1).await?; + self.interface + .data_x_times(spi, 0xFF, WIDTH * HEIGHT / 8) + .await?; - self.command(spi, Command::DataStartTransmission2)?; - self.interface.data_x_times(spi, 0x00, WIDTH * HEIGHT / 8)?; + self.command(spi, Command::DataStartTransmission2).await?; + self.interface + .data_x_times(spi, 0x00, WIDTH * HEIGHT / 8) + .await?; - self.command(spi, Command::DisplayRefresh)?; + self.command(spi, Command::DisplayRefresh).await?; Ok(()) } @@ -225,7 +234,7 @@ where HEIGHT } - fn set_lut( + async fn set_lut( &mut self, _spi: &mut SPI, _delay: &mut DELAY, @@ -235,9 +244,14 @@ where } /// wait - fn wait_until_idle(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + async fn wait_until_idle( + &mut self, + spi: &mut SPI, + delay: &mut DELAY, + ) -> Result<(), SPI::Error> { self.interface .wait_until_idle_with_cmd(spi, delay, IS_BUSY_LOW, Command::GetStatus) + .await } } @@ -251,7 +265,7 @@ where { /// temporary replacement for missing delay in the trait to call wait_until_idle #[allow(clippy::too_many_arguments)] - pub fn update_partial_frame2( + pub async fn update_partial_frame2( &mut self, spi: &mut SPI, buffer: &[u8], @@ -261,7 +275,7 @@ where height: u32, delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; if buffer.len() as u32 != width / 8 * height { //TODO panic or error } @@ -276,7 +290,7 @@ where let vred_lower = (y + height - 1) as u8; let pt_scan = 0x01; // Gates scan both inside and outside of the partial window. (default) - self.command(spi, Command::PartialIn)?; + self.command(spi, Command::PartialIn).await?; self.cmd_with_data( spi, Command::PartialWindow, @@ -284,44 +298,47 @@ where hrst_upper, hrst_lower, hred_upper, hred_lower, vrst_upper, vrst_lower, vred_upper, vred_lower, pt_scan, ], - )?; + ) + .await?; let half = buffer.len() / 2; - self.cmd_with_data(spi, Command::DataStartTransmission1, &buffer[..half])?; - self.cmd_with_data(spi, Command::DataStartTransmission2, &buffer[half..])?; + self.cmd_with_data(spi, Command::DataStartTransmission1, &buffer[..half]) + .await?; + self.cmd_with_data(spi, Command::DataStartTransmission2, &buffer[half..]) + .await?; - self.command(spi, Command::DisplayRefresh)?; - self.wait_until_idle(spi, delay)?; + self.command(spi, Command::DisplayRefresh).await?; + self.wait_until_idle(spi, delay).await?; - self.command(spi, Command::PartialOut)?; + self.command(spi, Command::PartialOut).await?; Ok(()) } - fn command(&mut self, spi: &mut SPI, command: Command) -> Result<(), SPI::Error> { - self.interface.cmd(spi, command) + async fn command(&mut self, spi: &mut SPI, command: Command) -> Result<(), SPI::Error> { + self.interface.cmd(spi, command).await } - fn send_data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> { - self.interface.data(spi, data) + async fn send_data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> { + self.interface.data(spi, data).await } - fn cmd_with_data( + async fn cmd_with_data( &mut self, spi: &mut SPI, command: Command, data: &[u8], ) -> Result<(), SPI::Error> { - self.interface.cmd_with_data(spi, command, data) + self.interface.cmd_with_data(spi, command, data).await } - fn send_resolution(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { + async fn send_resolution(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { let w = self.width(); let h = self.height(); - self.command(spi, Command::TconResolution)?; - self.send_data(spi, &[(w >> 8) as u8])?; - self.send_data(spi, &[w as u8])?; - self.send_data(spi, &[(h >> 8) as u8])?; - self.send_data(spi, &[h as u8]) + self.command(spi, Command::TconResolution).await?; + self.send_data(spi, &[(w >> 8) as u8]).await?; + self.send_data(spi, &[w as u8]).await?; + self.send_data(spi, &[(h >> 8) as u8]).await?; + self.send_data(spi, &[h as u8]).await } } diff --git a/src/interface.rs b/src/interface.rs index e53d9186..2470e5fe 100644 --- a/src/interface.rs +++ b/src/interface.rs @@ -1,6 +1,7 @@ use crate::traits::Command; use core::marker::PhantomData; -use embedded_hal::{delay::*, digital::*, spi::SpiDevice}; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::{delay::DelayUs, spi::SpiDevice}; /// The Connection Interface of all (?) Waveshare EPD-Devices /// @@ -49,28 +50,32 @@ where /// Basic function for sending [Commands](Command). /// /// Enables direct interaction with the device with the help of [data()](DisplayInterface::data()) - pub(crate) fn cmd(&mut self, spi: &mut SPI, command: T) -> Result<(), SPI::Error> { + pub(crate) async fn cmd( + &mut self, + spi: &mut SPI, + command: T, + ) -> Result<(), SPI::Error> { // low for commands let _ = self.dc.set_low(); // Transfer the command over spi - self.write(spi, &[command.address()]) + self.write(spi, &[command.address()]).await } /// 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()) - pub(crate) fn data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> { + pub(crate) async fn data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> { // high for data let _ = self.dc.set_high(); if SINGLE_BYTE_WRITE { for val in data.iter().copied() { // Transfer data one u8 at a time over spi - self.write(spi, &[val])?; + self.write(spi, &[val]).await?; } } else { - self.write(spi, data)?; + self.write(spi, data).await?; } Ok(()) @@ -79,20 +84,20 @@ where /// Basic function for sending [Commands](Command) and the data belonging to it. /// /// TODO: directly use ::write? cs wouldn't needed to be changed twice than - pub(crate) fn cmd_with_data( + pub(crate) async fn cmd_with_data( &mut self, spi: &mut SPI, command: T, data: &[u8], ) -> Result<(), SPI::Error> { - self.cmd(spi, command)?; - self.data(spi, data) + self.cmd(spi, command).await?; + self.data(spi, data).await } /// 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()) - pub(crate) fn data_x_times( + pub(crate) async fn data_x_times( &mut self, spi: &mut SPI, val: u8, @@ -102,23 +107,23 @@ where let _ = self.dc.set_high(); // Transfer data (u8) over spi for _ in 0..repetitions { - self.write(spi, &[val])?; + self.write(spi, &[val]).await?; } Ok(()) } // spi write helper/abstraction function - fn write(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> { + async fn write(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> { // transfer spi data // Be careful!! Linux has a default limit of 4096 bytes per spi transfer // see https://raspberrypi.stackexchange.com/questions/65595/spi-transfer-fails-with-buffer-size-greater-than-4096 if cfg!(target_os = "linux") { for data_chunk in data.chunks(4096) { - spi.write(data_chunk)?; + spi.write(data_chunk).await?; } Ok(()) } else { - spi.write(data) + spi.write(data).await } } @@ -134,7 +139,7 @@ where /// - 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, delay: &mut DELAY, is_busy_low: bool) { + pub(crate) async fn wait_until_idle(&mut self, delay: &mut DELAY, is_busy_low: bool) { while self.is_busy(is_busy_low) { // This has been removed and added many time : // - it is faster to not have it @@ -143,27 +148,27 @@ where // - delay waiting enables task switching on realtime OS // -> keep it and leave the decision to the user if self.delay_us > 0 { - delay.delay_us(self.delay_us); + delay.delay_us(self.delay_us).await; } } } /// Same as `wait_until_idle` for device needing a command to probe Busy pin - pub(crate) fn wait_until_idle_with_cmd( + pub(crate) async fn wait_until_idle_with_cmd( &mut self, spi: &mut SPI, delay: &mut DELAY, is_busy_low: bool, status_command: T, ) -> Result<(), SPI::Error> { - self.cmd(spi, status_command)?; + self.cmd(spi, status_command).await?; if self.delay_us > 0 { - delay.delay_us(self.delay_us); + delay.delay_us(self.delay_us).await; } while self.is_busy(is_busy_low) { - self.cmd(spi, status_command)?; + self.cmd(spi, status_command).await?; if self.delay_us > 0 { - delay.delay_us(self.delay_us); + delay.delay_us(self.delay_us).await; } } Ok(()) @@ -194,15 +199,15 @@ where /// The timing of keeping the reset pin low seems to be important and different per device. /// Most displays seem to require keeping it low for 10ms, but the 7in5_v2 only seems to reset /// properly with 2ms - pub(crate) fn reset(&mut self, delay: &mut DELAY, initial_delay: u32, duration: u32) { + pub(crate) async fn reset(&mut self, delay: &mut DELAY, initial_delay: u32, duration: u32) { let _ = self.rst.set_high(); - delay.delay_us(initial_delay); + delay.delay_us(initial_delay).await; let _ = self.rst.set_low(); - delay.delay_us(duration); + delay.delay_us(duration).await; let _ = self.rst.set_high(); //TODO: the upstream libraries always sleep for 200ms here // 10ms works fine with just for the 7in5_v2 but this needs to be validated for other devices - delay.delay_us(200_000); + delay.delay_us(200_000).await; } } diff --git a/src/lib.rs b/src/lib.rs index bdedf055..3174250f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,6 +62,9 @@ //! #![no_std] #![deny(missing_docs)] +#![allow(stable_features)] +#![cfg_attr(feature = "async", feature(async_fn_in_trait, impl_trait_projections))] +#![cfg_attr(feature = "async", allow(incomplete_features, async_fn_in_trait))] #[cfg(feature = "graphics")] pub mod graphics; diff --git a/src/traits.rs b/src/traits.rs index 25df34ad..d251949d 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -1,5 +1,6 @@ use core::marker::Sized; -use embedded_hal::{delay::*, digital::*, spi::SpiDevice}; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::{delay::DelayUs, spi::SpiDevice}; /// All commands need to have this trait which gives the address of the command /// which needs to be send via SPI with activated CommandsPin (Data/Command Pin in CommandMode) @@ -36,7 +37,7 @@ where /// This function calls [reset](WaveshareDisplay::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, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error>; + async fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error>; } /// Functions to interact with three color panels @@ -52,7 +53,7 @@ where /// Transmit data to the SRAM of the EPD /// /// Updates both the black and the secondary color layers - fn update_color_frame( + async fn update_color_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -63,7 +64,7 @@ where /// Update only the black/white data of the display. /// /// This must be finished by calling `update_chromatic_frame`. - fn update_achromatic_frame( + async fn update_achromatic_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -74,7 +75,7 @@ where /// /// This should be preceded by a call to `update_achromatic_frame`. /// This data takes precedence over the black/white data. - fn update_chromatic_frame( + async fn update_chromatic_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -143,7 +144,7 @@ where /// Setting it to None means a default value is used. /// /// This already initialises the device. - fn new( + async fn new( spi: &mut SPI, busy: BUSY, dc: DC, @@ -157,12 +158,12 @@ where /// Let the device enter deep-sleep mode to save power. /// /// The deep sleep mode returns to standby with a hardware reset. - fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error>; + async fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error>; /// Wakes the device up from sleep /// /// Also reintialises the device if necessary. - fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error>; + async fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error>; /// Sets the backgroundcolor for various commands like [clear_frame](WaveshareDisplay::clear_frame) fn set_background_color(&mut self, color: Self::DisplayColor); @@ -177,7 +178,7 @@ where fn height(&self) -> u32; /// Transmit a full frame to the SRAM of the EPD - fn update_frame( + async fn update_frame( &mut self, spi: &mut SPI, buffer: &[u8], @@ -190,7 +191,7 @@ where /// /// BUFFER needs to be of size: width / 8 * height ! #[allow(clippy::too_many_arguments)] - fn update_partial_frame( + async fn update_partial_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -204,10 +205,10 @@ where /// Displays the frame data from SRAM /// /// This function waits until the device isn`t busy anymore - fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error>; + async fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error>; /// Provide a combined update&display and save some time (skipping a busy check in between) - fn update_and_display_frame( + async fn update_and_display_frame( &mut self, spi: &mut SPI, buffer: &[u8], @@ -217,7 +218,7 @@ where /// Clears the frame buffer on the EPD with the declared background color /// /// The background color can be changed with [`WaveshareDisplay::set_background_color`] - fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error>; + async fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error>; /// Trait for using various Waveforms from different LUTs /// E.g. for partial refreshes @@ -227,7 +228,7 @@ where /// 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( + async fn set_lut( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -237,7 +238,8 @@ where /// Wait until the display has stopped processing data /// /// You can call this to make sure a frame is displayed before goin further - fn wait_until_idle(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error>; + async fn wait_until_idle(&mut self, spi: &mut SPI, delay: &mut DELAY) + -> Result<(), SPI::Error>; } /// Allows quick refresh support for displays that support it; lets you send both @@ -294,7 +296,7 @@ where DELAY: DelayUs, { /// Updates the old frame. - fn update_old_frame( + async fn update_old_frame( &mut self, spi: &mut SPI, buffer: &[u8], @@ -302,7 +304,7 @@ where ) -> Result<(), SPI::Error>; /// Updates the new frame. - fn update_new_frame( + async fn update_new_frame( &mut self, spi: &mut SPI, buffer: &[u8], @@ -310,10 +312,14 @@ where ) -> Result<(), SPI::Error>; /// Displays the new frame - fn display_new_frame(&mut self, spi: &mut SPI, _delay: &mut DELAY) -> Result<(), SPI::Error>; + async fn display_new_frame( + &mut self, + spi: &mut SPI, + _delay: &mut DELAY, + ) -> Result<(), SPI::Error>; /// Updates and displays the new frame. - fn update_and_display_new_frame( + async fn update_and_display_new_frame( &mut self, spi: &mut SPI, buffer: &[u8], @@ -322,7 +328,7 @@ where /// Updates the old frame for a portion of the display. #[allow(clippy::too_many_arguments)] - fn update_partial_old_frame( + async fn update_partial_old_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -335,7 +341,7 @@ where /// Updates the new frame for a portion of the display. #[allow(clippy::too_many_arguments)] - fn update_partial_new_frame( + async fn update_partial_new_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -348,7 +354,7 @@ where /// Clears the partial frame buffer on the EPD with the declared background color /// The background color can be changed with [`WaveshareDisplay::set_background_color`] - fn clear_partial_frame( + async fn clear_partial_frame( &mut self, spi: &mut SPI, delay: &mut DELAY,