Loading repository data…
Loading repository data…
tuanpmt / repository
A flexible e-paper display driver component for ESP-IDF with LVGL 9 integration. Designed for IoT devices, electronic shelf labels, photo frames, and low-power display applications.
A transparent discovery signal based on current public GitHub metadata.
This score does not audit code, security, maintainers, documentation quality, or suitability. Verify the repository and its current documentation before adoption.
A flexible e-paper display driver component for ESP-IDF with LVGL 9 integration. Designed for IoT devices, electronic shelf labels, photo frames, and low-power display applications.
Advanced error-diffusion dithering algorithm for photo-quality images:
Smart partial refresh for BW panels:
| Panel | Size | Resolution | Colors | Partial Refresh |
|---|---|---|---|---|
| GDEY0154D67 | 1.54" | 200x200 | BW | Yes (custom LUT) |
| GDEP073E01 | 7.3" | 800x480 | 6-Color | No |
| GDEY037F51 | 3.7" | 240x416 | 4-Color BWRY | No |
Adding new BW panels requires only 1 line of code - see ADDING_PANELS.md.
| Panel Type | Size | Resolution | Compatible Models |
|---|---|---|---|
| SSD16XX_154 | 1.54" | 200x200 | GDEM0154I61, etc. |
| SSD16XX_213 | 2.13" | 122x250 | GDEY0213B74, GDEM0213I61 |
| SSD16XX_266 | 2.66" | 152x296 | GDEY0266T90, GDEY0266T90H |
| SSD16XX_270 | 2.7" | 176x264 | GDEY027T91, GDEM027Q72 |
| SSD16XX_290 | 2.9" | 128x296 | GDEY029T94, GDEY029T71H |
| SSD16XX_370 | 3.7" | 280x480 | GDEY037T03 |
| SSD16XX_420 | 4.2" | 400x300 | GDEY042T81, GDEQ0426T82 |
Add to your project's idf_component.yml:
dependencies:
tuanpmt/esp_epaper: "^1.0.4"
lvgl/lvgl: "^9.4.0"
Then run:
idf.py reconfigure
Clone or copy this repository to your project's components folder:
cd your_project/components
git clone https://github.com/tuanpmt/esp_epaper.git
#include "epaper.h"
#include "epaper_lvgl.h"
#include "lvgl.h"
void app_main(void)
{
lv_init();
// Use preset configuration for ESP32-S3-ePaper-1.54
epd_config_t cfg = EPD_CONFIG_ESP32S3_154();
// Initialize e-paper
epd_handle_t epd;
ESP_ERROR_CHECK(epd_init(&cfg, &epd));
// Initialize LVGL display
epd_lvgl_config_t lvgl_cfg = EPD_LVGL_CONFIG_DEFAULT();
lvgl_cfg.epd = epd;
lv_display_t *disp = epd_lvgl_init(&lvgl_cfg);
// Create UI with LVGL...
lv_obj_t *label = lv_label_create(lv_screen_active());
lv_label_set_text(label, "Hello E-Paper!");
lv_obj_center(label);
// Refresh display
epd_lvgl_refresh(disp);
}
epd_config_t cfg = EPD_CONFIG_73_6COLOR();
epd_handle_t epd;
epd_init(&cfg, &epd);
epd_lvgl_config_t lvgl_cfg = EPD_LVGL_CONFIG_DEFAULT();
lvgl_cfg.epd = epd;
lvgl_cfg.update_mode = EPD_UPDATE_FULL;
lvgl_cfg.dither_mode = EPD_DITHER_FLOYD_STEINBERG;
lv_display_t *disp = epd_lvgl_init(&lvgl_cfg);
epd_config_t cfg = EPD_CONFIG_ESP32_WROOM_4COLOR();
epd_handle_t epd;
epd_init(&cfg, &epd);
epd_lvgl_config_t lvgl_cfg = EPD_LVGL_CONFIG_DEFAULT();
lvgl_cfg.epd = epd;
lvgl_cfg.dither_mode = EPD_DITHER_ORDERED; // Good for BWRY
lv_display_t *disp = epd_lvgl_init(&lvgl_cfg);
// Waveshare ESP32-S3-ePaper-1.54 (1.54" BW)
epd_config_t cfg = EPD_CONFIG_ESP32S3_154();
// Waveshare ESP32-S3-PhotoPainter (7.3" 6-Color)
epd_config_t cfg = EPD_CONFIG_73_6COLOR();
// Good Display ESP32-WROOM-32D (2.66" BW)
epd_config_t cfg = EPD_CONFIG_ESP32_WROOM();
// Good Display ESP32-WROOM-32D + 3.7" 4-Color BWRY
epd_config_t cfg = EPD_CONFIG_ESP32_WROOM_4COLOR();
epd_config_t cfg = {
.pins = {
.busy = GPIO_NUM_8,
.rst = GPIO_NUM_9,
.dc = GPIO_NUM_10,
.cs = GPIO_NUM_11,
.sck = GPIO_NUM_12,
.mosi = GPIO_NUM_13,
},
.spi = {
.host = SPI2_HOST,
.speed_hz = 10000000, // 10MHz
},
.panel = {
.type = EPD_PANEL_GDEY0154D67,
.width = 0, // 0 = use panel default
.height = 0,
},
};
| Mode | Description | Use Case |
|---|---|---|
EPD_UPDATE_FULL | Full refresh with flashing | Initial display, clearing ghosting |
EPD_UPDATE_PARTIAL | Fast partial update | UI updates, counters |
EPD_UPDATE_FAST | Fast mode (panel dependent) | Animations |
+------------------+ +-------------------+ +------------------+
| Application |---->| epaper_lvgl.c |---->| epaper.c |
| (LVGL UI) | | (RGB565->EPD fmt) | | (Device Manager) |
+------------------+ +-------------------+ +------------------+
|
+--------------------------------+
|
v
+------------------+ +-------------------+
| epaper_registry.c|---->| controllers/ |
| (Panel Database) | | - ssd16xx.c |
| | | - gdey0154_lut.c |
| - Panel specs | | - acep_6color.c |
| - Capabilities | | - bwry_4color.c |
| - Controller map | +-------------------+
+------------------+
All panels are defined in a single registry table:
static const epd_panel_desc_t panel_registry[EPD_PANEL_COUNT] = {
[EPD_PANEL_GDEY0154D67] = {
.name = "GDEY0154D67",
.width = 200, .height = 200,
.color_mode = EPD_COLOR_BW,
.bits_per_pixel = 1,
.caps = EPD_CAP_PARTIAL | EPD_CAP_FAST,
.ctrl = EPD_CTRL_GDEY0154_LUT,
},
// ... more panels
};
#define EPD_CAP_PARTIAL (1 << 0) // Supports partial refresh
#define EPD_CAP_FAST (1 << 1) // Supports fast refresh
#define EPD_CAP_GRAYSCALE (1 << 2) // Supports grayscale mode
#define EPD_CAP_BUSY_INV (1 << 3) // Inverted busy signal
The component implements Floyd-Steinberg error-diffusion dithering for photo-quality images on limited color e-paper displays.
| Mode | Description | Memory | Quality |
|---|---|---|---|
EPD_DITHER_NONE | Direct color mapping | None | Basic |
EPD_DITHER_ORDERED | Bayer 4x4 pattern | None | Good |
EPD_DITHER_FLOYD_STEINBERG | Error diffusion | WH3 | Best |
| Color | RGB Value | E-Paper Code |
|---|---|---|
| Black | (0, 0, 0) | 0x00 |
| White | (255, 255, 255) | 0x01 |
| Yellow | (255, 255, 0) | 0x02 |
| Red | (255, 0, 0) | 0x03 |
| Blue | (0, 0, 255) | 0x05 |
| Green | (0, 255, 0) | 0x06 |
BW panels support partial refresh for fast updates without full-screen flashing.
epd_lvgl_config_t lvgl_cfg = EPD_LVGL_CONFIG_DEFAULT();
lvgl_cfg.epd = epd;
lvgl_cfg.update_mode = EPD_UPDATE_PARTIAL;
lvgl_cfg.use_partial_refresh = true;
lv_display_t *disp = epd_lvgl_init(&lvgl_cfg);
// First refresh sets base image (full refresh)
epd_lvgl_refresh(disp);
// Subsequent refreshes use partial mode
lv_label_set_text(label, "Count: 1");
epd_lvgl_refresh(disp); // Fast partial update
// Force full refresh periodically to clear ghosting
epd_lvgl_force_full_refresh(disp);
epd_lvgl_refresh(disp);
Note: Multi-color panels (6-color, 4-color BWRY) do not support partial refresh.
See the examples/ folder for complete examples:
| Example | Board | Description |
|---|---|---|
| esp32s3_epaper_154 | ESP32-S3-ePaper-1.54 | 1.54" BW with grayscale dithering |
| esp32s3_photopainter | ESP32-S3-PhotoPainter | 7.3" 6-Color with dithering |
| esp32_wroom_generic | ESP32-WROOM-32D | Generic SSD16xx, responsive UI |
| esp32_wroom_4color | ESP32-WROOM-32D | 3.7" 4-Color BWRY |
cd examples/esp32s3_epaper_154
idf.py set-target esp32s3
idf.py build
idf.py -p PORT flash monitor
esp_err_t epd_init(const epd_config_t *config, epd_handle_t *handle);
esp_err_t epd_deinit(epd_handle_t handle);
esp_err_t epd_get_info(epd_handle_t handle, epd_panel_info_t *info);
uint8_t* epd_get_framebuffer(epd_handle_t handle);
esp_err_t epd_update(epd_handle_t handle, const uint8_t *data, epd_update_mode_t mode);
esp_err_t epd_fill(epd_handle_t handle, uint8_t color);
esp_err_t epd_sleep(epd_handle_t handle);
esp_err_t epd_wake(epd_handle_t handle);
lv_display_t* epd_lvgl_init(const epd_lvgl_config_t *config);
void epd_lvgl_deinit(lv_display_t *disp);
void epd_lvgl_refresh(lv_display_t *disp);
void epd_lvgl_force_full_refresh(lv_display_t *disp);
void epd_lvgl_set_update_mode(lv_display_t *disp, epd_update_mode_t mode);
void epd_lvgl_set_dither_mode(lv_display_t *disp, epd_dither_mode_t mode);
See ADDING_PANELS.md for detailed instructions on adding support for new e-paper panels.
Quick summary:
| Panel | Resolution | BPP | Framebuffer | RGB Buffer (dithering) |
|---|---|---|---|---|
| 1.54" BW | 200x200 | 1 | 5 KB | 120 KB |
| 2.13" BW | 122x250 | 1 | 3.8 KB | 92 KB |
| 2.66" BW | 152x296 | 1 | 5.6 KB |