no more error in display, but no refresh

This commit is contained in:
GW_MC
2026-01-25 15:28:07 +08:00
parent 580d6a0a5b
commit 57f698425b
3 changed files with 46 additions and 16 deletions

View File

@@ -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

View File

@@ -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 = &gt911_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;
}
}

View File

@@ -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;
}