From 57f698425b991ca5dd578ce9e496d522c5f4b0d2 Mon Sep 17 00:00:00 2001 From: GW_MC <72297530+GWMCwing@users.noreply.github.com> Date: Sun, 25 Jan 2026 15:28:07 +0800 Subject: [PATCH] no more error in display, but no refresh --- main/display/constants.h | 3 ++ main/display/display.cpp | 19 +++++++++++-- main/display/eink_display_handler.cpp | 40 ++++++++++++++++++--------- 3 files changed, 46 insertions(+), 16 deletions(-) diff --git a/main/display/constants.h b/main/display/constants.h index da77ac1..d41bfb0 100644 --- a/main/display/constants.h +++ b/main/display/constants.h @@ -9,3 +9,6 @@ #define PIN_RST GPIO_NUM_8 #define PIN_DC GPIO_NUM_9 #define PIN_CS GPIO_NUM_10 +#define PIN_MOSI GPIO_NUM_11 +#define PIN_SCK GPIO_NUM_12 +#define PIN_TOUCH_RST GPIO_NUM_13 diff --git a/main/display/display.cpp b/main/display/display.cpp index 56938de..4ee2e0b 100644 --- a/main/display/display.cpp +++ b/main/display/display.cpp @@ -1,6 +1,7 @@ #include "display/display.h" #include "common/constants.h" #include "esp_log.h" +#include "esp_lcd_touch_gt911.h" DisplayHandler::~DisplayHandler() { if (_spi_mutex != nullptr) { @@ -124,6 +125,7 @@ void DisplayHandler::_epd_init(void) { void DisplayHandler::_touch_init(void) { ESP_LOGI("DisplayHandler", "Initializing touch..."); + // 1. Initialize I2C Bus i2c_config_t conf = {}; conf.mode = I2C_MODE_MASTER; @@ -152,12 +154,23 @@ void DisplayHandler::_touch_init(void) { tp_io_config.flags = default_tp_io_config.flags; esp_lcd_new_panel_io_i2c(I2C_NUM_0, &tp_io_config, &_tp_io_handle); + // GT911-specific config with I2C address (0x5D = INT low during reset) + static esp_lcd_touch_io_gt911_config_t gt911_config = { + .dev_addr = ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS // 0x5D + }; + esp_lcd_touch_config_t tp_cfg = {}; tp_cfg.x_max = 800; tp_cfg.y_max = 480; - tp_cfg.rst_gpio_num = PIN_RST; + tp_cfg.rst_gpio_num = PIN_TOUCH_RST; tp_cfg.int_gpio_num = PIN_TOUCH_IRQ; + tp_cfg.driver_data = >911_config; // Pass GT911-specific config for automatic reset - esp_lcd_touch_new_i2c_gt911(_tp_io_handle, &tp_cfg, &_tp_handle); - ESP_LOGI("DisplayHandler", "GT911 touch controller initialized"); + esp_err_t touch_ret = esp_lcd_touch_new_i2c_gt911(_tp_io_handle, &tp_cfg, &_tp_handle); + if (touch_ret == ESP_OK && _tp_handle != nullptr) { + ESP_LOGI("DisplayHandler", "GT911 touch controller initialized successfully"); + } else { + ESP_LOGE("DisplayHandler", "GT911 touch controller initialization failed: %s", esp_err_to_name(touch_ret)); + _tp_handle = nullptr; + } } diff --git a/main/display/eink_display_handler.cpp b/main/display/eink_display_handler.cpp index 2f9a7b5..24cc767 100644 --- a/main/display/eink_display_handler.cpp +++ b/main/display/eink_display_handler.cpp @@ -107,6 +107,12 @@ void EInkDisplayHandler::init() { } memset(_framebuffer, 0xFF, DISPLAY_BUFFER_SIZE); // Initialize to white + // Perform initial full refresh to clear display BEFORE creating LVGL display + // This prevents LVGL from trying to render during the initial clear + ESP_LOGI(TAG, "Performing initial display clear..."); + _perform_full_refresh(_framebuffer); + ESP_LOGI(TAG, "Initial display clear complete"); + // Create LVGL display manually (no esp_lcd panel for e-paper) lv_display_t* disp = lv_display_create(DISPLAY_WIDTH, DISPLAY_HEIGHT); if (disp == nullptr) { @@ -160,10 +166,6 @@ void EInkDisplayHandler::init() { ESP_LOGI(TAG, "LVGL touch input registered"); } - // Perform initial full refresh to clear display - ESP_LOGI(TAG, "Performing initial display clear..."); - _perform_full_refresh(_framebuffer); - // Set display ready bits xEventGroupSetBits(_system_event_group, DISPLAY_READY_BIT | TOUCH_CALIBRATED_BIT); ESP_LOGI(TAG, "E-Ink display handler initialized successfully"); @@ -290,6 +292,7 @@ void EInkDisplayHandler::_lvgl_touch_read_cb(lv_indev_t* indev, lv_indev_data_t* esp_lcd_touch_get_data(tp_handle, point_data, &touch_cnt, 1); if (touch_cnt > 0) { + ESP_LOGI(TAG, "Touch data read successfully: x=%d, y=%d", point_data[0].x, point_data[0].y); data->point.x = point_data[0].x; data->point.y = point_data[0].y; data->state = LV_INDEV_STATE_PRESSED; @@ -344,17 +347,17 @@ void EInkDisplayHandler::_perform_full_refresh(const uint8_t* framebuffer) { xSemaphoreGive(_spi_mutex); - // Step 2: Write new data (0x13) with data inversion + // Step 2: Write new data (0x13) epd_write_cmd(0x13); xSemaphoreTake(_spi_mutex, portMAX_DELAY); gpio_set_level(PIN_DC, 1); // Data mode - // Use queued transactions with inverted framebuffer data - static uint8_t tx_buffer[100]; // Buffer for batch of inverted bytes + // Use queued transactions with framebuffer data + static uint8_t tx_buffer[100]; // Buffer for batch of bytes for (size_t i = 0; i < DISPLAY_BUFFER_SIZE; i++) { size_t buf_idx = i % 100; - tx_buffer[buf_idx] = ~framebuffer[i]; // Invert data per manufacturer spec + tx_buffer[buf_idx] = framebuffer[i]; // Write data directly (no inversion) spi_transaction_t t = {}; t.length = 8; @@ -415,18 +418,29 @@ void EInkDisplayHandler::_perform_partial_refresh(const uint8_t* framebuffer) { }; epd_write_cmd_with_data(0x90, window_data, 9); - // Step 4: Write new data with inversion (0x13 command) + // Step 4: Write new data (0x13 command) epd_write_cmd(0x13); xSemaphoreTake(_spi_mutex, portMAX_DELAY); gpio_set_level(PIN_DC, 1); // Data mode + // Send data in chunks with task yields to prevent blocking + static uint8_t tx_byte; + const size_t CHUNK_SIZE = 1000; // Send 1000 bytes between yields for (size_t i = 0; i < DISPLAY_BUFFER_SIZE; i++) { + tx_byte = framebuffer[i]; // Write data directly (no inversion) spi_transaction_t t = {}; t.length = 8; - uint8_t byte = ~framebuffer[i]; // Invert data per manufacturer spec - t.tx_buffer = &byte; + t.tx_buffer = &tx_byte; spi_device_polling_transmit(_spi, &t); + + // Yield to other tasks every CHUNK_SIZE bytes + if (i % CHUNK_SIZE == (CHUNK_SIZE - 1)) { + xSemaphoreGive(_spi_mutex); + vTaskDelay(1); // Allow other tasks to run + xSemaphoreTake(_spi_mutex, portMAX_DELAY); + gpio_set_level(PIN_DC, 1); // Re-set data mode after yield + } } xSemaphoreGive(_spi_mutex); @@ -446,10 +460,10 @@ void EInkDisplayHandler::_perform_partial_refresh(const uint8_t* framebuffer) { void EInkDisplayHandler::_wait_for_busy() { ESP_LOGI(TAG, "Waiting for display ready (BUSY pin)..."); int timeout = 0; - while (gpio_get_level(PIN_BUSY) == BUSY_INACTIVE_LEVEL) { // 0=BUSY, 1=FREE + while (gpio_get_level(PIN_BUSY) == BUSY_ACTIVE_LEVEL) { // 0=BUSY, 1=FREE vTaskDelay(pdMS_TO_TICKS(100)); timeout++; - if (timeout > 50) { // 5 second timeout + if (timeout > 100) { // 10 second timeout ESP_LOGW(TAG, "Display BUSY timeout!"); break; }