From 83b38d9cdd771fbcd0be055637d063a5419e28fd Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 2 Oct 2026 20:55:04 -0500 Subject: [PATCH] [st7701s] Keep the init sequence in a shared PROGMEM table --- esphome/components/st7701s/display.py | 3 +- esphome/components/st7701s/st7701s.cpp | 4 +- esphome/components/st7701s/st7701s.h | 9 ++- tests/component_tests/st7701s/__init__.py | 0 .../st7701s/test_init_sequence.py | 61 +++++++++++++++++++ 5 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 tests/component_tests/st7701s/__init__.py create mode 100644 tests/component_tests/st7701s/test_init_sequence.py diff --git a/esphome/components/st7701s/display.py b/esphome/components/st7701s/display.py index 16d7ef8e862..fc45419d17d 100644 --- a/esphome/components/st7701s/display.py +++ b/esphome/components/st7701s/display.py @@ -181,7 +181,8 @@ async def to_code(config: ConfigType) -> None: sequence = [] for seq in config[CONF_INIT_SEQUENCE]: sequence.extend(seq) - cg.add(var.set_init_sequence(sequence)) + table = cg.shared_progmem_array("st7701s_init_sequence", cg.uint8, sequence) + cg.add(var.set_init_sequence(table, len(sequence))) cg.add(var.set_color_mode(COLOR_ORDERS[config[CONF_COLOR_ORDER]])) cg.add(var.set_invert_colors(config[CONF_INVERT_COLORS])) cg.add(var.set_hsync_pulse_width(config[CONF_HSYNC_PULSE_WIDTH])) diff --git a/esphome/components/st7701s/st7701s.cpp b/esphome/components/st7701s/st7701s.cpp index 47b200c2de6..25ae3d93d84 100644 --- a/esphome/components/st7701s/st7701s.cpp +++ b/esphome/components/st7701s/st7701s.cpp @@ -144,14 +144,14 @@ void ST7701S::write_sequence_(uint8_t cmd, size_t len, const uint8_t *bytes) { } void ST7701S::write_init_sequence_() { - for (size_t i = 0; i != this->init_sequence_.size();) { + for (size_t i = 0; i != this->init_sequence_len_;) { uint8_t cmd = this->init_sequence_[i++]; size_t len = this->init_sequence_[i++]; if (len == ST7701S_DELAY_FLAG) { ESP_LOGV(TAG, "Delay %dms", cmd); delay(cmd); } else { - this->write_sequence_(cmd, len, &this->init_sequence_[i]); + this->write_sequence_(cmd, len, this->init_sequence_ + i); i += len; ESP_LOGV(TAG, "Command %X, %d bytes", cmd, len); if (cmd == SW_RESET_CMD) diff --git a/esphome/components/st7701s/st7701s.h b/esphome/components/st7701s/st7701s.h index d44f8c68590..c7b60d0b726 100644 --- a/esphome/components/st7701s/st7701s.h +++ b/esphome/components/st7701s/st7701s.h @@ -62,7 +62,10 @@ class ST7701S final : public display::Display, void set_vsync_pulse_width(uint16_t vsync_pulse_width) { this->vsync_pulse_width_ = vsync_pulse_width; } void set_vsync_back_porch(uint16_t vsync_back_porch) { this->vsync_back_porch_ = vsync_back_porch; } void set_vsync_front_porch(uint16_t vsync_front_porch) { this->vsync_front_porch_ = vsync_front_porch; } - void set_init_sequence(const std::vector &init_sequence) { this->init_sequence_ = init_sequence; } + void set_init_sequence(const uint8_t *init_sequence, size_t len) { + this->init_sequence_ = init_sequence; + this->init_sequence_len_ = len; + } void set_mirror_x(bool mirror_x) { this->mirror_x_ = mirror_x; } void set_mirror_y(bool mirror_y) { this->mirror_y_ = mirror_y; } void set_offsets(int16_t offset_x, int16_t offset_y) { @@ -95,7 +98,9 @@ class ST7701S final : public display::Display, uint16_t vsync_pulse_width_ = 10; uint16_t vsync_back_porch_ = 10; uint16_t vsync_front_porch_ = 10; - std::vector init_sequence_; + // Shared PROGMEM table + const uint8_t *init_sequence_{nullptr}; + size_t init_sequence_len_{0}; uint32_t pclk_frequency_ = 16 * 1000 * 1000; bool pclk_inverted_{true}; diff --git a/tests/component_tests/st7701s/__init__.py b/tests/component_tests/st7701s/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/component_tests/st7701s/test_init_sequence.py b/tests/component_tests/st7701s/test_init_sequence.py new file mode 100644 index 00000000000..f4dd614aadb --- /dev/null +++ b/tests/component_tests/st7701s/test_init_sequence.py @@ -0,0 +1,61 @@ +"""Tests for the st7701s init sequence codegen.""" + +from collections.abc import Callable +from pathlib import Path +import re + +_YAML = """ +esphome: + name: st7701s-test +esp32: + board: esp32-s3-devkitc-1 + framework: + type: esp-idf +psram: + mode: octal +spi: + clk_pin: 10 + mosi_pin: 11 +display: +{displays} +""" + +_DISPLAY = """ + - platform: st7701s + id: {display_id} + dimensions: + width: 480 + height: 480 + cs_pin: {cs_pin} + de_pin: 18 + hsync_pin: 16 + vsync_pin: 17 + pclk_pin: 21 + init_sequence: + - 1 + - [0x23, 0xA, 0xB] + - delay 20ms + data_pins: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 13, 14, 15, 38, 39] +""" + + +def test_init_sequence_is_progmem_table( + generate_main: Callable[[str | Path], str], + tmp_path: Path, +) -> None: + """The init sequence is a PROGMEM table instead of a vector copied at boot.""" + yaml_file = tmp_path / "st7701s.yaml" + yaml_file.write_text( + _YAML.format(displays=_DISPLAY.format(display_id="panel", cs_pin=44)) + ) + + main_cpp = generate_main(yaml_file) + + call = re.search(r"panel->set_init_sequence\((\w+), (\d+)\);", main_cpp) + assert call is not None + table = re.search( + rf"static constexpr uint8_t {call.group(1)}\[\] PROGMEM = \{{([^;]*)\}};", + main_cpp, + ) + assert table is not None + assert len(table.group(1).split(",")) == int(call.group(2))