From 58385bebff34b4f3b2acc3c9ca54b7395499b3ca Mon Sep 17 00:00:00 2001 From: Ryan Gammon Date: Fri, 24 Jul 2026 19:57:17 -0700 Subject: [PATCH] [mipi_spi] Add ST77916 / ESP-VoCat model (#17679) --- esphome/components/mipi_spi/models/st77916.py | 269 ++++++++++++++++++ 1 file changed, 269 insertions(+) create mode 100644 esphome/components/mipi_spi/models/st77916.py diff --git a/esphome/components/mipi_spi/models/st77916.py b/esphome/components/mipi_spi/models/st77916.py new file mode 100644 index 0000000000..38852f135f --- /dev/null +++ b/esphome/components/mipi_spi/models/st77916.py @@ -0,0 +1,269 @@ +# Init sequence sourced from Espressif's esp-bsp repository: +# https://github.com/espressif/esp-bsp/blob/master/bsp/esp_vocat/priv_include/disp_init_data.h +# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Apache-2.0 + +from esphome.components.mipi import MODE_RGB, DriverChip +from esphome.components.spi import TYPE_QUAD +from esphome.const import CONF_INVERTED, CONF_NUMBER + +# Init sequence for the ST77916 QSPI display on the ESP-VoCat v1.2 board. +# Source: disp_init_data.h from espressif/esp-bsp (bsp/esp_vocat/priv_include). +# The standard INVON/INVOFF and SLPOUT+DISPON commands (and required delays) are omitted because +# the mipi_spi framework appends them automatically based on the invert_colors and no_slpout settings. +# (So this sequence only contains panel-specific setup commands.) +_ESP_VOCAT_INIT = ( + # Page 1a — startup unlock + (0xF0, 0x28), + (0xF2, 0x28), + (0x73, 0xF0), + (0x7C, 0xD1), + (0x83, 0xE0), + (0x84, 0x61), + (0xF2, 0x82), + # Switch to page 0 → page 1 + (0xF0, 0x00), + (0xF0, 0x01), + (0xF1, 0x01), + # Power settings (Bx) + (0xB0, 0x56), + (0xB1, 0x4D), + (0xB2, 0x24), + (0xB4, 0x87), + (0xB5, 0x44), + (0xB6, 0x8B), + (0xB7, 0x40), + (0xB8, 0x86), + (0xBA, 0x00), + (0xBB, 0x08), + (0xBC, 0x08), + (0xBD, 0x00), + # VCOM / gate settings (Cx) + (0xC0, 0x80), + (0xC1, 0x10), + (0xC2, 0x37), + (0xC3, 0x80), + (0xC4, 0x10), + (0xC5, 0x37), + (0xC6, 0xA9), + (0xC7, 0x41), + (0xC8, 0x01), + (0xC9, 0xA9), + (0xCA, 0x41), + (0xCB, 0x01), + # Source settings (Dx) + (0xD0, 0x91), + (0xD1, 0x68), + (0xD2, 0x68), + # Misc + (0xF5, 0x00, 0xA5), + (0xDD, 0x4F), + (0xDE, 0x4F), + (0xF1, 0x10), + (0xF0, 0x00), + # Switch to page 2 — gamma + (0xF0, 0x02), + ( + 0xE0, + 0xF0, + 0x0A, + 0x10, + 0x09, + 0x09, + 0x36, + 0x35, + 0x33, + 0x4A, + 0x29, + 0x15, + 0x15, + 0x2E, + 0x34, + ), + ( + 0xE1, + 0xF0, + 0x0A, + 0x0F, + 0x08, + 0x08, + 0x05, + 0x34, + 0x33, + 0x4A, + 0x39, + 0x15, + 0x15, + 0x2D, + 0x33, + ), + # Switch to page 10 — GIP / timing + (0xF0, 0x10), + (0xF3, 0x10), + # Page 10: Exxx + (0xE0, 0x07), + (0xE1, 0x00), + (0xE2, 0x00), + (0xE3, 0x00), + (0xE4, 0xE0), + (0xE5, 0x06), + (0xE6, 0x21), + (0xE7, 0x01), + (0xE8, 0x05), + (0xE9, 0x02), + (0xEA, 0xDA), + (0xEB, 0x00), + (0xEC, 0x00), + (0xED, 0x0F), + (0xEE, 0x00), + (0xEF, 0x00), + # Page 10: Fxxx + (0xF8, 0x00), + (0xF9, 0x00), + (0xFA, 0x00), + (0xFB, 0x00), + (0xFC, 0x00), + (0xFD, 0x00), + (0xFE, 0x00), + (0xFF, 0x00), + # GIP section A (0x60–0x6B) + (0x60, 0x40), + (0x61, 0x04), + (0x62, 0x00), + (0x63, 0x42), + (0x64, 0xD9), + (0x65, 0x00), + (0x66, 0x00), + (0x67, 0x00), + (0x68, 0x00), + (0x69, 0x00), + (0x6A, 0x00), + (0x6B, 0x00), + # GIP section B (0x70–0x7B) + (0x70, 0x40), + (0x71, 0x03), + (0x72, 0x00), + (0x73, 0x42), + (0x74, 0xD8), + (0x75, 0x00), + (0x76, 0x00), + (0x77, 0x00), + (0x78, 0x00), + (0x79, 0x00), + (0x7A, 0x00), + (0x7B, 0x00), + # GIP timing (0x80–0x9F) + (0x80, 0x48), + (0x81, 0x00), + (0x82, 0x06), + (0x83, 0x02), + (0x84, 0xD6), + (0x85, 0x04), + (0x86, 0x00), + (0x87, 0x00), + (0x88, 0x48), + (0x89, 0x00), + (0x8A, 0x08), + (0x8B, 0x02), + (0x8C, 0xD8), + (0x8D, 0x04), + (0x8E, 0x00), + (0x8F, 0x00), + (0x90, 0x48), + (0x91, 0x00), + (0x92, 0x0A), + (0x93, 0x02), + (0x94, 0xDA), + (0x95, 0x04), + (0x96, 0x00), + (0x97, 0x00), + (0x98, 0x48), + (0x99, 0x00), + (0x9A, 0x0C), + (0x9B, 0x02), + (0x9C, 0xDC), + (0x9D, 0x04), + (0x9E, 0x00), + (0x9F, 0x00), + # GIP timing (0xA0–0xBF) + (0xA0, 0x48), + (0xA1, 0x00), + (0xA2, 0x05), + (0xA3, 0x02), + (0xA4, 0xD5), + (0xA5, 0x04), + (0xA6, 0x00), + (0xA7, 0x00), + (0xA8, 0x48), + (0xA9, 0x00), + (0xAA, 0x07), + (0xAB, 0x02), + (0xAC, 0xD7), + (0xAD, 0x04), + (0xAE, 0x00), + (0xAF, 0x00), + (0xB0, 0x48), + (0xB1, 0x00), + (0xB2, 0x09), + (0xB3, 0x02), + (0xB4, 0xD9), + (0xB5, 0x04), + (0xB6, 0x00), + (0xB7, 0x00), + (0xB8, 0x48), + (0xB9, 0x00), + (0xBA, 0x0B), + (0xBB, 0x02), + (0xBC, 0xDB), + (0xBD, 0x04), + (0xBE, 0x00), + (0xBF, 0x00), + # Source timing (0xC0–0xC9) + (0xC0, 0x10), + (0xC1, 0x47), + (0xC2, 0x56), + (0xC3, 0x65), + (0xC4, 0x74), + (0xC5, 0x88), + (0xC6, 0x99), + (0xC7, 0x01), + (0xC8, 0xBB), + (0xC9, 0xAA), + # Source timing (0xD0–0xD9) + (0xD0, 0x10), + (0xD1, 0x47), + (0xD2, 0x56), + (0xD3, 0x65), + (0xD4, 0x74), + (0xD5, 0x88), + (0xD6, 0x99), + (0xD7, 0x01), + (0xD8, 0xBB), + (0xD9, 0xAA), + # Finalise page 10, return to page 0 + (0xF3, 0x01), + (0xF0, 0x00), + # INVON (0x21) and SLPOUT (0x11) are appended by the framework. +) + +DriverChip( + "ESP-VOCAT", + width=360, + height=360, + # SPI pins for the ESP-VoCat v1.2 board. + # PCLK (GPIO18) and data pins (GPIO46/13/11/12) are configured on the spi: bus. + cs_pin=14, + # RST is active-HIGH on this panel; invert the ESPHome pin so the framework's + # active-low reset pulse (HIGH→LOW→HIGH) maps to the correct physical sequence + # (LOW→HIGH→LOW) on the wire. + reset_pin={CONF_NUMBER: 47, CONF_INVERTED: True}, + # Note: GPIO9 behaviour varies by board revision (may be POWER_CTRL, not LCD_EN). + # Do not set a default enable_pin — manage LCD power in on_boot if needed. + # GPIO44 is the backlight; manage it separately via an output: or light:. + bus_mode=TYPE_QUAD, + data_rate="80MHz", + invert_colors=True, + color_order=MODE_RGB, + requires={"psram"}, + initsequence=_ESP_VOCAT_INIT, +)