Skip to content

Commit

Permalink
Support configuration of timeouts and buffer size
Browse files Browse the repository at this point in the history
  • Loading branch information
pbert519 committed Jun 19, 2024
1 parent 62fa975 commit 6c27bb4
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 55 deletions.
7 changes: 2 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,12 @@ This driver can be used with the embedded graphics trait, currently only suppori
- Support display engine fill area
- Support display engine 1 bit per pixel mode
- Support static buffer allocations
- Make max buffer size configurable (default = 1kByte)
- Make gpio busy timeout configurable (default = 10s)
- Make lut timeout configurable (default = 10s)


## Changelog

### 0.4.0
- **Public API** `new` expects a `Config` parameter to set timeout and buffer size. Default is implemented with timeouts of 15s and buffer size is 1024 Bytes.
- Buffer data type changed from u16 to u8
- **Public API**: `load_image_area`, `load_image`, and `memory_burst_write` functions are now using u8 as buffer type
- Memory usage is reduced by half (1kByte max. instead of 2kByte)
- **Behavior** Calling `init` no longer clears the eink display. Instead call `reset` directly.
- **Behavior** Calling `init` no longer clears the eink display. Instead call `reset` directly.
3 changes: 2 additions & 1 deletion examples/esp32/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use esp_idf_hal::{delay::Ets, gpio::PinDriver, prelude::*, spi::*};
use esp_idf_sys as _; // If using the `binstart` feature of `esp-idf-sys`, always keep this module imported
use it8951::{interface::*, *};
use embedded_graphics::{prelude::*, primitives::{Rectangle, PrimitiveStyle}, pixelcolor::Gray4};
use it8951::Config;

