[mipi_spi] Suppress sequence errors when page selection used (#17176)

This commit is contained in:
Clyde Stubbs
2026-06-24 22:05:23 +10:00
committed by GitHub
parent cbcf23426d
commit 18f29f8d2b
4 changed files with 126 additions and 16 deletions
+1
View File
@@ -120,6 +120,7 @@ CSCON = 0xF0
PWCTR6 = 0xF6
ADJCTL3 = 0xF7
PAGESEL = 0xFE
PAGESEL1 = 0xFF
MADCTL_MY = 0x80 # Bit 7 Bottom to top
MADCTL_MX = 0x40 # Bit 6 Right to left
+12 -8
View File
@@ -17,6 +17,8 @@ from esphome.components.mipi import (
MADCTL,
MODE_BGR,
MODE_RGB,
PAGESEL,
PAGESEL1,
PIXFMT,
DriverChip,
dimension_schema,
@@ -276,14 +278,16 @@ def customise_schema(config):
# Check for invalid combinations of MADCTL config
if init_sequence := config.get(CONF_INIT_SEQUENCE):
commands = [x[0] for x in init_sequence]
if MADCTL in commands and CONF_TRANSFORM in config:
raise cv.Invalid(
f"transform is not supported when MADCTL ({MADCTL:#X}) is in the init sequence"
)
if PIXFMT in commands:
raise cv.Invalid(
f"PIXFMT ({PIXFMT:#X}) should not be in the init sequence, it will be set automatically"
)
# If there is page swapping, we can't rely on recognising common commands
if PAGESEL not in commands and PAGESEL1 not in commands:
if MADCTL in commands and CONF_TRANSFORM in config:
raise cv.Invalid(
f"transform is not supported when MADCTL ({MADCTL:#X}) is in the init sequence"
)
if PIXFMT in commands:
raise cv.Invalid(
f"PIXFMT ({PIXFMT:#X}) should not be in the init sequence, it will be set automatically"
)
if bus_mode == TYPE_QUAD and CONF_DC_PIN in config:
raise cv.Invalid("DC pin is not supported in quad mode")
-8
View File
@@ -176,7 +176,6 @@ class MipiSpi : public display::Display,
this->mark_failed();
return;
}
auto arg_byte = vec[index];
switch (cmd) {
case SLEEP_OUT: {
// are we ready, boots?
@@ -187,13 +186,6 @@ class MipiSpi : public display::Display,
}
} break;
case INVERT_ON:
this->invert_colors_ = true;
break;
case BRIGHTNESS:
this->brightness_ = arg_byte;
break;
default:
break;
}
@@ -0,0 +1,113 @@
"""Combined tests for PAGESEL/PAGESEL1 behaviour with MADCTL/PIXFMT.
Covers both the suppression behaviour (when PAGESEL or PAGESEL1 are present)
and the error behaviour when neither page-selection command is present.
"""
from __future__ import annotations
from typing import Any
import pytest
from esphome.components.esp32 import KEY_BOARD, KEY_VARIANT, VARIANT_ESP32
from esphome.components.mipi import MADCTL, PAGESEL, PAGESEL1, PIXFMT
from esphome.components.mipi_spi.display import CONFIG_SCHEMA, FINAL_VALIDATE_SCHEMA
import esphome.config_validation as cv
from esphome.const import PlatformFramework
from tests.component_tests.types import SetCoreConfigCallable
def validated_config(config: dict[str, Any]) -> dict[str, Any]:
"""Run schema + final validation and return the validated config."""
cfg = CONFIG_SCHEMA(config)
FINAL_VALIDATE_SCHEMA(cfg)
return cfg
def test_madctl_error_suppressed_when_pagesel_present(
set_core_config: SetCoreConfigCallable,
) -> None:
"""If PAGESEL is present in init_sequence, MADCTL presence must not raise an error."""
set_core_config(
PlatformFramework.ESP32_IDF,
platform_data={KEY_BOARD: "esp32dev", KEY_VARIANT: VARIANT_ESP32},
)
cfg = {
"model": "custom",
"dc_pin": 18,
"dimensions": {"width": 320, "height": 240},
"transform": {"mirror_x": True, "mirror_y": True, "swap_xy": False},
"init_sequence": [[PAGESEL, 0x00], [MADCTL, 0x01]],
}
# Should not raise
validated = validated_config(cfg)
assert validated is not None
def test_pixfmt_error_suppressed_when_pagesel1_present(
set_core_config: SetCoreConfigCallable,
) -> None:
"""If PAGESEL1 is present in init_sequence, PIXFMT presence must not raise an error."""
set_core_config(
PlatformFramework.ESP32_IDF,
platform_data={KEY_BOARD: "esp32dev", KEY_VARIANT: VARIANT_ESP32},
)
cfg = {
"model": "custom",
"dc_pin": 18,
"dimensions": {"width": 320, "height": 240},
"init_sequence": [[PAGESEL1, 0x00], [PIXFMT, 0x01]],
}
# Should not raise
validated = validated_config(cfg)
assert validated is not None
def test_madctl_raises_without_pagesel(
set_core_config: SetCoreConfigCallable,
) -> None:
"""MADCTL in the init_sequence should raise when a transform is configured and
no PAGESEL/PAGESEL1 is present.
"""
set_core_config(
PlatformFramework.ESP32_IDF,
platform_data={KEY_BOARD: "esp32dev", KEY_VARIANT: VARIANT_ESP32},
)
cfg: dict[str, Any] = {
"model": "custom",
"dc_pin": 18,
"dimensions": {"width": 320, "height": 240},
"transform": {"mirror_x": True, "mirror_y": True, "swap_xy": False},
"init_sequence": [[MADCTL, 0x01]],
}
with pytest.raises(cv.Invalid, match=r"MADCTL .* in the init sequence"):
CONFIG_SCHEMA(cfg)
def test_pixfmt_raises_without_pagesel1(
set_core_config: SetCoreConfigCallable,
) -> None:
"""PIXFMT in the init_sequence should raise when no PAGESEL/PAGESEL1 is present."""
set_core_config(
PlatformFramework.ESP32_IDF,
platform_data={KEY_BOARD: "esp32dev", KEY_VARIANT: VARIANT_ESP32},
)
cfg: dict[str, Any] = {
"model": "custom",
"dc_pin": 18,
"dimensions": {"width": 320, "height": 240},
"init_sequence": [[PIXFMT, 0x01]],
}
with pytest.raises(
cv.Invalid, match=r"PIXFMT .* should not be in the init sequence"
):
CONFIG_SCHEMA(cfg)