[ili9xxx] Keep the custom init sequence in a shared PROGMEM table

The table carries the 0 terminator init_lcd_() stops at; the vector it
replaces had none, so the loop read past its end.
This commit is contained in:
J. Nick Koston
2026-10-02 21:00:59 -05:00
parent 5c9c233568
commit 70ee367c28
5 changed files with 56 additions and 4 deletions
+4 -1
View File
@@ -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))
@@ -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_) {
+3 -2
View File
@@ -58,7 +58,7 @@ class ILI9XXXDisplay : public display::DisplayBuffer,
}
}
void add_init_sequence(const std::vector<uint8_t> &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<uint8_t> 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};
@@ -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]
@@ -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
)