no more error in display, but no refresh
This commit is contained in:
@@ -9,3 +9,6 @@
|
|||||||
#define PIN_RST GPIO_NUM_8
|
#define PIN_RST GPIO_NUM_8
|
||||||
#define PIN_DC GPIO_NUM_9
|
#define PIN_DC GPIO_NUM_9
|
||||||
#define PIN_CS GPIO_NUM_10
|
#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
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "display/display.h"
|
#include "display/display.h"
|
||||||
#include "common/constants.h"
|
#include "common/constants.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
|
#include "esp_lcd_touch_gt911.h"
|
||||||
|
|
||||||
DisplayHandler::~DisplayHandler() {
|
DisplayHandler::~DisplayHandler() {
|
||||||
if (_spi_mutex != nullptr) {
|
if (_spi_mutex != nullptr) {
|
||||||
@@ -124,6 +125,7 @@ void DisplayHandler::_epd_init(void) {
|
|||||||
|
|
||||||
void DisplayHandler::_touch_init(void) {
|
void DisplayHandler::_touch_init(void) {
|
||||||
ESP_LOGI("DisplayHandler", "Initializing touch...");
|
ESP_LOGI("DisplayHandler", "Initializing touch...");
|
||||||
|
|
||||||
// 1. Initialize I2C Bus
|
// 1. Initialize I2C Bus
|
||||||
i2c_config_t conf = {};
|
i2c_config_t conf = {};
|
||||||
conf.mode = I2C_MODE_MASTER;
|
conf.mode = I2C_MODE_MASTER;
|
||||||
@@ -152,12 +154,23 @@ void DisplayHandler::_touch_init(void) {
|
|||||||
tp_io_config.flags = default_tp_io_config.flags;
|
tp_io_config.flags = default_tp_io_config.flags;
|
||||||
esp_lcd_new_panel_io_i2c(I2C_NUM_0, &tp_io_config, &_tp_io_handle);
|
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 = {};
|
esp_lcd_touch_config_t tp_cfg = {};
|
||||||
tp_cfg.x_max = 800;
|
tp_cfg.x_max = 800;
|
||||||
tp_cfg.y_max = 480;
|
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.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_err_t touch_ret = esp_lcd_touch_new_i2c_gt911(_tp_io_handle, &tp_cfg, &_tp_handle);
|
||||||
ESP_LOGI("DisplayHandler", "GT911 touch controller initialized");
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,6 +107,12 @@ void EInkDisplayHandler::init() {
|
|||||||
}
|
}
|
||||||
memset(_framebuffer, 0xFF, DISPLAY_BUFFER_SIZE); // Initialize to white
|
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)
|
// Create LVGL display manually (no esp_lcd panel for e-paper)
|
||||||
lv_display_t* disp = lv_display_create(DISPLAY_WIDTH, DISPLAY_HEIGHT);
|
lv_display_t* disp = lv_display_create(DISPLAY_WIDTH, DISPLAY_HEIGHT);
|
||||||
if (disp == nullptr) {
|
if (disp == nullptr) {
|
||||||
@@ -160,10 +166,6 @@ void EInkDisplayHandler::init() {
|
|||||||
ESP_LOGI(TAG, "LVGL touch input registered");
|
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
|
// Set display ready bits
|
||||||
xEventGroupSetBits(_system_event_group, DISPLAY_READY_BIT | TOUCH_CALIBRATED_BIT);
|
xEventGroupSetBits(_system_event_group, DISPLAY_READY_BIT | TOUCH_CALIBRATED_BIT);
|
||||||
ESP_LOGI(TAG, "E-Ink display handler initialized successfully");
|
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);
|
esp_lcd_touch_get_data(tp_handle, point_data, &touch_cnt, 1);
|
||||||
|
|
||||||
if (touch_cnt > 0) {
|
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.x = point_data[0].x;
|
||||||
data->point.y = point_data[0].y;
|
data->point.y = point_data[0].y;
|
||||||
data->state = LV_INDEV_STATE_PRESSED;
|
data->state = LV_INDEV_STATE_PRESSED;
|
||||||
@@ -344,17 +347,17 @@ void EInkDisplayHandler::_perform_full_refresh(const uint8_t* framebuffer) {
|
|||||||
|
|
||||||
xSemaphoreGive(_spi_mutex);
|
xSemaphoreGive(_spi_mutex);
|
||||||
|
|
||||||
// Step 2: Write new data (0x13) with data inversion
|
// Step 2: Write new data (0x13)
|
||||||
epd_write_cmd(0x13);
|
epd_write_cmd(0x13);
|
||||||
|
|
||||||
xSemaphoreTake(_spi_mutex, portMAX_DELAY);
|
xSemaphoreTake(_spi_mutex, portMAX_DELAY);
|
||||||
gpio_set_level(PIN_DC, 1); // Data mode
|
gpio_set_level(PIN_DC, 1); // Data mode
|
||||||
|
|
||||||
// Use queued transactions with inverted framebuffer data
|
// Use queued transactions with framebuffer data
|
||||||
static uint8_t tx_buffer[100]; // Buffer for batch of inverted bytes
|
static uint8_t tx_buffer[100]; // Buffer for batch of bytes
|
||||||
for (size_t i = 0; i < DISPLAY_BUFFER_SIZE; i++) {
|
for (size_t i = 0; i < DISPLAY_BUFFER_SIZE; i++) {
|
||||||
size_t buf_idx = i % 100;
|
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 = {};
|
spi_transaction_t t = {};
|
||||||
t.length = 8;
|
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);
|
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);
|
epd_write_cmd(0x13);
|
||||||
|
|
||||||
xSemaphoreTake(_spi_mutex, portMAX_DELAY);
|
xSemaphoreTake(_spi_mutex, portMAX_DELAY);
|
||||||
gpio_set_level(PIN_DC, 1); // Data mode
|
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++) {
|
for (size_t i = 0; i < DISPLAY_BUFFER_SIZE; i++) {
|
||||||
|
tx_byte = framebuffer[i]; // Write data directly (no inversion)
|
||||||
spi_transaction_t t = {};
|
spi_transaction_t t = {};
|
||||||
t.length = 8;
|
t.length = 8;
|
||||||
uint8_t byte = ~framebuffer[i]; // Invert data per manufacturer spec
|
t.tx_buffer = &tx_byte;
|
||||||
t.tx_buffer = &byte;
|
|
||||||
spi_device_polling_transmit(_spi, &t);
|
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);
|
xSemaphoreGive(_spi_mutex);
|
||||||
|
|
||||||
@@ -446,10 +460,10 @@ void EInkDisplayHandler::_perform_partial_refresh(const uint8_t* framebuffer) {
|
|||||||
void EInkDisplayHandler::_wait_for_busy() {
|
void EInkDisplayHandler::_wait_for_busy() {
|
||||||
ESP_LOGI(TAG, "Waiting for display ready (BUSY pin)...");
|
ESP_LOGI(TAG, "Waiting for display ready (BUSY pin)...");
|
||||||
int timeout = 0;
|
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));
|
vTaskDelay(pdMS_TO_TICKS(100));
|
||||||
timeout++;
|
timeout++;
|
||||||
if (timeout > 50) { // 5 second timeout
|
if (timeout > 100) { // 10 second timeout
|
||||||
ESP_LOGW(TAG, "Display BUSY timeout!");
|
ESP_LOGW(TAG, "Display BUSY timeout!");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user