mirror of
https://github.com/esphome/esphome.git
synced 2026-10-19 04:32:50 +00:00
[epaper_spi] Add the UC8151D controller and the Waveshare 2.13" B V3 (#21022)
This commit is contained in:
@@ -20,7 +20,7 @@ static BwrState color_to_bwr(Color color) {
|
||||
return BwrState::BWR_BLACK;
|
||||
}
|
||||
|
||||
// UC8179 3-color display buffer layout:
|
||||
// 3-color display buffer layout (UC8179 and UC8151D):
|
||||
// - 1 bit per pixel, 8 pixels per byte
|
||||
// - Buffer first half: Black/White plane (1=black, 0=white)
|
||||
// - Buffer second half: Red plane (1=red, 0=white)
|
||||
@@ -79,7 +79,7 @@ bool HOT EPaperWaveshareBWR::transfer_data() {
|
||||
uint8_t bytes_to_send[MAX_TRANSFER_SIZE];
|
||||
|
||||
// Phase 1: send Black/White plane (first half) via command 0x10 (DTM1)
|
||||
// UC8179 DTM1 (0x10): inverted to get 0=black, 1=white
|
||||
// DTM1 (0x10): inverted to get 0=black, 1=white
|
||||
if (this->current_data_index_ < half_buffer) {
|
||||
if (this->current_data_index_ == 0) {
|
||||
this->command(0x10); // DATA START TRANSMISSION 1 (black channel)
|
||||
@@ -101,7 +101,7 @@ bool HOT EPaperWaveshareBWR::transfer_data() {
|
||||
}
|
||||
|
||||
// Phase 2: send Red plane (second half) via command 0x13 (DTM2)
|
||||
// UC8179 DTM2 (0x13): 1=red, 0=white
|
||||
// DTM2 (0x13): 1=red, 0=white; on the UC8151D this relies on the 0x50 value in uc8151.py
|
||||
if (this->current_data_index_ < buffer_length) {
|
||||
if (this->current_data_index_ == half_buffer) {
|
||||
this->command(0x13); // DATA START TRANSMISSION 2 (red channel)
|
||||
@@ -127,8 +127,7 @@ bool HOT EPaperWaveshareBWR::transfer_data() {
|
||||
}
|
||||
|
||||
void EPaperWaveshareBWR::power_on() {
|
||||
this->cmd_data(0x01, {0x07, 0x17, 0x3F, 0x3F}); // POWER SETTING
|
||||
this->command(0x04); // POWER ON
|
||||
this->command(0x04); // POWER ON
|
||||
}
|
||||
|
||||
void EPaperWaveshareBWR::refresh_screen(bool /*partial*/) {
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
namespace esphome::epaper_spi {
|
||||
|
||||
/**
|
||||
* Waveshare 3-color e-paper displays (UC8179 controller).
|
||||
* Supports: 7.5" V2 BWR (EDP_7in5b_V2), 800x480 pixels.
|
||||
* Waveshare 3-color e-paper displays (UC8179 and UC8151D controllers).
|
||||
* Supports: 7.5" V2 BWR (EPD_7in5b_V2), 800x480 pixels; 2.13" B V3 (EPD_2in13b_V3), 104x212 pixels.
|
||||
*
|
||||
* Color scheme: Black, White, Red (BWR)
|
||||
* Buffer layout: 1 bit per pixel, separate planes
|
||||
@@ -14,8 +14,8 @@ namespace esphome::epaper_spi {
|
||||
* - Buffer second half: Red plane (1=red, 0=no red)
|
||||
* - Total buffer: width * height / 4 bytes (2 * width * height / 8)
|
||||
*
|
||||
* The init sequence (INITIALISE state) sends panel configuration only.
|
||||
* Power-on (0x01 + 0x04) is sent in the POWER_ON state after data transfer;
|
||||
* The init sequence (INITIALISE state) sends the power and panel configuration.
|
||||
* Power-on (0x04) is sent in the POWER_ON state after data transfer;
|
||||
* the state machine then busy-waits before triggering REFRESH_SCREEN (0x12).
|
||||
*/
|
||||
class EPaperWaveshareBWR : public EPaperBase {
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
"""Black/white/red e-paper displays using the UltraChip UC8151D controller.
|
||||
|
||||
Supported models:
|
||||
- uc8151: the controller on its own; dimensions and pins must be configured
|
||||
- waveshare-2.13in-bv3: 104x212 pixels (2.13" B V3, EPD_2in13b_V3)
|
||||
|
||||
The busy pin of these displays is low while busy, so configure it with ``inverted: true``.
|
||||
"""
|
||||
|
||||
from typing import Any
|
||||
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_DIMENSIONS
|
||||
from esphome.types import ConfigType
|
||||
|
||||
from . import EpaperModel
|
||||
|
||||
MAX_SOURCES = 160
|
||||
MAX_GATES = 296
|
||||
|
||||
|
||||
class UC8151(EpaperModel):
|
||||
"""EpaperModel class for black/white/red displays using the UC8151D controller."""
|
||||
|
||||
def __init__(self, name: str, **defaults: Any) -> None:
|
||||
super().__init__(name, "EPaperWaveshareBWR", **defaults)
|
||||
|
||||
def validate_config(self, config: ConfigType) -> ConfigType:
|
||||
width, height = self.get_dimensions(config)
|
||||
if width > MAX_SOURCES or height > MAX_GATES:
|
||||
raise cv.Invalid(
|
||||
f"{self.name} supports at most {MAX_SOURCES}x{MAX_GATES} pixels (width x height)",
|
||||
path=[CONF_DIMENSIONS],
|
||||
)
|
||||
return config
|
||||
|
||||
def get_init_sequence(self, config: dict) -> tuple:
|
||||
width, height = self.get_dimensions(config)
|
||||
return (
|
||||
# PANEL SETTING (black/white/red mode, LUT from OTP)
|
||||
(0x00, 0x0F, 0x89),
|
||||
# RESOLUTION SETTING: sources, then gates
|
||||
(0x61, width, height >> 8, height & 0xFF),
|
||||
# VCOM AND DATA INTERVAL SETTING; 0x57, not Waveshare's 0x77, so that 1 in DTM2 is red
|
||||
(0x50, 0x57),
|
||||
)
|
||||
|
||||
|
||||
uc8151 = UC8151(
|
||||
"uc8151",
|
||||
data_rate="10MHz",
|
||||
minimum_update_interval="15s",
|
||||
width_multiple=8,
|
||||
)
|
||||
|
||||
uc8151.extend(
|
||||
"waveshare-2.13in-bv3",
|
||||
width=104,
|
||||
height=212,
|
||||
)
|
||||
@@ -1,10 +1,10 @@
|
||||
"""Waveshare Black/White/Red e-paper displays using UC8179 controller.
|
||||
|
||||
Supported models:
|
||||
- waveshare-7.5in-bv2-bwr: 800x480 pixels (7.5" BWR display, EDP_7in5b_V2)
|
||||
- waveshare-7.5in-bv2-bwr: 800x480 pixels (7.5" BWR display, EPD_7in5b_V2)
|
||||
|
||||
These displays use the UC8179 controller. Panel configuration is sent during
|
||||
the INITIALISE state. Power-on is handled in the POWER_ON state, after data
|
||||
These displays use the UC8179 controller. Power and panel configuration are sent
|
||||
during the INITIALISE state. Power-on is handled in the POWER_ON state, after data
|
||||
transfer, so the state machine's built-in busy wait covers the power-on delay.
|
||||
"""
|
||||
|
||||
@@ -20,8 +20,8 @@ class WaveshareBWR(EpaperModel):
|
||||
def get_init_sequence(self, config):
|
||||
"""Generate initialization sequence for UC8179 BWR displays.
|
||||
|
||||
Panel configuration only — power-on is handled separately in power_on()
|
||||
after data transfer, with the state machine busy-waiting before refresh.
|
||||
Power and panel configuration only — power-on is handled separately in
|
||||
power_on() after data transfer, with the state machine busy-waiting before refresh.
|
||||
"""
|
||||
width, height = self.get_dimensions(config)
|
||||
return (
|
||||
@@ -43,10 +43,12 @@ class WaveshareBWR(EpaperModel):
|
||||
(0x60, 0x22),
|
||||
# RESOLUTION GATE SETTING
|
||||
(0x65, 0x00, 0x00, 0x00, 0x00),
|
||||
# POWER SETTING
|
||||
(0x01, 0x07, 0x17, 0x3F, 0x3F),
|
||||
)
|
||||
|
||||
|
||||
# Model: Waveshare 7.5" V2 BWR (EDP_7in5b_V2) — 800x480, UC8179 controller
|
||||
# Model: Waveshare 7.5" V2 BWR (EPD_7in5b_V2) — 800x480, UC8179 controller
|
||||
WaveshareBWR(
|
||||
"waveshare-7.5in-bv2-bwr",
|
||||
width=800,
|
||||
|
||||
@@ -143,7 +143,7 @@ def test_all_predefined_models(
|
||||
|
||||
# Add dimensions if not provided by model
|
||||
if not model.get_default(CONF_WIDTH):
|
||||
config[CONF_DIMENSIONS] = {CONF_HEIGHT: 240, CONF_WIDTH: 320}
|
||||
config[CONF_DIMENSIONS] = {CONF_HEIGHT: 120, CONF_WIDTH: 120}
|
||||
|
||||
# Add init sequence if model doesn't provide one
|
||||
if model.initsequence is None:
|
||||
@@ -199,7 +199,7 @@ def test_individual_models(
|
||||
config[CONF_DC_PIN] = 21
|
||||
|
||||
if not model.get_default(CONF_WIDTH):
|
||||
config[CONF_DIMENSIONS] = {CONF_HEIGHT: 240, CONF_WIDTH: 320}
|
||||
config[CONF_DIMENSIONS] = {CONF_HEIGHT: 120, CONF_WIDTH: 120}
|
||||
|
||||
if model.initsequence is None:
|
||||
config[CONF_INIT_SEQUENCE] = [[0xA0, 0x01]]
|
||||
|
||||
@@ -285,6 +285,28 @@ display:
|
||||
it.circle(it.get_width() / 2, it.get_height() / 2, 20, Color::BLACK);
|
||||
it.circle(it.get_width() / 2, it.get_height() / 2, 15, Color(255, 0, 0));
|
||||
|
||||
# Waveshare 2.13" V3 B series 3-color e-paper (104x212, BWR, UC8151D)
|
||||
- platform: epaper_spi
|
||||
spi_id: spi_bus
|
||||
model: waveshare-2.13in-bv3
|
||||
cs_pin:
|
||||
allow_other_uses: true
|
||||
number: GPIO5
|
||||
dc_pin:
|
||||
allow_other_uses: true
|
||||
number: GPIO17
|
||||
reset_pin:
|
||||
allow_other_uses: true
|
||||
number: GPIO16
|
||||
busy_pin:
|
||||
allow_other_uses: true
|
||||
number: GPIO4
|
||||
inverted: true
|
||||
lambda: |-
|
||||
it.filled_rectangle(0, 0, it.get_width(), it.get_height(), Color::WHITE);
|
||||
it.circle(it.get_width() / 2, it.get_height() / 2, 20, Color::BLACK);
|
||||
it.circle(it.get_width() / 2, it.get_height() / 2, 15, Color(255, 0, 0));
|
||||
|
||||
# Waveshare 2.66" B 3-color e-paper (152x296, BWR, SSD1680)
|
||||
- platform: epaper_spi
|
||||
spi_id: spi_bus
|
||||
|
||||
Reference in New Issue
Block a user