New kernel drivers and device implementation updates (#561)

- Added modular device support and devicetree bindings for ILI9341, ILI9488, CST816S, XPT2046, and GPIO button input, updating several board configurations for display/touch/backlight/keyboard/battery.
- Added a setting to control deprecated HAL usage (device property + Kconfig).
This commit is contained in:
Ken Van Hoeylandt
2026-07-12 23:54:55 +02:00
committed by GitHub
parent 50c0a14a93
commit fa4a6e255c
148 changed files with 5837 additions and 2145 deletions
+44 -3
View File
@@ -17,6 +17,8 @@
#include <esp_lcd_panel_ops.h>
#include <esp_lcd_panel_st7789.h>
#include <freertos/semphr.h>
#include <cstdlib>
#define TAG "ST7789"
@@ -26,8 +28,22 @@
struct St7789Internal {
esp_lcd_panel_io_handle_t io_handle;
esp_lcd_panel_handle_t panel_handle;
// Given from ISR context by on_color_trans_done() once a queued SPI transfer physically
// completes. draw_bitmap() blocks on this so it can honor DisplayApi's synchronous contract
// (see lvgl_display.c: the caller reuses/overwrites the color buffer as soon as draw_bitmap
// returns) - esp_lcd_panel_draw_bitmap() itself only queues the transfer and returns early.
SemaphoreHandle_t draw_done_semaphore;
};
// Fires for every completed SPI transaction on this IO (not just draw_bitmap's color transfers -
// bring-up commands like reset/init/gap go through the same IO), called from ISR context.
static bool IRAM_ATTR on_color_trans_done(esp_lcd_panel_io_handle_t, esp_lcd_panel_io_event_data_t*, void* user_ctx) {
auto* internal = static_cast<St7789Internal*>(user_ctx);
BaseType_t high_task_woken = pdFALSE;
xSemaphoreGiveFromISR(internal->draw_done_semaphore, &high_task_woken);
return high_task_woken == pdTRUE;
}
static int pin_or_unused(const struct GpioPinSpec& pin) {
return pin.gpio_controller == nullptr ? -1 : static_cast<int>(pin.pin);
}
@@ -52,14 +68,20 @@ static error_t start(Device* device) {
return ERROR_OUT_OF_MEMORY;
}
internal->draw_done_semaphore = xSemaphoreCreateBinary();
if (internal->draw_done_semaphore == nullptr) {
free(internal);
return ERROR_OUT_OF_MEMORY;
}
esp_lcd_panel_io_spi_config_t io_config = {
.cs_gpio_num = pin_or_unused(cs_pin),
.dc_gpio_num = pin_or_unused(config->pin_dc),
.spi_mode = 0,
.pclk_hz = config->pixel_clock_hz,
.trans_queue_depth = config->transaction_queue_depth,
.on_color_trans_done = nullptr,
.user_ctx = nullptr,
.on_color_trans_done = on_color_trans_done,
.user_ctx = internal,
.lcd_cmd_bits = 8,
.lcd_param_bits = 8,
.cs_ena_pretrans = 0,
@@ -79,6 +101,7 @@ static error_t start(Device* device) {
esp_err_t ret = esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)spi_config->host, &io_config, &internal->io_handle);
if (ret != ESP_OK) {
LOG_E(TAG, "Failed to create panel IO: %s", esp_err_to_name(ret));
vSemaphoreDelete(internal->draw_done_semaphore);
free(internal);
return ERROR_RESOURCE;
}
@@ -96,6 +119,7 @@ static error_t start(Device* device) {
if (ret != ESP_OK) {
LOG_E(TAG, "Failed to create panel: %s", esp_err_to_name(ret));
esp_lcd_panel_io_del(internal->io_handle);
vSemaphoreDelete(internal->draw_done_semaphore);
free(internal);
return ERROR_RESOURCE;
}
@@ -122,6 +146,7 @@ static error_t start(Device* device) {
LOG_E(TAG, "Failed to bring up panel");
esp_lcd_panel_del(internal->panel_handle);
esp_lcd_panel_io_del(internal->io_handle);
vSemaphoreDelete(internal->draw_done_semaphore);
free(internal);
return ERROR_RESOURCE;
}
@@ -142,6 +167,7 @@ static error_t stop(Device* device) {
return ERROR_RESOURCE;
}
vSemaphoreDelete(internal->draw_done_semaphore);
free(internal);
return ERROR_NONE;
}
@@ -162,7 +188,22 @@ static error_t st7789_init(Device* device) {
static error_t st7789_draw_bitmap(Device* device, int32_t x_start, int32_t y_start, int32_t x_end, int32_t y_end, const void* color_data) {
auto* internal = static_cast<St7789Internal*>(device_get_driver_data(device));
return esp_lcd_panel_draw_bitmap(internal->panel_handle, x_start, y_start, x_end, y_end, color_data) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE;
// Drain any stale signal left over from a prior non-draw transaction (bring-up commands like
// reset/gap also complete through on_color_trans_done), so the take() below can only be
// satisfied by this draw's own transfer completing.
xSemaphoreTake(internal->draw_done_semaphore, 0);
if (esp_lcd_panel_draw_bitmap(internal->panel_handle, x_start, y_start, x_end, y_end, color_data) != ESP_OK) {
return ERROR_RESOURCE;
}
// Block until the SPI transfer physically completes: DisplayApi's draw_bitmap is a synchronous
// contract (see lvgl_display.c), so the caller must be able to safely reuse/overwrite
// color_data as soon as this call returns. esp_lcd_panel_draw_bitmap() only queues the
// transfer and returns once it's handed to the SPI peripheral, not once it's finished.
xSemaphoreTake(internal->draw_done_semaphore, portMAX_DELAY);
return ERROR_NONE;
}
static error_t st7789_mirror(Device* device, bool x_axis, bool y_axis) {