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_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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user