mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-10-17 19:05:07 +00:00
- CL-32 features added: - Hardware revision detection - v0.3 and v0.4 keyboard - v0.4 power supply - Inlined epd library (was a module) and made changes to the device definition (don't do full update after 5 small updates) - Statusbar: add support for inverted colors - e-paper driver improvements and warning fixes - Implemented gpio_controller_get_level() - Keyboard support improvements (unicode for tca drivers)
386 lines
11 KiB
Markdown
386 lines
11 KiB
Markdown
# ESP E-Paper Component
|
|
|
|
Forked from https://github.com/NellowTCS/esp_epaper which is a fork of https://github.com/tuanpmt/esp_epaper
|
|
|
|
[](https://components.espressif.com/components/tuanpmt/esp_epaper)
|
|
|
|
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.
|
|
|
|
## Key Features
|
|
|
|
### Multi-Color Panel Support
|
|
- **Black/White (1-bit)**: Classic e-paper with fastest refresh
|
|
- **4-Color BWRY (2-bit)**: Black, White, Red, Yellow
|
|
- **6-Color (4-bit)**: Black, White, Yellow, Red, Blue, Green - ideal for photo frames
|
|
|
|
### Floyd-Steinberg Dithering
|
|
Advanced error-diffusion dithering algorithm for photo-quality images:
|
|
- Smooth gradients using only available colors
|
|
- Automatic RGB565 to panel palette conversion
|
|
- PSRAM support for large displays (800x480)
|
|
|
|
### LVGL 9 Partial Refresh
|
|
Smart partial refresh for BW panels:
|
|
- Base image tracking for differential updates
|
|
- Automatic mode switching (partial <-> full)
|
|
- Configurable ghosting prevention
|
|
|
|
### Data-Driven Architecture
|
|
- **Panel Registry**: Add new panels with a single line of code
|
|
- **Controller Abstraction**: Reusable controller implementations
|
|
- **Capability Flags**: Runtime feature detection (partial, fast, grayscale)
|
|
|
|
### Memory Efficient
|
|
- Automatic PSRAM allocation for large buffers
|
|
- Chunked SPI transfers for DMA compatibility
|
|
- Optional dithering buffer
|
|
|
|
## Supported Panels
|
|
|
|
### Specific Panels (Custom LUT/Features)
|
|
|
|
| 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 |
|
|
|
|
### Generic SSD16xx Panels
|
|
|
|
Adding new BW panels requires only **1 line of code** - see [ADDING_PANELS.md](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 |
|
|
|
|
## Installation
|
|
|
|
### Using ESP-IDF Component Registry (Recommended)
|
|
|
|
Add to your project's `idf_component.yml`:
|
|
|
|
```yaml
|
|
dependencies:
|
|
tuanpmt/esp_epaper: "^1.0.4"
|
|
lvgl/lvgl: "^9.4.0"
|
|
```
|
|
|
|
Then run:
|
|
```bash
|
|
idf.py reconfigure
|
|
```
|
|
|
|
### Manual Installation
|
|
|
|
Clone or copy this repository to your project's `components` folder:
|
|
|
|
```bash
|
|
cd your_project/components
|
|
git clone https://github.com/tuanpmt/esp_epaper.git
|
|
```
|
|
|
|
## Quick Start
|
|
|
|
### Basic Usage
|
|
|
|
```c
|
|
#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);
|
|
}
|
|
```
|
|
|
|
### 6-Color Panel with Dithering (PhotoPainter)
|
|
|
|
```c
|
|
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);
|
|
```
|
|
|
|
### 4-Color BWRY Panel
|
|
|
|
```c
|
|
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);
|
|
```
|
|
|
|
## Configuration Presets
|
|
|
|
```c
|
|
// 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();
|
|
```
|
|
|
|
### Custom Configuration
|
|
|
|
```c
|
|
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,
|
|
},
|
|
};
|
|
```
|
|
|
|
## Update Modes
|
|
|
|
| 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 |
|
|
|
|
## Architecture Overview
|
|
|
|
```
|
|
+------------------+ +-------------------+ +------------------+
|
|
| 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 | +-------------------+
|
|
+------------------+
|
|
```
|
|
|
|
### Panel Registry (Data-Driven)
|
|
|
|
All panels are defined in a single registry table:
|
|
|
|
```c
|
|
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
|
|
};
|
|
```
|
|
|
|
### Capability Flags
|
|
|
|
```c
|
|
#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
|
|
```
|
|
|
|
## Floyd-Steinberg Dithering
|
|
|
|
The component implements Floyd-Steinberg error-diffusion dithering for photo-quality images on limited color e-paper displays.
|
|
|
|
### How It Works
|
|
|
|
1. **RGB565 -> RGB888 Conversion**: LVGL buffer is converted with proper bit expansion
|
|
2. **Palette Matching**: Each pixel is matched to the nearest e-paper color
|
|
3. **Error Diffusion**: Quantization error is distributed to neighbors (7/16 right, 3/16 bottom-left, 5/16 bottom, 1/16 bottom-right)
|
|
|
|
### Dithering Modes
|
|
|
|
| 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 | W*H*3 | Best |
|
|
|
|
### Color Palette
|
|
|
|
| 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 |
|
|
|
|
## Partial Refresh
|
|
|
|
BW panels support partial refresh for fast updates without full-screen flashing.
|
|
|
|
### How It Works
|
|
|
|
1. **Base Image**: First update writes to both current RAM (0x24) and base RAM (0x26)
|
|
2. **Partial Updates**: Subsequent updates only write to current RAM (0x24)
|
|
3. **Differential Update**: Display compares RAMs and only refreshes changed pixels
|
|
|
|
### Usage
|
|
|
|
```c
|
|
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.
|
|
|
|
## Examples
|
|
|
|
See the `examples/` folder for complete examples:
|
|
|
|
| Example | Board | Description |
|
|
|---------|-------|-------------|
|
|
| [esp32s3_epaper_154](examples/esp32s3_epaper_154) | ESP32-S3-ePaper-1.54 | 1.54" BW with grayscale dithering |
|
|
| [esp32s3_photopainter](examples/esp32s3_photopainter) | ESP32-S3-PhotoPainter | 7.3" 6-Color with dithering |
|
|
| [esp32_wroom_generic](examples/esp32_wroom_generic) | ESP32-WROOM-32D | Generic SSD16xx, responsive UI |
|
|
| [esp32_wroom_4color](examples/esp32_wroom_4color) | ESP32-WROOM-32D | 3.7" 4-Color BWRY |
|
|
|
|
### Building Examples
|
|
|
|
```bash
|
|
cd examples/esp32s3_epaper_154
|
|
idf.py set-target esp32s3
|
|
idf.py build
|
|
idf.py -p PORT flash monitor
|
|
```
|
|
|
|
## API Reference
|
|
|
|
### Core Functions
|
|
|
|
```c
|
|
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);
|
|
```
|
|
|
|
### LVGL Functions
|
|
|
|
```c
|
|
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);
|
|
```
|
|
|
|
## Adding New Panels
|
|
|
|
See [ADDING_PANELS.md](ADDING_PANELS.md) for detailed instructions on adding support for new e-paper panels.
|
|
|
|
**Quick summary**:
|
|
- **Same controller, different size**: Add 1 line to panel registry
|
|
- **New controller**: Add controller ops + panel registry entry
|
|
|
|
## Memory Requirements
|
|
|
|
| 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 | 135 KB |
|
|
| 3.7" BW | 280x480 | 1 | 16.8 KB | 403 KB |
|
|
| 4.2" BW | 400x300 | 1 | 15 KB | 360 KB |
|
|
| 3.7" BWRY | 240x416 | 2 | 25 KB | 300 KB |
|
|
| 7.3" 6-Color | 800x480 | 4 | 192 KB | 1.15 MB |
|
|
|
|
**Note**: Large buffers (>32KB) are automatically allocated from PSRAM when available.
|
|
|
|
## License
|
|
|
|
MIT License - See [LICENSE](LICENSE)
|
|
|
|
## Author
|
|
|
|
- **tuanpmt** - [GitHub](https://github.com/tuanpmt)
|