Skip to main content

Crate epdsi

Crate epdsi 

Source
Expand description

§epdsi — E-Paper Display Serial Interface Framework

A no_std, embedded-hal 1.0 compatible driver framework for Electronic Paper Displays (EPDs), covering seven driver ICs and ten panels behind one API.

Most EPD crates bind one driver IC to one panel. epdsi separates the two, so adding a panel to an existing controller is a single new file, and adding a controller does not disturb the panels already supported.

§Architecture

Four pieces compose into a driver:

  • EpdPanel — a zero-sized type holding static physical facts about one panel: WIDTH, HEIGHT, COLOR_MODE, plus optional vcom, custom_lut and gate_voltage overrides. See panels.
  • EpdController — the driver IC’s command and register logic: init sequence, window and cursor addressing, frame writes, refresh, sleep. See controllers.
  • SpiBusWrapper — the physical transport, wrapping an embedded-hal SpiDevice plus DC, RST and BUSY pins. See bus. Panels needing OTP register reads over a bit-banged 3-wire link use Spi3Bus instead (see bus3).
  • EpdDriver — the orchestrator, built with EpdBuilder, exposing the public API: init, set_window, write_frame, clear_frame, refresh, sleep.

Colour is unified across all panels by ColorMode and ColorChannel, so multi-buffer COGs (Pervasive’s separate black/white and red RAM, for instance) are always addressed explicitly rather than implicitly. Panels using the 4 bpp ACeP / Spectra palette pack two pixels per byte through SevenColor::pack.

§Supported controllers and panels

ControllerPanelsResolutionColour mode
Ssd1681ControllerGDEM0154Z90200 × 200Tri-Color
Ssd1680ControllerGDEM0213B74122 × 250Monochrome
Jd79661ControllerZJY122250_0213AJH_E5 / GDEY0213F51122 × 250Quad-Color
Uc8253ControllerGDEY037T03240 × 416Monochrome
Ssd1677ControllerGDEQ0426T82800 × 480Monochrome
Ed2208ControllerGDEP073E01800 × 480Spectra 6 (4 bpp)
PervasiveBwControllerE2266KS0C1, E2290KS0F1152 × 296, 168 × 384Monochrome
PervasiveBwryControllerE2154QS0F1, E2417QS0A3152 × 152, 400 × 300Quad-Color (Spectra-4)

Ssd1680Controller and Ssd1681Controller are thin wrappers over the shared Ssd168xController. Many panels also carry vendor-parity aliases, such as EPD_266_KS_0C for E2266KS0C1 or GxEPD2_370_GDEY037T03 for GDEY037T03.

§Quick start

use epdsi::prelude::*;
use embedded_graphics::{
    prelude::*, primitives::{Rectangle, PrimitiveStyle},
    pixelcolor::BinaryColor, geometry::{Point, Size},
};

// Wrap the SPI device and its control pins.
let epd_bus = SpiBusWrapper::new(spi_device, dc_pin, rst_pin, busy_pin);
let controller = Ssd1681Controller::new(GDEM0154Z90::WIDTH, GDEM0154Z90::HEIGHT);

// Bind controller and panel into a driver.
let mut epd = EpdBuilder::<_, GDEM0154Z90>::new(controller).build(epd_bus);
epd.init(&mut delay).unwrap();

// Both RAM channels must be primed on a tri-colour panel.
epd.clear_frame(ColorChannel::BlackWhite, 0xFF).unwrap();
epd.clear_frame(ColorChannel::RedYellow, 0x00).unwrap();

// Draw through embedded-graphics into a PageBuffer.
let mut bw_buf = [0xFFu8; 200 * 200 / 8];
let mut display = PageBuffer::new(&mut bw_buf, 200, 200, 0);
Rectangle::new(Point::new(10, 10), Size::new(50, 50))
    .into_styled(PrimitiveStyle::with_fill(BinaryColor::On))
    .draw(&mut display)
    .unwrap();

epd.write_frame(ColorChannel::BlackWhite, display.as_slice()).unwrap();
epd.refresh(&mut delay).unwrap();

prelude re-exports everything above and is the intended single import.

§Low-RAM paged rendering

A full 800 × 480 monochrome frame is 48 KB — more than many targets have. Rather than buffering a whole frame, render_paged sweeps the panel one horizontal band at a time, handing a small stack-allocated PageBuffer to a closure for each band, writing it, and refreshing once at the end. This is the GxEPD2 paged pattern; RAM use is set by the page height you choose, not by panel size.

§Colour panels refresh slowly, and that is physics

Tri-Color and Quad-Color panels have no fast differential waveform. The coloured pigment is a heavier particle needing the full OTP waveform to migrate, so every update takes seconds — roughly 14 s on GDEM0154Z90. Partial refresh modes select a controller LUT that only exists for monochrome panels; on a colour panel it produces wrong output rather than a fast update. Partial window updates still work, at full refresh speed.

§Cargo features

  • graphics (default) — implements embedded-graphics-core’s DrawTarget and Dimensions for PageBuffer. Disable to drop the dependency; the buffer and paged rendering still work, you just fill pixels yourself.
  • defmt — derives defmt::Format on the public error and mode enums for logging on embedded targets.

§Hardware note

On EXT3-1 extension boards, the J3 jumper must be OPEN (10 µH path) for panels 3.7“ and smaller. Closed (47 µH) the DC-DC booster sags during current bursts, which shows up as BUSY-pin hangs that look like driver bugs but are not.

§Complete examples

Runnable, flashable programs for every supported controller live in rust-rpico2-discovery (RP2350 Pico 2, rp-hal) and rust-reterminal-e1002-examples (XIAO ESP32-S3, Embassy + esp-hal).

The minimum supported Rust version is 1.75.

Re-exports§

pub use bus::SpiBusWrapper;
pub use bus3::Spi3Bus;
pub use driver::EpdBuilder;
pub use driver::EpdDriver;
pub use traits::ColorChannel;
pub use traits::ColorMode;
pub use traits::EpdController;
pub use traits::EpdPanel;
pub use traits::SevenColor;

Modules§

bus
SPI communication bus wrapper compatible with embedded-hal 1.0.
bus3
Bit-banged “3-wire” half-duplex SPI bus for the Pervasive Displays BWRY COG family’s OTP register read handshake.
controllers
Controller IC module for various EPD display drivers.
driver
Display driver orchestrator and builder implementation.
graphics
Graphics and paged rendering framework module.
panels
Hardware panel specifications module.
prelude
Prelude re-exporting common traits, drivers, controllers, and helpers.
traits
Core trait definitions for E-Paper Display Serial Interface (epdsi).