diff --git a/esphome/components/ili9xxx/display.py b/esphome/components/ili9xxx/display.py index 64f87c167c1..93c189b0a35 100644 --- a/esphome/components/ili9xxx/display.py +++ b/esphome/components/ili9xxx/display.py @@ -234,7 +234,10 @@ async def to_code(config: ConfigType) -> None: sequence = [] for seq in init_sequences: sequence.extend(seq) - cg.add(var.add_init_sequence(sequence)) + # init_lcd_() stops at a 0 command + sequence.append(0) + table = cg.shared_progmem_array("ili9xxx_init_sequence", cg.uint8, sequence) + cg.add(var.add_init_sequence(table)) if pixel_mode := config.get(CONF_PIXEL_MODE): cg.add(var.set_pixel_mode(pixel_mode)) diff --git a/esphome/components/ili9xxx/ili9xxx_display.cpp b/esphome/components/ili9xxx/ili9xxx_display.cpp index 0ed18c45da0..abec48ea03b 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.cpp +++ b/esphome/components/ili9xxx/ili9xxx_display.cpp @@ -32,7 +32,7 @@ void ILI9XXXDisplay::set_madctl() { void ILI9XXXDisplay::setup() { this->setup_pins_(); this->init_lcd_(this->init_sequence_); - this->init_lcd_(this->extra_init_sequence_.data()); + this->init_lcd_(this->extra_init_sequence_); switch (this->pixel_mode_) { case PIXEL_MODE_16: if (this->is_18bitdisplay_) { diff --git a/esphome/components/ili9xxx/ili9xxx_display.h b/esphome/components/ili9xxx/ili9xxx_display.h index 2529e54021b..0622277a4d1 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.h +++ b/esphome/components/ili9xxx/ili9xxx_display.h @@ -58,7 +58,7 @@ class ILI9XXXDisplay : public display::DisplayBuffer, } } - void add_init_sequence(const std::vector &sequence) { this->extra_init_sequence_ = sequence; } + void add_init_sequence(const uint8_t *sequence) { this->extra_init_sequence_ = sequence; } void set_dc_pin(GPIOPin *dc_pin) { dc_pin_ = dc_pin; } float get_setup_priority() const override; void set_reset_pin(GPIOPin *reset) { this->reset_pin_ = reset; } @@ -114,7 +114,8 @@ class ILI9XXXDisplay : public display::DisplayBuffer, void reset_(); uint8_t const *init_sequence_{}; - std::vector extra_init_sequence_; + // Shared PROGMEM table ending in a 0 command, like the built-in sequences + const uint8_t *extra_init_sequence_{nullptr}; int16_t width_{0}; ///< Display width as modified by current rotation int16_t height_{0}; ///< Display height as modified by current rotation int16_t offset_x_{0}; diff --git a/tests/component_tests/ili9xxx/config/init_sequence.yaml b/tests/component_tests/ili9xxx/config/init_sequence.yaml new file mode 100644 index 00000000000..31a613e41ad --- /dev/null +++ b/tests/component_tests/ili9xxx/config/init_sequence.yaml @@ -0,0 +1,31 @@ +esphome: + name: test + +esp32: + board: esp32dev + framework: + type: arduino + +spi: + clk_pin: GPIO18 + mosi_pin: GPIO23 + +display: + - platform: ili9xxx + id: first + model: ST7789V + cs_pin: GPIO5 + dc_pin: GPIO17 + invert_colors: false + init_sequence: + - [0x36, 0x48] + - [0x3A, 0x55] + - platform: ili9xxx + id: second + model: ST7789V + cs_pin: GPIO4 + dc_pin: GPIO16 + invert_colors: false + init_sequence: + - [0x36, 0x48] + - [0x3A, 0x55] diff --git a/tests/component_tests/ili9xxx/test_ili9xxx.py b/tests/component_tests/ili9xxx/test_ili9xxx.py index 3919eb3823e..b4bf8d44793 100644 --- a/tests/component_tests/ili9xxx/test_ili9xxx.py +++ b/tests/component_tests/ili9xxx/test_ili9xxx.py @@ -4,6 +4,7 @@ from __future__ import annotations from collections.abc import Callable from pathlib import Path +import re def test_ili9xxx_placement_new_uses_model_subclass( @@ -29,3 +30,19 @@ def test_ili9xxx_placement_new_uses_model_subclass( assert "new(tft_display) ili9xxx::ILI9XXXST7789V()" in main_cpp # Base-class default constructor must NOT be used. assert "new(tft_display) ili9xxx::ILI9XXXDisplay()" not in main_cpp + + +def test_extra_init_sequence_is_terminated_progmem_table( + generate_main: Callable[[str | Path], str], + component_config_path: Callable[[str], Path], +) -> None: + """A custom init sequence is a 0 terminated PROGMEM table shared by equal displays.""" + main_cpp = generate_main(component_config_path("init_sequence.yaml")) + + tables = re.findall(r"(\w+)->add_init_sequence\((\w+)\);", main_cpp) + assert {t[0] for t in tables} == {"first", "second"} + assert len({t[1] for t in tables}) == 1 + assert ( + f"static constexpr uint8_t {tables[0][1]}[] PROGMEM = {{54, 1, 72, 58, 1, 85, 0}};" + in main_cpp + )