fn main() -> ! {
// Bind the log crate to the ESP Logging facilities
Expand Down Expand Up @@ -33,7 +34,7 @@ fn main() -> ! {
reset,
Ets,
);
let mut epd = IT8951::new(display_interface).init(1605).unwrap();
let mut epd = IT8951::new(display_interface, Config::default()).init(1605).unwrap();

log::info!("Initialized display: {:?}", epd.get_dev_info());

Expand Down
3 changes: 2 additions & 1 deletion examples/test_eink.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use it8951::Config;
use linux_embedded_hal::gpio_cdev::{Chip, LineRequestFlags};
use linux_embedded_hal::spidev::{SpiModeFlags, SpidevOptions};
use linux_embedded_hal::{CdevPin, Delay, SpidevDevice};
Expand Down Expand Up @@ -34,7 +35,7 @@ fn main() -> Result<(), Box<dyn Error>> {
let busy = CdevPin::new(busy_input_handle)?;

let driver = it8951::interface::IT8951SPIInterface::new(spi, busy, rst, Delay);
let mut epd = it8951::IT8951::new(driver).init(1670).unwrap();
let mut epd = it8951::IT8951::new(driver, Config::default()).init(1670).unwrap();

println!(
"Reset and initalized E-Ink Display: \n\r {:?}",
Expand Down
29 changes: 12 additions & 17 deletions src/area_serializer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,7 @@ pub struct AreaSerializer {
}

impl AreaSerializer {
pub fn new(area: Rectangle, color: Gray4) -> Self {
let max_entries: usize = 1024; // 1 KByte

Self::with_buffer_size(area, color, max_entries)
}
pub fn with_buffer_size(area: Rectangle, color: Gray4, buffer_size: usize) -> Self {
pub fn new(area: Rectangle, color: Gray4, buffer_size: usize) -> Self {
let raw_color = color.luma();
let data_entry = raw_color << 4 | raw_color;

Expand Down Expand Up @@ -98,7 +93,7 @@ mod tests {
height: 1,
},
};
let area_s = AreaSerializer::new(area.intersection(&BOUNDING_BOX_DEFAULT), Gray4::new(0xA));
let area_s = AreaSerializer::new(area.intersection(&BOUNDING_BOX_DEFAULT), Gray4::new(0xA), 1024);
let mut s = AreaSerializerIterator::new(&area_s);
assert_eq!(
s.next(),
Expand All @@ -125,7 +120,7 @@ mod tests {
height: 1,
},
};
let area_s = AreaSerializer::new(area.intersection(&BOUNDING_BOX_DEFAULT), Gray4::new(0xA));
let area_s = AreaSerializer::new(area.intersection(&BOUNDING_BOX_DEFAULT), Gray4::new(0xA), 1024);
let mut s = AreaSerializerIterator::new(&area_s);
assert_eq!(
s.next(),
Expand All @@ -151,7 +146,7 @@ mod tests {
height: 1,
},
};
let area_s = AreaSerializer::new(area.intersection(&BOUNDING_BOX_DEFAULT), Gray4::new(0xA));
let area_s = AreaSerializer::new(area.intersection(&BOUNDING_BOX_DEFAULT), Gray4::new(0xA), 1024);
let mut s = AreaSerializerIterator::new(&area_s);
assert_eq!(
s.next(),
Expand All @@ -177,7 +172,7 @@ mod tests {
height: 1,
},
};
let area_s = AreaSerializer::new(area.intersection(&BOUNDING_BOX_DEFAULT), Gray4::new(0xA));
let area_s = AreaSerializer::new(area.intersection(&BOUNDING_BOX_DEFAULT), Gray4::new(0xA), 1024);
let mut s = AreaSerializerIterator::new(&area_s);
assert_eq!(
s.next(),
Expand All @@ -204,7 +199,7 @@ mod tests {
height: 1,
},
};
let area_s = AreaSerializer::new(area.intersection(&BOUNDING_BOX_DEFAULT), Gray4::new(0xA));
let area_s = AreaSerializer::new(area.intersection(&BOUNDING_BOX_DEFAULT), Gray4::new(0xA), 1024);
let mut s = AreaSerializerIterator::new(&area_s);

assert_eq!(
Expand Down Expand Up @@ -232,7 +227,7 @@ mod tests {
height: 1,
},
};
let area_s = AreaSerializer::new(area.intersection(&BOUNDING_BOX_DEFAULT), Gray4::new(0xA));
let area_s = AreaSerializer::new(area.intersection(&BOUNDING_BOX_DEFAULT), Gray4::new(0xA), 1024);
let mut s = AreaSerializerIterator::new(&area_s);
assert_eq!(
s.next(),
Expand All @@ -259,7 +254,7 @@ mod tests {
height: 2,
},
};
let area_s = AreaSerializer::with_buffer_size(
let area_s = AreaSerializer::new(
area.intersection(&BOUNDING_BOX_DEFAULT),
Gray4::new(0xA),
2,
Expand Down Expand Up @@ -302,7 +297,7 @@ mod tests {
height: 2,
},
};
let area_s = AreaSerializer::with_buffer_size(
let area_s = AreaSerializer::new(
area.intersection(&BOUNDING_BOX_DEFAULT),
Gray4::new(0xA),
4,
Expand Down Expand Up @@ -345,7 +340,7 @@ mod tests {
height: 2,
},
};
let area_s = AreaSerializer::new(area.intersection(&BOUNDING_BOX_DEFAULT), Gray4::new(0xA));
let area_s = AreaSerializer::new(area.intersection(&BOUNDING_BOX_DEFAULT), Gray4::new(0xA), 1024);
let mut s = AreaSerializerIterator::new(&area_s);
assert_eq!(
s.next(),
Expand All @@ -372,7 +367,7 @@ mod tests {
height: 2,
},
};
let area_s = AreaSerializer::new(area.intersection(&BOUNDING_BOX_DEFAULT), Gray4::new(0xA));
let area_s = AreaSerializer::new(area.intersection(&BOUNDING_BOX_DEFAULT), Gray4::new(0xA), 1024);
let mut s = AreaSerializerIterator::new(&area_s);
assert_eq!(
s.next(),
Expand All @@ -399,7 +394,7 @@ mod tests {
height: 2,
},
};
let area_s = AreaSerializer::new(area.intersection(&BOUNDING_BOX_DEFAULT), Gray4::new(0xA));
let area_s = AreaSerializer::new(area.intersection(&BOUNDING_BOX_DEFAULT), Gray4::new(0xA), 1024);
let mut s = AreaSerializerIterator::new(&area_s);
assert_eq!(
s.next(),
Expand Down
10 changes: 10 additions & 0 deletions src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ pub enum Error {
/// Trait to describe the interface with the controller
/// The controller supports different hardware interfaces like i2c, usb, spi and i80
pub trait IT8951Interface {
/// set wait timeout
/// internally used by the library
fn set_busy_timeout(&mut self, timeout: core::time::Duration);

/// active wait while the controller is busy and no new transactions should be issued
fn wait_while_busy(&mut self) -> Result<(), Error>;

Expand Down Expand Up @@ -64,6 +68,7 @@ pub struct IT8951SPIInterface<SPI, BUSY, RST, DELAY> {
busy: BUSY,
rst: RST,
delay: DELAY,
timeout: core::time::Duration
}

impl<SPI, BUSY, RST, DELAY> IT8951SPIInterface<SPI, BUSY, RST, DELAY>
Expand All @@ -85,6 +90,7 @@ where
busy,
rst,
delay,
timeout: core::time::Duration::default()
}
}
}
Expand All @@ -96,6 +102,10 @@ where
RST: OutputPin,
DELAY: DelayNs,
{
fn set_busy_timeout(&mut self, timeout: core::time::Duration) {
self.timeout = timeout
}

fn wait_while_busy(&mut self) -> Result<(), Error> {
let mut counter = 0u64;
while self.busy.is_low().map_err(|_| Error::GPIOError)? {
Expand Down
51 changes: 46 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,29 @@ impl From<interface::Error> for Error {
}
}

/// Driver configuration
pub struct Config {
/// Timeout for the internal display engine
pub timeout_display_engine: core::time::Duration,
/// Timeout for the busy pin
pub timeout_interface: core::time::Duration,
/// Max buffer size in bytes for staging buffers
/// The buffer should be large enough to at least contain the pixels of a complete row
/// The buffer must be aligned to u16
/// The used IT8951 interface must support to write a complete buffer at once
pub max_buffer_size: usize,
}

impl Default for Config {
fn default() -> Self {
Self {
timeout_display_engine: core::time::Duration::from_secs(15),
timeout_interface: core::time::Duration::from_secs(15),
max_buffer_size: 1024,
}
}
}

/// Device Info Struct
/// Describes the connected display
#[derive(Debug, Clone)]
Expand Down Expand Up @@ -103,16 +126,19 @@ pub struct IT8951<IT8951Interface, State> {
interface: IT8951Interface,
dev_info: Option<DevInfo>,
marker: core::marker::PhantomData<State>,
config: Config,
}

impl<IT8951Interface: interface::IT8951Interface> IT8951<IT8951Interface, Off> {
/// Creates a new controller driver object
/// Call init afterwards to initalize the controller
pub fn new(interface: IT8951Interface) -> Self {
pub fn new(mut interface: IT8951Interface, config: Config) -> Self {
interface.set_busy_timeout(config.timeout_interface);
IT8951 {
interface,
dev_info: None,
marker: PhantomData {},
config,
}
}

Expand All @@ -126,6 +152,7 @@ impl<IT8951Interface: interface::IT8951Interface> IT8951<IT8951Interface, Off> {
interface: self.interface,
dev_info: self.dev_info,
marker: PhantomData {},
config: self.config,
}
.sys_run()?;

Expand All @@ -145,11 +172,17 @@ impl<IT8951Interface: interface::IT8951Interface> IT8951<IT8951Interface, Off> {

/// Create a new Driver for are already active and initalized driver
/// This can be usefull if the device was still powered on, but the uC restarts.
pub fn attach(interface: IT8951Interface) -> Result<IT8951<IT8951Interface, Run>, Error> {
pub fn attach(
mut interface: IT8951Interface,
config: Config,
) -> Result<IT8951<IT8951Interface, Run>, Error> {
interface.set_busy_timeout(config.timeout_interface);

let mut it8951 = IT8951 {
interface,
dev_info: None,
marker: PhantomData {},
config,
}
.sys_run()?;

Expand Down Expand Up @@ -358,9 +391,10 @@ impl<IT8951Interface: interface::IT8951Interface> IT8951<IT8951Interface, Run> {
// misc ------------------------------------------------------------------------------------------------

fn wait_for_display_ready(&mut self) -> Result<(), Error> {
let timeout = self.config.timeout_display_engine.as_micros() as u64;
let mut counter = 0u64;
while 0 != self.read_register(register::LUTAFSR)? {
if counter > 10_000_000u64 {
if counter > timeout {
return Err(Error::DisplayEngineTimeout);
}
counter += 1;
Expand All @@ -377,6 +411,7 @@ impl<IT8951Interface: interface::IT8951Interface> IT8951<IT8951Interface, Run> {
interface: self.interface,
dev_info: self.dev_info,
marker: PhantomData {},
config: self.config,
})
}

Expand All @@ -388,6 +423,7 @@ impl<IT8951Interface: interface::IT8951Interface> IT8951<IT8951Interface, Run> {
interface: self.interface,
dev_info: self.dev_info,
marker: PhantomData {},
config: self.config,
})
}

Expand Down Expand Up @@ -462,6 +498,7 @@ impl<IT8951Interface: interface::IT8951Interface> IT8951<IT8951Interface, PowerD
interface: self.interface,
dev_info: self.dev_info,
marker: PhantomData {},
config: self.config,
})
}
}
Expand Down Expand Up @@ -491,7 +528,7 @@ impl<IT8951Interface: interface::IT8951Interface> DrawTarget for IT8951<IT8951In
}

fn fill_solid(&mut self, area: &Rectangle, color: Self::Color) -> Result<(), Self::Error> {
let a = AreaSerializer::new(*area, color);
let a = AreaSerializer::new(*area, color, self.config.max_buffer_size);
let area_iter = AreaSerializerIterator::new(&a);

for (area_img_info, buffer) in area_iter {
Expand All @@ -512,7 +549,11 @@ impl<IT8951Interface: interface::IT8951Interface> DrawTarget for IT8951<IT8951In
{
let iter = convert_color_to_pixel_iterator(*area, self.bounding_box(), colors.into_iter());

let pixel = PixelSerializer::new(area.intersection(&self.bounding_box()), iter);
let pixel = PixelSerializer::new(
area.intersection(&self.bounding_box()),
iter,
self.config.max_buffer_size,
);

for (area_img_info, buffer) in pixel {
let dev_info = self.get_dev_info();
Expand Down
Loading

0 comments on commit 6c27bb4

Please sign in to comment.