mirror of
https://github.com/esphome/esphome.git
synced 2026-10-14 10:12:52 +00:00
[mipi_spi] Add LCDwiki ES3C35P model (ST77922 QSPI) (#19011)
Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: J. Nick Koston <nick@koston.org> Co-authored-by: J. Nick Koston <nick@home-assistant.io>
This commit is contained in:
co-authored by
Claude Opus 5
J. Nick Koston
J. Nick Koston
parent
e50a0d902e
commit
59d31505e9
@@ -0,0 +1,86 @@
|
||||
# Init sequence sourced from LCDwiki's own published Arduino example for this board:
|
||||
# https://github.com/ydedox/st77922 (Example_01_Simple_test/Simple_test/Simple_test.ino)
|
||||
# It is the commented-out panel table in that file, with the 0x71 and 0xBE values from the
|
||||
# active one, which is what the shipped firmware writes.
|
||||
|
||||
from esphome.components.mipi import MODE_RGB, SLPOUT, DriverChip, delay
|
||||
from esphome.components.spi import TYPE_QUAD
|
||||
from esphome.const import CONF_MIRROR_X, CONF_MIRROR_Y
|
||||
|
||||
# fmt: off
|
||||
ES3C35P = DriverChip(
|
||||
"ES3C35P",
|
||||
width=320,
|
||||
height=480,
|
||||
draw_rounding=4,
|
||||
transforms={CONF_MIRROR_X, CONF_MIRROR_Y},
|
||||
color_order=MODE_RGB,
|
||||
invert_colors=True,
|
||||
bus_mode=TYPE_QUAD,
|
||||
data_rate="40MHz", # datasheet caps the write clock at 62.5MHz
|
||||
cs_pin=10,
|
||||
reset_delay=120,
|
||||
no_slpout=True, # SLPOUT is in the init sequence, the panel needs 120ms after it
|
||||
requires={"psram"},
|
||||
initsequence=(
|
||||
(0xF1, 0x00),
|
||||
(0x60, 0x00, 0x00, 0x00),
|
||||
(0x65, 0x80),
|
||||
(0x79, 0x06),
|
||||
(0x7B, 0x00, 0x08, 0x08),
|
||||
(0x80, 0x55, 0x62, 0x2F, 0x17, 0xF0, 0x52, 0x70, 0xD2, 0x52, 0x62, 0xEA),
|
||||
(0x81, 0x26, 0x52, 0x72, 0x27),
|
||||
(0x84, 0x92, 0x25),
|
||||
(0x87, 0x10, 0x10, 0x58, 0x00, 0x02, 0x3A),
|
||||
(0x88, 0x00, 0x00, 0x2C, 0x10, 0x04, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x06),
|
||||
(0x89, 0x00, 0x00, 0x00),
|
||||
(0x8A, 0x13, 0x00, 0x2C, 0x00, 0x00, 0x2C, 0x10, 0x10, 0x00, 0x3E, 0x19),
|
||||
(0x8B, 0x15, 0xB1, 0xB1, 0x44, 0x96, 0x2C, 0x10, 0x97, 0x8E),
|
||||
(0x8C, 0x1D, 0xB1, 0xB1, 0x44, 0x96, 0x2C, 0x10, 0x50, 0x0F, 0x01, 0xC5, 0x12, 0x09),
|
||||
(0x8D, 0x0C),
|
||||
(0x8E, 0x33, 0x01, 0x0C, 0x13, 0x01, 0x01),
|
||||
(0xB3, 0x00, 0x30),
|
||||
(0x71, 0xD0),
|
||||
(0x66, 0x02, 0x3F),
|
||||
(0xBE, 0x26, 0x00, 0x9D),
|
||||
(0x70, 0x01, 0xA6, 0x11, 0x40, 0xE0, 0x00, 0x11, 0x60, 0x11, 0x00, 0x00, 0x1A),
|
||||
(0x90, 0x04, 0x04, 0x55, 0x74, 0x00, 0x40, 0x43, 0x2D, 0x2D),
|
||||
(0x91, 0x04, 0x04, 0x55, 0x75, 0x00, 0x40, 0x42, 0x2D, 0x2D),
|
||||
(0x92, 0x04, 0x44, 0x55, 0xC0, 0x06, 0x00, 0x07, 0x05, 0x90, 0x2D),
|
||||
(0x93, 0x04, 0x43, 0x11, 0x00, 0x00, 0x00, 0x00, 0x05, 0x90, 0x2D),
|
||||
(0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
|
||||
(0x95, 0x96, 0x16, 0x00, 0x00, 0xFF),
|
||||
(0x96, 0x44, 0x53, 0x03, 0x12, 0x23, 0x24, 0x06, 0x05, 0x9A, 0x2D, 0x00, 0x44),
|
||||
(0x97, 0x44, 0x53, 0x47, 0x56, 0x20, 0x20, 0x02, 0x01, 0x9A, 0x2D, 0x00, 0x44),
|
||||
(0xBA, 0x55, 0x9A, 0x2D, 0x9A, 0x2D),
|
||||
(0x9A, 0x40, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00),
|
||||
(0x9B, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00),
|
||||
(0x9C, 0x5C, 0x12, 0x00, 0x00, 0x10, 0x12, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x00),
|
||||
(0x9D, 0x8A, 0x51, 0x00, 0x00, 0x00, 0x80, 0x1E, 0x01),
|
||||
(0x9E, 0x51, 0x00, 0x00, 0x00, 0x80, 0x1E, 0x01),
|
||||
(0xB4, 0x1D, 0x1C, 0x1E, 0x0B, 0x14, 0x02, 0x13, 0x09, 0x1E, 0x00, 0x1E, 0x10),
|
||||
(0xB5, 0x1D, 0x1C, 0x1E, 0x0A, 0x15, 0x03, 0x11, 0x08, 0x1E, 0x01, 0x1E, 0x12),
|
||||
(0xB6, 0x77, 0x77, 0x00, 0x0A, 0xFF, 0x0A, 0xFF),
|
||||
(0x86, 0xC6, 0x04, 0xB1, 0x02, 0x58, 0x12, 0x58, 0x0C, 0x13, 0x01, 0xA5, 0x00, 0xA5, 0xA5),
|
||||
(0xB7, 0x07, 0x0A, 0x0E, 0x06, 0x05, 0x03, 0x2B, 0x03, 0x03, 0x42, 0x07, 0x10, 0x10, 0x2E, 0x3F, 0x0D),
|
||||
(0xB8, 0x07, 0x0A, 0x0D, 0x05, 0x05, 0x02, 0x2B, 0x02, 0x03, 0x42, 0x06, 0x10, 0x0F, 0x2E, 0x3F, 0x0D),
|
||||
(0xB9, 0x23, 0x23),
|
||||
(0xBF, 0x10, 0x14, 0x14, 0x0B, 0x0B, 0x0B),
|
||||
(0xF2, 0x00),
|
||||
(0x73, 0x04, 0xDA, 0x12, 0x54, 0x47),
|
||||
(0x77, 0x6B, 0x5B, 0xFD, 0xC3, 0xC5),
|
||||
(0x7A, 0x15, 0x27),
|
||||
(0x7B, 0x04, 0x57),
|
||||
(0x7E, 0x01, 0x0E),
|
||||
(0xBF, 0x36),
|
||||
(0xE3, 0x40, 0x40),
|
||||
(0xF0, 0x00),
|
||||
(0xD0, 0x00),
|
||||
(SLPOUT,),
|
||||
delay(120),
|
||||
),
|
||||
)
|
||||
# fmt: on
|
||||
|
||||
# The speakerless variant uses the same display
|
||||
ES3C35P.extend("ES3C35P-NS")
|
||||
@@ -8,8 +8,11 @@ from esphome.components.mipi import (
|
||||
BRIGHTNESS,
|
||||
CONF_INVERT_COLORS,
|
||||
CONF_PIXEL_MODE,
|
||||
SLPOUT,
|
||||
SWRESET,
|
||||
DriverChip,
|
||||
)
|
||||
from esphome.components.mipi_spi.display import MODELS
|
||||
from esphome.const import CONF_BRIGHTNESS
|
||||
|
||||
# A minimal config with no reset pin: enough for get_sequence(add_madctl=False) to run
|
||||
@@ -96,3 +99,23 @@ def test_get_sequence_omits_brightness_when_not_set() -> None:
|
||||
sequence = chip.get_sequence(_BASE_CONFIG, add_madctl=False)
|
||||
|
||||
assert not any(_has_brightness_command(sequence, v) for v in range(256))
|
||||
|
||||
|
||||
def _count_subsequence(sequence: tuple[int, ...], part: tuple[int, ...]) -> int:
|
||||
return sum(
|
||||
sequence[i : i + len(part)] == part
|
||||
for i in range(len(sequence) - len(part) + 1)
|
||||
)
|
||||
|
||||
|
||||
def test_es3c35p_waits_after_reset_and_issues_its_own_slpout() -> None:
|
||||
"""The ES3C35P settles 120ms after reset and sends SLPOUT itself with a 120ms wait."""
|
||||
sequence = MODELS["ES3C35P"].get_sequence(
|
||||
_BASE_CONFIG, add_madctl=False, add_reset=True
|
||||
)
|
||||
|
||||
assert sequence[:4] == (SWRESET, 0, 120, 255)
|
||||
# Exactly one SLPOUT, followed by the panel's 120ms settle, and none appended by the framework
|
||||
assert _count_subsequence(sequence, (SLPOUT, 0, 120, 255)) == 1
|
||||
assert _count_subsequence(sequence, (SLPOUT, 0, 10, 255)) == 0
|
||||
assert "ES3C35P-NS" in MODELS
|
||||
|
||||
Reference in New Issue
Block a user