diff --git a/Cargo.toml b/Cargo.toml index 55d682a7..69316d0e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ edition = "2021" [dependencies] embedded-graphics-core = { version = "0.4", optional = true } embedded-hal = "1.0.0" +embedded-hal-async = "1.0.0" bit_field = "0.10.1" [dev-dependencies] diff --git a/examples/epd1in54_no_graphics.rs b/examples/epd1in54_no_graphics.rs index 4baac378..44f08cef 100644 --- a/examples/epd1in54_no_graphics.rs +++ b/examples/epd1in54_no_graphics.rs @@ -1,6 +1,6 @@ #![deny(warnings)] -use embedded_hal::delay::DelayNs; +use embedded_hal_async::delay::DelayNs; use epd_waveshare::{epd1in54::Epd1in54, prelude::*}; use linux_embedded_hal::{ spidev::{self, SpidevOptions}, diff --git a/examples/epd2in13_v2.rs b/examples/epd2in13_v2.rs index b3cb64eb..458029b6 100644 --- a/examples/epd2in13_v2.rs +++ b/examples/epd2in13_v2.rs @@ -6,7 +6,7 @@ use embedded_graphics::{ primitives::{Circle, Line, PrimitiveStyle}, text::{Baseline, Text, TextStyleBuilder}, }; -use embedded_hal::delay::DelayNs; +use embedded_hal_async::delay::DelayNs; use epd_waveshare::{ color::*, epd2in13_v2::{Display2in13, Epd2in13}, diff --git a/examples/epd2in13bc.rs b/examples/epd2in13bc.rs index 8007acf3..eda7e740 100644 --- a/examples/epd2in13bc.rs +++ b/examples/epd2in13bc.rs @@ -6,7 +6,7 @@ use embedded_graphics::{ primitives::{Circle, Line, PrimitiveStyle}, text::{Baseline, Text, TextStyleBuilder}, }; -use embedded_hal::delay::DelayNs; +use embedded_hal_async::delay::DelayNs; use epd_waveshare::{ color::*, epd2in13bc::{Display2in13bc, Epd2in13bc}, diff --git a/examples/epd4in2.rs b/examples/epd4in2.rs index 10576124..8130a4ae 100644 --- a/examples/epd4in2.rs +++ b/examples/epd4in2.rs @@ -6,7 +6,7 @@ use embedded_graphics::{ primitives::{Circle, Line, PrimitiveStyleBuilder}, text::{Baseline, Text, TextStyleBuilder}, }; -use embedded_hal::delay::DelayNs; +use embedded_hal_async::delay::DelayNs; use epd_waveshare::{ color::*, epd4in2::{Display4in2, Epd4in2}, diff --git a/examples/epd4in2_variable_size.rs b/examples/epd4in2_variable_size.rs index 8ff8259d..5a21129c 100644 --- a/examples/epd4in2_variable_size.rs +++ b/examples/epd4in2_variable_size.rs @@ -7,7 +7,7 @@ use embedded_graphics::{ primitives::{Circle, Line, PrimitiveStyleBuilder}, text::{Baseline, Text, TextStyleBuilder}, }; -use embedded_hal::delay::DelayNs; +use embedded_hal_async::delay::DelayNs; use epd_waveshare::{ color::*, epd4in2::{self, Epd4in2}, diff --git a/src/epd1in54/mod.rs b/src/epd1in54/mod.rs index 4a4514ed..c32f95fd 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::DelayNs, digital::Wait, spi::SpiDevice}; use crate::type_a::{ command::Command, @@ -91,24 +92,26 @@ pub struct Epd1in54 { impl Epd1in54 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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(()) } } @@ -146,7 +154,7 @@ impl WaveshareDisplay for Epd1in54 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, @@ -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> { + self.interface.wait_until_idle(delay, IS_BUSY_LOW).await; Ok(()) } } @@ -297,24 +315,25 @@ where impl Epd1in54 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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)?; + 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 80bf5849..8312e3bc 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::DelayNs, digital::Wait, spi::SpiDevice}; use crate::type_a::command::Command; @@ -41,48 +42,55 @@ pub struct Epd1in54 { impl Epd1in54 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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::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?; //Initialize the lookup table with a refresh waveform - 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(()) } } @@ -91,7 +99,7 @@ impl WaveshareDisplay for Epd1in54 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, @@ -105,7 +113,7 @@ where HEIGHT } - fn new( + async fn new( spi: &mut SPI, busy: BUSY, dc: DC, @@ -121,37 +129,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 +171,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 +238,7 @@ where &self.background_color } - fn set_lut( + async fn set_lut( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -232,31 +248,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(()) } } @@ -264,24 +288,25 @@ where impl Epd1in54 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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 +315,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 08aae37c..318bc7bd 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::DelayNs, digital::Wait, spi::SpiDevice}; use crate::interface::DisplayInterface; use crate::traits::{ @@ -47,43 +48,49 @@ impl InternalWiAdditions for Epd1in54b where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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(()) } @@ -93,48 +100,52 @@ impl WaveshareThreeColorDisplay where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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(()) } } @@ -143,13 +154,13 @@ impl WaveshareDisplay for Epd1in54b where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { 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 / 8 * HEIGHT))?; + .data_x_times(spi, color, 2 * (WIDTH / 8 * HEIGHT)) + .await?; // Clear the red - self.interface.cmd(spi, Command::DataStartTransmission2)?; self.interface - .data_x_times(spi, color, WIDTH / 8 * HEIGHT)?; + .cmd(spi, Command::DataStartTransmission2) + .await?; + self.interface + .data_x_times(spi, color, WIDTH / 8 * HEIGHT) + .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(()) } } @@ -321,37 +359,37 @@ where impl Epd1in54b where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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 bbe27302..5937db11 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::DelayNs, digital::Wait, spi::SpiDevice}; use crate::interface::DisplayInterface; use crate::traits::{ @@ -44,33 +45,36 @@ impl InternalWiAdditions for Epd1in54c where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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(()) } @@ -80,42 +84,44 @@ impl WaveshareThreeColorDisplay where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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(()) } @@ -125,13 +131,13 @@ impl WaveshareDisplay for Epd1in54c where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { 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(()) } } @@ -262,45 +278,45 @@ where impl Epd1in54c where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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 5d8d4e0b..4142b1d8 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::DelayNs, - digital::{InputPin, OutputPin}, - spi::SpiDevice, -}; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::{delay::DelayNs, digital::Wait, spi::SpiDevice}; use crate::buffer_len; use crate::color::Color; @@ -84,32 +81,33 @@ impl InternalWiAdditions for Epd2in13 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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])?; + // self.cmd_with_data(spi, Command::WriteOtpSelection, &[0, 0, 0, 0, 0x40, 0, 0]).await?; // During partial update, clock/analog are not disabled between 2 // updates. 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(()) } } @@ -177,13 +181,13 @@ impl WaveshareDisplay for Epd2in13 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { 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(()) } } @@ -389,24 +407,25 @@ where impl Epd2in13 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { /// 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 9d1f0d88..7ca30f0f 100644 --- a/src/epd2in13bc/mod.rs +++ b/src/epd2in13bc/mod.rs @@ -50,7 +50,9 @@ //!# Ok(()) //!# } //!``` -use embedded_hal::{delay::*, digital::*, spi::SpiDevice}; + +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::{delay::DelayNs, digital::Wait, spi::SpiDevice}; use crate::interface::DisplayInterface; use crate::traits::{ @@ -101,40 +103,44 @@ impl InternalWiAdditions for Epd2in13bc where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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(()) } @@ -144,49 +150,53 @@ impl WaveshareThreeColorDisplay where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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(()) } } @@ -195,13 +205,13 @@ impl WaveshareDisplay for Epd2in13bc where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { type DisplayColor = TriColor; - fn new( + async fn new( spi: &mut SPI, busy: BUSY, dc: DC, @@ -214,30 +224,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 +268,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 +308,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 +361,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(()) } } @@ -344,41 +374,45 @@ where impl Epd2in13bc where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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 +423,6 @@ where Command::VcomAndDataIntervalSetting, &[border | VCOM_DATA_INTERVAL], ) + .await } } diff --git a/src/epd2in66b/mod.rs b/src/epd2in66b/mod.rs index 092fce3f..95a3aefc 100644 --- a/src/epd2in66b/mod.rs +++ b/src/epd2in66b/mod.rs @@ -166,11 +166,8 @@ //!} //!``` -use embedded_hal::{ - delay::DelayNs, - digital::{InputPin, OutputPin}, - spi::SpiDevice, -}; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::{delay::DelayNs, digital::Wait, spi::SpiDevice}; use crate::color::TriColor; use crate::interface::DisplayInterface; @@ -212,24 +209,27 @@ impl InternalWiAdditions for Epd2in66b where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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> { // We follow the sequence of the Pi-Pico hat example code. - self.hw_reset(delay)?; - self.sw_reset(spi, delay)?; - self.data_entry_mode(spi, DataEntryRow::XMinor, DataEntrySign::IncYIncX)?; - self.set_display_window(spi, 0, 0, WIDTH - 1, HEIGHT - 1)?; + self.hw_reset(delay).await?; + self.sw_reset(spi, delay).await?; + self.data_entry_mode(spi, DataEntryRow::XMinor, DataEntrySign::IncYIncX) + .await?; + self.set_display_window(spi, 0, 0, WIDTH - 1, HEIGHT - 1) + .await?; self.update_control1( spi, WriteMode::Normal, WriteMode::Normal, OutputSource::S8ToS167, - )?; - self.set_cursor(spi, 0, 0)?; + ) + .await?; + self.set_cursor(spi, 0, 0).await?; Ok(()) } @@ -239,42 +239,42 @@ impl WaveshareThreeColorDisplay where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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.set_cursor(spi, 0, 0)?; - self.interface.cmd(spi, Command::WriteBlackWhiteRAM)?; - self.interface.data(spi, black) + self.set_cursor(spi, 0, 0).await?; + self.interface.cmd(spi, Command::WriteBlackWhiteRAM).await?; + self.interface.data(spi, black).await } - fn update_chromatic_frame( + async fn update_chromatic_frame( &mut self, spi: &mut SPI, _delay: &mut DELAY, chromatic: &[u8], ) -> Result<(), SPI::Error> { - self.set_cursor(spi, 0, 0)?; - self.interface.cmd(spi, Command::WriteRedRAM)?; - self.interface.data(spi, chromatic) + self.set_cursor(spi, 0, 0).await?; + self.interface.cmd(spi, Command::WriteRedRAM).await?; + self.interface.data(spi, chromatic).await } } @@ -282,14 +282,14 @@ impl WaveshareDisplay for Epd2in66b where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { type DisplayColor = TriColor; - fn new( + async fn new( spi: &mut SPI, busy: BUSY, dc: DC, @@ -304,20 +304,22 @@ where interface: DisplayInterface::new(busy, dc, rst, delay_us), background: DEFAULT_BACKGROUND_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.interface.cmd_with_data( - spi, - Command::DeepSleepMode, - &[DeepSleep::SleepLosingRAM as u8], - ) + async fn sleep(&mut self, spi: &mut SPI, _delay: &mut DELAY) -> Result<(), SPI::Error> { + self.interface + .cmd_with_data( + spi, + Command::DeepSleepMode, + &[DeepSleep::SleepLosingRAM as u8], + ) + .await } - 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: Self::DisplayColor) { @@ -336,18 +338,19 @@ where HEIGHT } - fn update_frame( + async fn update_frame( &mut self, spi: &mut SPI, buffer: &[u8], delay: &mut DELAY, ) -> Result<(), SPI::Error> { - self.set_cursor(spi, 0, 0)?; - self.update_achromatic_frame(spi, delay, buffer)?; - self.red_pattern(spi, delay, PatW::W160, PatH::H296, StartWith::Zero) // do NOT consider background here since red overrides other colors + self.set_cursor(spi, 0, 0).await?; + self.update_achromatic_frame(spi, delay, buffer).await?; + self.red_pattern(spi, delay, PatW::W160, PatH::H296, StartWith::Zero) + .await // do NOT consider background here since red overrides other colors } - fn update_partial_frame( + async fn update_partial_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -357,38 +360,41 @@ where width: u32, height: u32, ) -> Result<(), SPI::Error> { - self.set_display_window(spi, x, y, x + width, y + height)?; - self.set_cursor(spi, x, y)?; - self.update_achromatic_frame(spi, delay, buffer)?; - self.set_display_window(spi, 0, 0, WIDTH, HEIGHT) + self.set_display_window(spi, x, y, x + width, y + height) + .await?; + self.set_cursor(spi, x, y).await?; + self.update_achromatic_frame(spi, delay, buffer).await?; + self.set_display_window(spi, 0, 0, WIDTH, HEIGHT).await } - fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.interface.cmd(spi, Command::MasterActivation)?; - self.wait_until_idle(delay) + async fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.interface.cmd(spi, Command::MasterActivation).await?; + self.wait_until_idle(delay).await } - 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 } - 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 (white, red) = match self.background { TriColor::Black => (StartWith::Zero, StartWith::Zero), TriColor::White => (StartWith::One, StartWith::Zero), TriColor::Chromatic => (StartWith::Zero, StartWith::One), }; - self.black_white_pattern(spi, delay, PatW::W160, PatH::H296, white)?; + self.black_white_pattern(spi, delay, PatW::W160, PatH::H296, white) + .await?; self.red_pattern(spi, delay, PatW::W160, PatH::H296, red) + .await } - fn set_lut( + async fn set_lut( &mut self, _spi: &mut SPI, _delay: &mut DELAY, @@ -397,8 +403,12 @@ where Ok(()) } - fn wait_until_idle(&mut self, _spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.wait_until_idle(delay) + async fn wait_until_idle( + &mut self, + _spi: &mut SPI, + delay: &mut DELAY, + ) -> Result<(), SPI::Error> { + self.wait_until_idle(delay).await } } @@ -406,25 +416,25 @@ where impl Epd2in66b where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - fn wait_until_idle(&mut self, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.interface.wait_until_idle(delay, false); + async fn wait_until_idle(&mut self, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.interface.wait_until_idle(delay, false).await; Ok(()) } - fn hw_reset(&mut self, delay: &mut DELAY) -> Result<(), SPI::Error> { + async fn hw_reset(&mut self, delay: &mut DELAY) -> Result<(), SPI::Error> { // The initial delay is taken from other code here, the 2 ms comes from the SSD1675B datasheet. - self.interface.reset(delay, 20_000, 2_000); - self.wait_until_idle(delay) + self.interface.reset(delay, 20_000, 2_000).await; + self.wait_until_idle(delay).await } - fn sw_reset(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.interface.cmd(spi, Command::Reset)?; - self.wait_until_idle(delay) + async fn sw_reset(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.interface.cmd(spi, Command::Reset).await?; + self.wait_until_idle(delay).await } - fn data_entry_mode( + async fn data_entry_mode( &mut self, spi: &mut SPI, row: DataEntryRow, @@ -432,8 +442,9 @@ where ) -> Result<(), SPI::Error> { self.interface .cmd_with_data(spi, Command::DataEntryMode, &[row as u8 | sign as u8]) + .await } - fn set_display_window( + async fn set_display_window( &mut self, spi: &mut SPI, xstart: u32, @@ -441,50 +452,57 @@ where xend: u32, yend: u32, ) -> Result<(), SPI::Error> { - self.interface.cmd_with_data( - spi, - Command::SetXAddressRange, - &[(((xstart >> 3) & 0x1f) as u8), (((xend >> 3) & 0x1f) as u8)], - )?; - self.interface.cmd_with_data( - spi, - Command::SetYAddressRange, - &[ - ((ystart & 0xff) as u8), - (((ystart >> 8) & 0x01) as u8), - ((yend & 0xff) as u8), - (((yend >> 8) & 0x01) as u8), - ], - ) + self.interface + .cmd_with_data( + spi, + Command::SetXAddressRange, + &[(((xstart >> 3) & 0x1f) as u8), (((xend >> 3) & 0x1f) as u8)], + ) + .await?; + self.interface + .cmd_with_data( + spi, + Command::SetYAddressRange, + &[ + ((ystart & 0xff) as u8), + (((ystart >> 8) & 0x01) as u8), + ((yend & 0xff) as u8), + (((yend >> 8) & 0x01) as u8), + ], + ) + .await } - fn update_control1( + + async fn update_control1( &mut self, spi: &mut SPI, red_mode: WriteMode, bw_mode: WriteMode, source: OutputSource, ) -> Result<(), SPI::Error> { - self.interface.cmd_with_data( - spi, - Command::DisplayUpdateControl1, - &[((red_mode as u8) << 4 | bw_mode as u8), (source as u8)], - ) + self.interface + .cmd_with_data( + spi, + Command::DisplayUpdateControl1, + &[((red_mode as u8) << 4 | bw_mode as u8), (source as u8)], + ) + .await } - fn set_cursor(&mut self, spi: &mut SPI, x: u32, y: u32) -> Result<(), SPI::Error> { - self.interface.cmd_with_data( - spi, - Command::SetXAddressCounter, - &[((x >> 3) & 0x1f) as u8], - )?; - self.interface.cmd_with_data( - spi, - Command::SetYAddressCounter, - &[((y & 0xff) as u8), (((y >> 8) & 0x01) as u8)], - ) + async fn set_cursor(&mut self, spi: &mut SPI, x: u32, y: u32) -> Result<(), SPI::Error> { + self.interface + .cmd_with_data(spi, Command::SetXAddressCounter, &[((x >> 3) & 0x1f) as u8]) + .await?; + self.interface + .cmd_with_data( + spi, + Command::SetYAddressCounter, + &[((y & 0xff) as u8), (((y >> 8) & 0x01) as u8)], + ) + .await } - fn black_white_pattern( + async fn black_white_pattern( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -492,14 +510,17 @@ where h: PatH, phase: StartWith, ) -> Result<(), SPI::Error> { - self.interface.cmd_with_data( - spi, - Command::BlackWhiteRAMTestPattern, - &[phase as u8 | h as u8 | w as u8], - )?; - self.wait_until_idle(delay) + self.interface + .cmd_with_data( + spi, + Command::BlackWhiteRAMTestPattern, + &[phase as u8 | h as u8 | w as u8], + ) + .await?; + self.wait_until_idle(delay).await } - fn red_pattern( + + async fn red_pattern( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -507,11 +528,13 @@ where h: PatH, phase: StartWith, ) -> Result<(), SPI::Error> { - self.interface.cmd_with_data( - spi, - Command::RedRAMTestPattern, - &[phase as u8 | h as u8 | w as u8], - )?; - self.wait_until_idle(delay) + self.interface + .cmd_with_data( + spi, + Command::RedRAMTestPattern, + &[phase as u8 | h as u8 | w as u8], + ) + .await?; + self.wait_until_idle(delay).await } } diff --git a/src/epd2in7b/command.rs b/src/epd2in7b/command.rs index e32365cf..03a57972 100644 --- a/src/epd2in7b/command.rs +++ b/src/epd2in7b/command.rs @@ -20,7 +20,7 @@ pub(crate) enum Command { /// Starting data transmission /// /// ```ignore - /// self.send_data(&[0x07, 0x07, 0x17])?; + /// self.send_data(&[0x07, 0x07, 0x17]).await?; /// ``` BoosterSoftStart = 0x06, /// After this command is transmitted, the chip would enter the deep-sleep mode to save power. diff --git a/src/epd2in7b/mod.rs b/src/epd2in7b/mod.rs index 42f25f19..32461670 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::DelayNs, digital::Wait, spi::SpiDevice}; use crate::interface::DisplayInterface; use crate::traits::{ @@ -51,63 +52,72 @@ impl InternalWiAdditions for Epd2in7b where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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(()) } } @@ -116,13 +126,13 @@ impl WaveshareDisplay for Epd2in7b where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { 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 / 8 * HEIGHT)?; + .cmd(spi, Command::DataStartTransmission2) + .await?; + self.interface + .data_x_times(spi, !self.color.get_byte_value(), WIDTH / 8 * HEIGHT) + .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 / 8 * HEIGHT)?; + .cmd(spi, Command::DataStartTransmission1) + .await?; + self.interface + .data_x_times(spi, color_value, WIDTH / 8 * HEIGHT) + .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 / 8 * HEIGHT)?; - self.interface.cmd(spi, Command::DataStop)?; + .cmd(spi, Command::DataStartTransmission2) + .await?; + self.interface + .data_x_times(spi, color_value, WIDTH / 8 * HEIGHT) + .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(()) } } @@ -277,53 +310,57 @@ impl WaveshareThreeColorDisplay where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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(()) } @@ -332,39 +369,39 @@ where impl Epd2in7b where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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 48c5bdcc..60a83b7a 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::DelayNs, digital::Wait, spi::SpiDevice}; use crate::type_a::{ command::Command, @@ -88,15 +89,15 @@ pub struct Epd2in9 { impl Epd2in9 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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 } } @@ -139,7 +146,7 @@ impl WaveshareDisplay for Epd2in9 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, @@ -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(()) } } @@ -293,20 +309,20 @@ where impl Epd2in9 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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 3a36fdf7..58725f7d 100644 --- a/src/epd2in9_v2/mod.rs +++ b/src/epd2in9_v2/mod.rs @@ -87,7 +87,8 @@ const WS_20_30: [u8; 159] = [ 0x44, 0x44, 0x0, 0x0, 0x0, 0x22, 0x17, 0x41, 0x0, 0x32, 0x36, ]; -use embedded_hal::{delay::*, digital::*, spi::SpiDevice}; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::{delay::DelayNs, digital::Wait, spi::SpiDevice}; use crate::type_a::command::Command; @@ -123,17 +124,17 @@ pub struct Epd2in9 { impl Epd2in9 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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] @@ -141,32 +142,39 @@ 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?; // set LUT by host - self.set_lut_helper(spi, delay, &WS_20_30[0..153])?; + self.set_lut_helper(spi, delay, &WS_20_30[0..153]).await?; self.interface - .cmd_with_data(spi, Command::WriteLutRegisterEnd, &WS_20_30[153..154])?; + .cmd_with_data(spi, Command::WriteLutRegisterEnd, &WS_20_30[153..154]) + .await?; self.interface - .cmd_with_data(spi, Command::GateDrivingVoltage, &WS_20_30[154..155])?; + .cmd_with_data(spi, Command::GateDrivingVoltage, &WS_20_30[154..155]) + .await?; self.interface - .cmd_with_data(spi, Command::SourceDrivingVoltage, &WS_20_30[155..158])?; + .cmd_with_data(spi, Command::SourceDrivingVoltage, &WS_20_30[155..158]) + .await?; self.interface - .cmd_with_data(spi, Command::WriteVcomRegister, &WS_20_30[158..159])?; + .cmd_with_data(spi, Command::WriteVcomRegister, &WS_20_30[158..159]) + .await?; Ok(()) } @@ -176,7 +184,7 @@ impl WaveshareDisplay for Epd2in9 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, @@ -190,7 +198,7 @@ where HEIGHT } - fn new( + async fn new( spi: &mut SPI, busy: BUSY, dc: DC, @@ -206,35 +214,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, @@ -245,48 +256,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, &[0xC7])?; - self.interface.cmd(spi, Command::MasterActivation)?; - self.wait_until_idle(spi, delay)?; + .cmd_with_data(spi, Command::DisplayUpdateControl2, &[0xC7]) + .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) { @@ -297,7 +313,7 @@ where &self.background_color } - fn set_lut( + async fn set_lut( &mut self, _spi: &mut SPI, _delay: &mut DELAY, @@ -309,8 +325,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(()) } } @@ -318,20 +338,20 @@ where impl Epd2in9 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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, @@ -344,58 +364,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(()) } } @@ -404,79 +432,90 @@ impl QuickRefresh for Epd2in9 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { /// 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, @@ -492,7 +531,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, @@ -508,7 +547,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 0f6d52b2..702d181d 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::DelayNs, digital::Wait, spi::SpiDevice}; use crate::interface::DisplayInterface; use crate::traits::{ @@ -105,40 +106,44 @@ impl InternalWiAdditions for Epd2in9bc where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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(()) } @@ -148,49 +153,53 @@ impl WaveshareThreeColorDisplay where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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(()) } } @@ -199,13 +208,13 @@ impl WaveshareDisplay for Epd2in9bc where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { 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(()) } } @@ -348,41 +377,45 @@ where impl Epd2in9bc where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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/epd2in9d/mod.rs b/src/epd2in9d/mod.rs index 95d72398..ca63613b 100644 --- a/src/epd2in9d/mod.rs +++ b/src/epd2in9d/mod.rs @@ -7,11 +7,8 @@ use core::slice::from_raw_parts; -use embedded_hal::{ - delay::DelayNs, - digital::{InputPin, OutputPin}, - spi::SpiDevice, -}; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::{delay::DelayNs, digital::Wait, spi::SpiDevice}; use crate::interface::DisplayInterface; use crate::traits::{InternalWiAdditions, RefreshLut, WaveshareDisplay}; @@ -68,29 +65,32 @@ impl InternalWiAdditions for Epd2in9d<'_, SPI, BUSY, DC, RST, DELAY> where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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; //panel setting //LUT from OTP,KW-BF KWR-AF BWROTP 0f BWOTP 1f self.interface - .cmd_with_data(spi, Command::PanelSetting, &[0x1f, 0x0D])?; + .cmd_with_data(spi, Command::PanelSetting, &[0x1f, 0x0D]) + .await?; //resolution setting self.interface - .cmd_with_data(spi, Command::ResolutionSetting, &[0x80, 0x01, 0x28])?; + .cmd_with_data(spi, Command::ResolutionSetting, &[0x80, 0x01, 0x28]) + .await?; - self.interface.cmd(spi, Command::PowerOn)?; - self.wait_until_idle(spi, delay)?; + self.interface.cmd(spi, Command::PowerOn).await?; + self.wait_until_idle(spi, delay).await?; //VCOM AND DATA INTERVAL SETTING self.interface - .cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x97])?; + .cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x97]) + .await?; Ok(()) } @@ -100,13 +100,13 @@ impl WaveshareDisplay for Epd2in9d<'_, SPI, BUSY, DC, RST, DELAY> where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { type DisplayColor = Color; - fn new( + async fn new( spi: &mut SPI, busy: BUSY, dc: DC, @@ -127,26 +127,28 @@ where is_partial_refresh, }; - 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> { self.is_partial_refresh = false; self.interface - .cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0xf7])?; - self.interface.cmd(spi, Command::PowerOff)?; - self.wait_until_idle(spi, delay)?; - delay.delay_us(100_000); + .cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0xf7]) + .await?; + self.interface.cmd(spi, Command::PowerOff).await?; + self.wait_until_idle(spi, delay).await?; + delay.delay_us(100_000).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?; Ok(()) } @@ -168,7 +170,7 @@ where // Corresponds to the Display function. // Used to write the data to be displayed to the screen SRAM. - fn update_frame( + async fn update_frame( &mut self, spi: &mut SPI, buffer: &[u8], @@ -178,20 +180,23 @@ where // Modify local refresh status if full refresh is performed. self.is_partial_refresh = false; } - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; - self.interface.cmd(spi, Command::DataStartTransmission1)?; - self.interface.data_x_times(spi, 0xFF, EPD_ARRAY)?; + self.interface + .cmd(spi, Command::DataStartTransmission1) + .await?; + self.interface.data_x_times(spi, 0xFF, EPD_ARRAY).await?; self.interface - .cmd_with_data(spi, Command::DataStartTransmission2, buffer)?; + .cmd_with_data(spi, Command::DataStartTransmission2, buffer) + .await?; self.old_data = unsafe { from_raw_parts(buffer.as_ptr(), buffer.len()) }; Ok(()) } // 这个是DisplayPart // Partial refresh write address and data - fn update_partial_frame( + async fn update_partial_frame( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -203,65 +208,74 @@ where ) -> Result<(), SPI::Error> { if !self.is_partial_refresh { // Initialize only on first call - self.set_part_reg(spi, delay)?; + self.set_part_reg(spi, delay).await?; self.is_partial_refresh = true; } - self.interface.cmd(spi, Command::PartialIn)?; + self.interface.cmd(spi, Command::PartialIn).await?; - self.interface.cmd(spi, Command::PartialWindow)?; - self.interface.data(spi, &[(x - x % 8) as u8])?; + self.interface.cmd(spi, Command::PartialWindow).await?; + self.interface.data(spi, &[(x - x % 8) as u8]).await?; self.interface - .data(spi, &[(((x - x % 8) + width - 1) - 1) as u8])?; - self.interface.data(spi, &[(y / 256) as u8])?; - self.interface.data(spi, &[(y % 256) as u8])?; + .data(spi, &[(((x - x % 8) + width - 1) - 1) as u8]) + .await?; + self.interface.data(spi, &[(y / 256) as u8]).await?; + self.interface.data(spi, &[(y % 256) as u8]).await?; self.interface - .data(spi, &[((y + height - 1) / 256) as u8])?; + .data(spi, &[((y + height - 1) / 256) as u8]) + .await?; self.interface - .data(spi, &[((y + height - 1) % 256 - 1) as u8])?; - self.interface.data(spi, &[0x28])?; + .data(spi, &[((y + height - 1) % 256 - 1) as u8]) + .await?; + self.interface.data(spi, &[0x28]).await?; self.interface - .cmd_with_data(spi, Command::DataStartTransmission1, self.old_data)?; + .cmd_with_data(spi, Command::DataStartTransmission1, self.old_data) + .await?; self.interface - .cmd_with_data(spi, Command::DataStartTransmission2, buffer)?; + .cmd_with_data(spi, Command::DataStartTransmission2, buffer) + .await?; self.old_data = unsafe { from_raw_parts(buffer.as_ptr(), buffer.len()) }; Ok(()) } /// actually is the "Turn on Display" sequence - fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { - self.interface.cmd(spi, Command::DisplayRefresh)?; - delay.delay_us(1_000); - self.wait_until_idle(spi, delay)?; + async fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.interface.cmd(spi, Command::DisplayRefresh).await?; + delay.delay_us(1_000).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.interface.cmd(spi, Command::DataStartTransmission1)?; - self.interface.data_x_times(spi, 0x00, EPD_ARRAY)?; + async fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.interface + .cmd(spi, Command::DataStartTransmission1) + .await?; + self.interface.data_x_times(spi, 0x00, EPD_ARRAY).await?; - self.interface.cmd(spi, Command::DataStartTransmission2)?; - self.interface.data_x_times(spi, 0xFF, EPD_ARRAY)?; + self.interface + .cmd(spi, Command::DataStartTransmission2) + .await?; + self.interface.data_x_times(spi, 0xFF, EPD_ARRAY).await?; - self.display_frame(spi, delay)?; + self.display_frame(spi, delay).await?; Ok(()) } - fn set_lut( + async fn set_lut( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -272,13 +286,18 @@ where } self.set_lut_helper( spi, delay, &LUT_VCOM1, &LUT_WW1, &LUT_BW1, &LUT_WB1, &LUT_BB1, - )?; + ) + .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(()) } } @@ -286,7 +305,7 @@ where impl Epd2in9d<'_, SPI, BUSY, DC, RST, DELAY> where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, @@ -303,11 +322,11 @@ where // // panel setting // // LUT from OTP,KW-BF KWR-AF BWROTP 0f BWOTP 1f // self.interface - // .cmd_with_data(spi, Command::PanelSetting, &[0x1f])?; + // .cmd_with_data(spi, Command::PanelSetting, &[0x1f]).await?; // // resolution setting // self.interface - // .cmd_with_data(spi, Command::ResolutionSetting, &[0x80, 0x01, 0x28])?; + // .cmd_with_data(spi, Command::ResolutionSetting, &[0x80, 0x01, 0x28]).await?; // // VCOM AND DATA INTERVAL SETTING // self.interface @@ -315,42 +334,45 @@ where // Ok(()) // } - fn set_part_reg(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + async fn set_part_reg(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { // Reset the EPD driver circuit //TODO: 这里在微雪的例程中反复刷新了3次,后面有显示问题再进行修改 - self.interface.reset(delay, 10_000, 2_000); + self.interface.reset(delay, 10_000, 2_000).await; // Power settings //TODO: The data in the document is [0x03,0x00,0x2b,0x2b,0x09]. - self.interface.cmd_with_data( - spi, - Command::PowerSetting, - &[0x03, 0x00, 0x2b, 0x2b, 0x03], - )?; + self.interface + .cmd_with_data(spi, Command::PowerSetting, &[0x03, 0x00, 0x2b, 0x2b, 0x03]) + .await?; // Soft start self.interface - .cmd_with_data(spi, Command::BoosterSoftStart, &[0x17, 0x17, 0x17])?; + .cmd_with_data(spi, Command::BoosterSoftStart, &[0x17, 0x17, 0x17]) + .await?; // Panel settings self.interface - .cmd_with_data(spi, Command::PanelSetting, &[0xbf, 0x0D])?; + .cmd_with_data(spi, Command::PanelSetting, &[0xbf, 0x0D]) + .await?; // Setting the refresh rate // 3a 100HZ | 29 150Hz | 39 200HZ | 31 171HZ // 3a is used in the example self.interface - .cmd_with_data(spi, Command::PllControl, &[0x3C])?; + .cmd_with_data(spi, Command::PllControl, &[0x3C]) + .await?; // Resolution Settings self.interface - .cmd_with_data(spi, Command::ResolutionSetting, &[0x80, 0x01, 0x28])?; + .cmd_with_data(spi, Command::ResolutionSetting, &[0x80, 0x01, 0x28]) + .await?; // vcom_DC settings self.interface - .cmd_with_data(spi, Command::VcmDcSetting, &[0x12])?; + .cmd_with_data(spi, Command::VcmDcSetting, &[0x12]) + .await?; - self.set_lut(spi, delay, None)?; + self.set_lut(spi, delay, None).await?; // Power on // self.interface.cmd_with_data( @@ -358,21 +380,21 @@ where // Command::PowerOn, // &[0x04], // ); - self.interface.cmd(spi, Command::PowerOn)?; + self.interface.cmd(spi, Command::PowerOn).await?; // Get the BUSY level, high to continue, low to wait for the screen to respond. //TODO: This is the recommended step in the documentation, but I've ignored it since I've seen other screens that don't wait. - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; // vcom and data interval settings // self.interface - // .cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x97])?; + // .cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x97]).await?; Ok(()) } #[allow(clippy::too_many_arguments)] - fn set_lut_helper( + async fn set_lut_helper( &mut self, spi: &mut SPI, delay: &mut DELAY, @@ -385,23 +407,28 @@ where let _ = delay; // LUT VCOM self.interface - .cmd_with_data(spi, Command::LutForVcom, lut_vcom)?; + .cmd_with_data(spi, Command::LutForVcom, lut_vcom) + .await?; // LUT WHITE to WHITE self.interface - .cmd_with_data(spi, Command::LutWhiteToWhite, lut_ww)?; + .cmd_with_data(spi, Command::LutWhiteToWhite, lut_ww) + .await?; // LUT BLACK to WHITE self.interface - .cmd_with_data(spi, Command::LutBlackToWhite, lut_bw)?; + .cmd_with_data(spi, Command::LutBlackToWhite, lut_bw) + .await?; // LUT WHITE to BLACK self.interface - .cmd_with_data(spi, Command::LutWhiteToBlack, lut_wb)?; + .cmd_with_data(spi, Command::LutWhiteToBlack, lut_wb) + .await?; // LUT BLACK to BLACK self.interface - .cmd_with_data(spi, Command::LutBlackToBlack, lut_bb)?; + .cmd_with_data(spi, Command::LutBlackToBlack, lut_bb) + .await?; Ok(()) } } diff --git a/src/epd3in7/mod.rs b/src/epd3in7/mod.rs index c01c49fa..1e616603 100644 --- a/src/epd3in7/mod.rs +++ b/src/epd3in7/mod.rs @@ -2,11 +2,9 @@ //! //! //! Build with the help of documentation/code from [Waveshare](https://www.waveshare.com/wiki/3.7inch_e-Paper_HAT), -use embedded_hal::{ - delay::DelayNs, - digital::{InputPin, OutputPin}, - spi::SpiDevice, -}; + +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::{delay::DelayNs, digital::Wait, spi::SpiDevice}; pub(crate) mod command; mod constants; @@ -54,71 +52,89 @@ impl InternalWiAdditions for EPD3in7 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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]) + .await?; self.interface - .cmd_with_data(spi, Command::GateVoltage, &[0x00])?; + .cmd_with_data(spi, Command::GateVoltageSource, &[0x41, 0xA8, 0x32]) + .await?; + self.interface - .cmd_with_data(spi, Command::GateVoltageSource, &[0x41, 0xA8, 0x32])?; + .cmd_with_data(spi, Command::DataEntrySequence, &[0x03]) + .await?; self.interface - .cmd_with_data(spi, Command::DataEntrySequence, &[0x03])?; + .cmd_with_data(spi, Command::BorderWaveformControl, &[0x03]) + .await?; self.interface - .cmd_with_data(spi, Command::BorderWaveformControl, &[0x03])?; + .cmd_with_data( + spi, + Command::BoosterSoftStartControl, + &[0xAE, 0xC7, 0xC3, 0xC0, 0xC0], + ) + .await?; - self.interface.cmd_with_data( - spi, - Command::BoosterSoftStartControl, - &[0xAE, 0xC7, 0xC3, 0xC0, 0xC0], - )?; + 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(()) } } @@ -127,14 +143,14 @@ impl WaveshareDisplay for EPD3in7 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { type DisplayColor = Color; - fn new( + async fn new( spi: &mut SPI, busy: BUSY, dc: DC, @@ -147,19 +163,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 +198,7 @@ where HEIGHT } - fn update_frame( + async fn update_frame( &mut self, spi: &mut SPI, buffer: &[u8], @@ -187,18 +206,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 +233,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 +283,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 a1c2a0d4..861f2aa3 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::DelayNs, digital::Wait, spi::SpiDevice}; use crate::interface::DisplayInterface; use crate::traits::{InternalWiAdditions, QuickRefresh, RefreshLut, WaveshareDisplay}; @@ -98,52 +99,55 @@ impl InternalWiAdditions for Epd4in2 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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(()) } } @@ -152,13 +156,13 @@ impl WaveshareDisplay for Epd4in2 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { 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(()) } } @@ -351,41 +376,41 @@ where impl Epd4in2 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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(()) } @@ -446,65 +477,73 @@ impl QuickRefresh for Epd4in2 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { /// 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.wait_until_idle(spi, delay).await?; // self.send_resolution(spi)?; - 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 1a70b78a..35736f42 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::DelayNs, - digital::{InputPin, OutputPin}, - spi::SpiDevice, -}; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::{delay::DelayNs, digital::Wait, spi::SpiDevice}; use crate::color::OctColor; use crate::interface::DisplayInterface; @@ -52,30 +49,37 @@ impl InternalWiAdditions for Epd5in65f where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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(()) } } @@ -84,13 +88,13 @@ impl WaveshareDisplay for Epd5in65f where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { 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(()) } } @@ -210,45 +221,46 @@ where impl Epd5in65f where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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/epd5in83_v2/mod.rs b/src/epd5in83_v2/mod.rs index 58909b2c..f6ec07fe 100644 --- a/src/epd5in83_v2/mod.rs +++ b/src/epd5in83_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_5in83_V2.c) //! - [Waveshare Python driver](https://github.com/waveshare/e-Paper/blob/master/RaspberryPi_JetsonNano/python/lib/waveshare_epd/epd5in83_V2.py) -use embedded_hal::{ - delay::DelayNs, - digital::{InputPin, OutputPin}, - spi::SpiDevice, -}; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::{delay::DelayNs, digital::Wait, spi::SpiDevice}; use crate::color::Color; use crate::interface::DisplayInterface; @@ -54,39 +51,43 @@ impl InternalWiAdditions for Epd5in83 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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, 2000, 50); + self.interface.reset(delay, 2000, 50).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: BWOTP - self.cmd_with_data(spi, Command::PanelSetting, &[0x1F])?; + self.cmd_with_data(spi, Command::PanelSetting, &[0x1F]) + .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, &[0x10, 0x07])?; + self.cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x10, 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(()) } } @@ -95,13 +96,13 @@ impl WaveshareDisplay for Epd5in83 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { type DisplayColor = Color; - fn new( + async fn new( spi: &mut SPI, busy: BUSY, dc: DC, @@ -114,21 +115,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) { @@ -147,25 +148,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, @@ -178,36 +183,40 @@ 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?; - 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, @@ -216,8 +225,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(()) } } @@ -225,37 +238,37 @@ where impl Epd5in83 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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/epd5in83b_v2/mod.rs b/src/epd5in83b_v2/mod.rs index 625b1e7c..06ac774b 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::DelayNs, - digital::{InputPin, OutputPin}, - spi::SpiDevice, -}; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::{delay::DelayNs, digital::Wait, spi::SpiDevice}; use crate::color::Color; use crate::interface::DisplayInterface; @@ -54,42 +51,47 @@ impl InternalWiAdditions for Epd5in83 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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(()) } } @@ -98,42 +100,44 @@ impl WaveshareThreeColorDisplay where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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(()) } } @@ -142,13 +146,13 @@ impl WaveshareDisplay for Epd5in83 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { 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(()) } } @@ -305,37 +321,37 @@ where impl Epd5in83 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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 121b780d..b6a0b094 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::DelayNs, - digital::{InputPin, OutputPin}, - spi::SpiDevice, -}; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::{delay::DelayNs, digital::Wait, spi::SpiDevice}; use crate::color::Color; use crate::interface::DisplayInterface; @@ -52,53 +49,61 @@ impl InternalWiAdditions for Epd7in5 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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(()) } } @@ -107,13 +112,13 @@ impl WaveshareDisplay for Epd7in5 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { 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(()) } } @@ -240,37 +250,37 @@ where impl Epd7in5 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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 f78df1f2..f449a9ef 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::DelayNs, - digital::{InputPin, OutputPin}, - spi::SpiDevice, -}; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::{delay::DelayNs, digital::Wait, spi::SpiDevice}; use crate::color::Color; use crate::interface::DisplayInterface; @@ -55,49 +52,60 @@ impl InternalWiAdditions for Epd7in5 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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(()) } @@ -107,13 +115,13 @@ impl WaveshareDisplay for Epd7in5 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { 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 / 8 * HEIGHT; 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(()) } } @@ -237,22 +254,22 @@ where impl Epd7in5 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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 7f09a253..8f0e8021 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::DelayNs, - digital::{InputPin, OutputPin}, - spi::SpiDevice, -}; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::{delay::DelayNs, digital::Wait, spi::SpiDevice}; use crate::color::Color; use crate::interface::DisplayInterface; @@ -56,31 +53,38 @@ impl InternalWiAdditions for Epd7in5 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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(()) } } @@ -89,13 +93,13 @@ impl WaveshareDisplay for Epd7in5 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { 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 / 8 * HEIGHT)?; + self.command(spi, Command::DataStartTransmission1).await?; + self.interface + .data_x_times(spi, 0x00, WIDTH / 8 * HEIGHT) + .await?; - self.command(spi, Command::DataStartTransmission2)?; - self.interface.data_x_times(spi, 0x00, WIDTH / 8 * HEIGHT)?; + self.command(spi, Command::DataStartTransmission2).await?; + self.interface + .data_x_times(spi, 0x00, WIDTH / 8 * HEIGHT) + .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,46 +214,51 @@ 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 } } impl Epd7in5 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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 708dd452..baa7da01 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::DelayNs, - digital::{InputPin, OutputPin}, - spi::SpiDevice, -}; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::{delay::DelayNs, digital::Wait, spi::SpiDevice}; use crate::color::TriColor; use crate::interface::DisplayInterface; @@ -61,33 +58,36 @@ impl InternalWiAdditions for Epd7in5 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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 @@ -96,12 +96,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(()) } } @@ -110,51 +113,55 @@ impl WaveshareThreeColorDisplay where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { - 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::DataStop)?; + self.interface + .cmd(spi, Command::DataStartTransmission1) + .await?; + self.interface.data(spi, black).await?; + self.interface.cmd(spi, Command::DataStop).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::DataStop)?; + self.interface + .cmd(spi, Command::DataStartTransmission2) + .await?; + self.interface.data(spi, chromatic).await?; + self.interface.cmd(spi, Command::DataStop).await?; - self.wait_until_idle(spi, delay)?; + self.wait_until_idle(spi, delay).await?; Ok(()) } } @@ -163,13 +170,13 @@ impl WaveshareDisplay for Epd7in5 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { type DisplayColor = TriColor; - fn new( + async fn new( spi: &mut SPI, busy: BUSY, dc: DC, @@ -182,46 +189,48 @@ 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_BITS], - )?; + ) + .await?; self.cmd_with_data( spi, Command::DataStartTransmission2, &buffer[NUM_DISPLAY_BITS..], - )?; - self.interface.cmd(spi, Command::DataStop)?; + ) + .await?; + 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, @@ -234,36 +243,40 @@ 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 / 8 * HEIGHT)?; + self.command(spi, Command::DataStartTransmission1).await?; + self.interface + .data_x_times(spi, 0xFF, WIDTH / 8 * HEIGHT) + .await?; - self.command(spi, Command::DataStartTransmission2)?; - self.interface.data_x_times(spi, 0x00, WIDTH / 8 * HEIGHT)?; + self.command(spi, Command::DataStartTransmission2).await?; + self.interface + .data_x_times(spi, 0x00, WIDTH / 8 * HEIGHT) + .await?; - self.interface.cmd(spi, Command::DataStop)?; + self.interface.cmd(spi, Command::DataStop).await?; - self.command(spi, Command::DisplayRefresh)?; + self.command(spi, Command::DisplayRefresh).await?; Ok(()) } @@ -284,7 +297,7 @@ where HEIGHT } - fn set_lut( + async fn set_lut( &mut self, _spi: &mut SPI, _delay: &mut DELAY, @@ -294,23 +307,28 @@ 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 } } impl Epd7in5 where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { /// 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], @@ -320,7 +338,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 } @@ -335,7 +353,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, @@ -343,44 +361,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 f3a9a3d7..91c06880 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::DelayNs, digital::Wait, spi::SpiDevice}; /// The Connection Interface of all (?) Waveshare EPD-Devices /// @@ -25,7 +26,7 @@ impl DisplayInterface where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, @@ -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,8 +139,15 @@ 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) { - while self.is_busy(is_busy_low) { + pub(crate) async fn wait_until_idle(&mut self, delay: &mut DELAY, is_busy_low: bool) { + let is_err: bool = if is_busy_low { + self.busy.wait_for_high().await + } else { + self.busy.wait_for_low().await + } + .is_err(); + + while is_err && self.is_busy(is_busy_low) { // This has been removed and added many time : // - it is faster to not have it // - it is complicated to pass the delay everywhere all the time @@ -143,27 +155,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 +206,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 fc1d392d..145a06b8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,6 +62,7 @@ //! #![no_std] #![deny(missing_docs)] +#![allow(async_fn_in_trait)] // https://github.com/rust-embedded/embedded-hal/pull/515#issuecomment-1763525962 #[cfg(feature = "graphics")] pub mod graphics; diff --git a/src/traits.rs b/src/traits.rs index b1f3f731..248bb085 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::DelayNs, digital::Wait, 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) @@ -21,7 +22,7 @@ pub enum RefreshLut { pub(crate) trait InternalWiAdditions where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, @@ -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 @@ -44,7 +45,7 @@ pub trait WaveshareThreeColorDisplay: WaveshareDisplay where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, @@ -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, @@ -129,7 +130,7 @@ where pub trait WaveshareDisplay where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, @@ -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 @@ -288,13 +290,13 @@ where pub trait QuickRefresh where SPI: SpiDevice, - BUSY: InputPin, + BUSY: Wait + InputPin, DC: OutputPin, RST: OutputPin, DELAY: DelayNs, { /// 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,