Fix touch screen not responding, but screen still not refreshed.
This commit is contained in:
@@ -3,6 +3,9 @@
|
||||
#include "esp_log.h"
|
||||
#include "esp_lcd_touch_gt911.h"
|
||||
|
||||
#define BUSY_ACTIVE_LEVEL 0 // BUSY pin is active low
|
||||
#define BUSY_INACTIVE_LEVEL 1
|
||||
|
||||
DisplayHandler::~DisplayHandler() {
|
||||
if (_spi_mutex != nullptr) {
|
||||
vSemaphoreDelete(_spi_mutex);
|
||||
@@ -32,7 +35,10 @@ void DisplayHandler::init_devices(bool set_display_ready /*= true*/) {
|
||||
|
||||
void DisplayHandler::epd_write_cmd(uint8_t cmd) {
|
||||
ESP_LOGI("DisplayHandler", "epd_write_cmd: waiting to send 0x%02X", cmd);
|
||||
xSemaphoreTake(_spi_mutex, portMAX_DELAY);
|
||||
if (xSemaphoreTake(_spi_mutex, pdMS_TO_TICKS(5000)) != pdTRUE) {
|
||||
ESP_LOGE("DisplayHandler", "SPI mutex timeout for cmd 0x%02X", cmd);
|
||||
return;
|
||||
}
|
||||
_dangerous_epd_write_cmd_without_lock(cmd);
|
||||
xSemaphoreGive(_spi_mutex);
|
||||
ESP_LOGI("DisplayHandler", "epd_write_cmd: 0x%02X done", cmd);
|
||||
@@ -40,7 +46,10 @@ void DisplayHandler::epd_write_cmd(uint8_t cmd) {
|
||||
|
||||
void DisplayHandler::epd_write_data(uint8_t data) {
|
||||
ESP_LOGI("DisplayHandler", "epd_write_data: waiting to send 0x%02X", data);
|
||||
xSemaphoreTake(_spi_mutex, portMAX_DELAY);
|
||||
if (xSemaphoreTake(_spi_mutex, pdMS_TO_TICKS(5000)) != pdTRUE) {
|
||||
ESP_LOGE("DisplayHandler", "SPI mutex timeout for data 0x%02X", data);
|
||||
return;
|
||||
}
|
||||
_dangerous_epd_write_data_without_lock(data);
|
||||
xSemaphoreGive(_spi_mutex);
|
||||
ESP_LOGI("DisplayHandler", "epd_write_data: 0x%02X done", data);
|
||||
@@ -48,7 +57,10 @@ void DisplayHandler::epd_write_data(uint8_t data) {
|
||||
|
||||
void DisplayHandler::epd_write_cmd_with_data(uint8_t cmd, const uint8_t* data, size_t data_len) {
|
||||
ESP_LOGI("DisplayHandler", "epd_write_cmd_with_data: waiting to send cmd 0x%02X with %u bytes of data", cmd, (unsigned)data_len);
|
||||
xSemaphoreTake(_spi_mutex, portMAX_DELAY);
|
||||
if (xSemaphoreTake(_spi_mutex, pdMS_TO_TICKS(5000)) != pdTRUE) {
|
||||
ESP_LOGE("DisplayHandler", "SPI mutex timeout for cmd with data 0x%02X", cmd);
|
||||
return;
|
||||
}
|
||||
_dangerous_epd_write_cmd_without_lock(cmd);
|
||||
for (size_t i = 0; i < data_len; ++i) {
|
||||
_dangerous_epd_write_data_without_lock(data[i]);
|
||||
@@ -108,7 +120,7 @@ void DisplayHandler::_epd_init(void) {
|
||||
|
||||
// Check BUSY pin
|
||||
ESP_LOGI("DisplayHandler", "Waiting for EPD to be ready...");
|
||||
while (gpio_get_level(PIN_BUSY) == 0) { // 0=BUSY, 1=FREE
|
||||
while (gpio_get_level(PIN_BUSY) == BUSY_ACTIVE_LEVEL) { // BUSY is active LOW
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
}
|
||||
ESP_LOGI("DisplayHandler", "EPD is ready.");
|
||||
|
||||
@@ -75,7 +75,7 @@ void EInkDisplayHandler::init() {
|
||||
|
||||
// Add SPI device
|
||||
spi_device_interface_config_t devcfg = {};
|
||||
devcfg.clock_speed_hz = 10 * 1000 * 1000; // 10 MHz (max for GDEY075T7)
|
||||
devcfg.clock_speed_hz = 6 * 1000 * 1000; // 6 MHz (reduced for reliability)
|
||||
devcfg.mode = 0; // SPI mode 0
|
||||
devcfg.spics_io_num = PIN_CS;
|
||||
devcfg.queue_size = 7; // Queue size for non-blocking transactions
|
||||
@@ -316,72 +316,84 @@ void EInkDisplayHandler::_perform_full_refresh(const uint8_t* framebuffer) {
|
||||
// Step 1: Write old data (0x10) - typically all zeros for full refresh
|
||||
epd_write_cmd(0x10);
|
||||
|
||||
xSemaphoreTake(_spi_mutex, portMAX_DELAY);
|
||||
if (xSemaphoreTake(_spi_mutex, pdMS_TO_TICKS(5000)) != pdTRUE) {
|
||||
ESP_LOGE(TAG, "SPI mutex timeout in full refresh step 1");
|
||||
return;
|
||||
}
|
||||
gpio_set_level(PIN_DC, 1); // Data mode
|
||||
|
||||
// Use queued transactions to allow task switching
|
||||
static uint8_t zero_byte = 0x00; // Static to persist across queue operations
|
||||
ESP_LOGI(TAG, "Starting SPI data transmission for old data (0x10)...");
|
||||
|
||||
// Use simpler polling transmission instead of queued to avoid complexity
|
||||
static uint8_t zero_byte = 0x00; // Static to persist
|
||||
esp_err_t ret;
|
||||
for (size_t i = 0; i < DISPLAY_BUFFER_SIZE; i++) {
|
||||
spi_transaction_t t = {};
|
||||
t.length = 8;
|
||||
t.tx_buffer = &zero_byte;
|
||||
|
||||
esp_err_t ret = spi_device_queue_trans(_spi, &t, portMAX_DELAY);
|
||||
ret = spi_device_polling_transmit(_spi, &t);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to queue SPI transaction: %s", esp_err_to_name(ret));
|
||||
ESP_LOGE(TAG, "Failed to send SPI byte %zu: %s", i, esp_err_to_name(ret));
|
||||
break;
|
||||
}
|
||||
|
||||
// Retrieve result every 100 bytes to prevent queue overflow and allow yielding
|
||||
if (i % 100 == 99) {
|
||||
for (int j = 0; j < 100; j++) {
|
||||
spi_device_get_trans_result(_spi, &rtrans, portMAX_DELAY);
|
||||
// Yield every 1000 bytes to prevent watchdog timeout
|
||||
if (i % 1000 == 999) {
|
||||
xSemaphoreGive(_spi_mutex);
|
||||
vTaskDelay(pdMS_TO_TICKS(1)); // Small delay
|
||||
if (xSemaphoreTake(_spi_mutex, pdMS_TO_TICKS(5000)) != pdTRUE) {
|
||||
ESP_LOGE(TAG, "SPI mutex timeout during yield at byte %zu", i);
|
||||
return;
|
||||
}
|
||||
gpio_set_level(PIN_DC, 1); // Re-set data mode after yield
|
||||
ESP_LOGI(TAG, "Transmitted %zu/%zu bytes (%.1f%%)", i+1, DISPLAY_BUFFER_SIZE,
|
||||
(float)(i+1) * 100.0f / DISPLAY_BUFFER_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
// Get remaining results
|
||||
for (size_t i = 0; i < (DISPLAY_BUFFER_SIZE % 100); i++) {
|
||||
spi_device_get_trans_result(_spi, &rtrans, portMAX_DELAY);
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Completed SPI data transmission for old data");
|
||||
xSemaphoreGive(_spi_mutex);
|
||||
|
||||
// Step 2: Write new data (0x13)
|
||||
epd_write_cmd(0x13);
|
||||
|
||||
xSemaphoreTake(_spi_mutex, portMAX_DELAY);
|
||||
if (xSemaphoreTake(_spi_mutex, pdMS_TO_TICKS(5000)) != pdTRUE) {
|
||||
ESP_LOGE(TAG, "SPI mutex timeout in full refresh step 2");
|
||||
return;
|
||||
}
|
||||
gpio_set_level(PIN_DC, 1); // Data mode
|
||||
|
||||
// Use queued transactions with framebuffer data
|
||||
static uint8_t tx_buffer[100]; // Buffer for batch of bytes
|
||||
ESP_LOGI(TAG, "Starting SPI data transmission for new data (0x13)...");
|
||||
|
||||
// Use polling transmission for simplicity and reliability
|
||||
for (size_t i = 0; i < DISPLAY_BUFFER_SIZE; i++) {
|
||||
size_t buf_idx = i % 100;
|
||||
tx_buffer[buf_idx] = framebuffer[i]; // Write data directly (no inversion)
|
||||
|
||||
uint8_t data_byte = framebuffer[i]; // Write data directly (no inversion)
|
||||
|
||||
spi_transaction_t t = {};
|
||||
t.length = 8;
|
||||
t.tx_buffer = &tx_buffer[buf_idx];
|
||||
t.tx_buffer = &data_byte;
|
||||
|
||||
esp_err_t ret = spi_device_queue_trans(_spi, &t, portMAX_DELAY);
|
||||
esp_err_t ret = spi_device_polling_transmit(_spi, &t);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to queue SPI transaction: %s", esp_err_to_name(ret));
|
||||
ESP_LOGE(TAG, "Failed to send SPI byte %zu: %s", i, esp_err_to_name(ret));
|
||||
break;
|
||||
}
|
||||
|
||||
// Retrieve result every 100 bytes to prevent queue overflow and allow yielding
|
||||
if (buf_idx == 99) {
|
||||
for (int j = 0; j < 100; j++) {
|
||||
spi_device_get_trans_result(_spi, &rtrans, portMAX_DELAY);
|
||||
// Yield every 1000 bytes to prevent watchdog timeout
|
||||
if (i % 1000 == 999) {
|
||||
xSemaphoreGive(_spi_mutex);
|
||||
vTaskDelay(pdMS_TO_TICKS(1)); // Small delay
|
||||
if (xSemaphoreTake(_spi_mutex, pdMS_TO_TICKS(5000)) != pdTRUE) {
|
||||
ESP_LOGE(TAG, "SPI mutex timeout during yield at byte %zu", i);
|
||||
return;
|
||||
}
|
||||
gpio_set_level(PIN_DC, 1); // Re-set data mode after yield
|
||||
ESP_LOGI(TAG, "Transmitted %zu/%zu bytes (%.1f%%)", i+1, DISPLAY_BUFFER_SIZE,
|
||||
(float)(i+1) * 100.0f / DISPLAY_BUFFER_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
// Get remaining results
|
||||
for (size_t i = 0; i < (DISPLAY_BUFFER_SIZE % 100); i++) {
|
||||
spi_device_get_trans_result(_spi, &rtrans, portMAX_DELAY);
|
||||
}
|
||||
|
||||
|
||||
ESP_LOGI(TAG, "Completed SPI data transmission for new data");
|
||||
xSemaphoreGive(_spi_mutex);
|
||||
|
||||
// Step 3: Trigger display refresh (DRF)
|
||||
@@ -421,9 +433,14 @@ void EInkDisplayHandler::_perform_partial_refresh(const uint8_t* framebuffer) {
|
||||
// Step 4: Write new data (0x13 command)
|
||||
epd_write_cmd(0x13);
|
||||
|
||||
xSemaphoreTake(_spi_mutex, portMAX_DELAY);
|
||||
if (xSemaphoreTake(_spi_mutex, pdMS_TO_TICKS(5000)) != pdTRUE) {
|
||||
ESP_LOGE(TAG, "SPI mutex timeout in partial refresh");
|
||||
return;
|
||||
}
|
||||
gpio_set_level(PIN_DC, 1); // Data mode
|
||||
|
||||
ESP_LOGI(TAG, "Starting SPI data transmission for partial refresh...");
|
||||
|
||||
// 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
|
||||
@@ -437,11 +454,17 @@ void EInkDisplayHandler::_perform_partial_refresh(const uint8_t* framebuffer) {
|
||||
// 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);
|
||||
vTaskDelay(pdMS_TO_TICKS(1)); // Allow other tasks to run
|
||||
if (xSemaphoreTake(_spi_mutex, pdMS_TO_TICKS(5000)) != pdTRUE) {
|
||||
ESP_LOGE(TAG, "SPI mutex timeout during partial refresh yield");
|
||||
return;
|
||||
}
|
||||
gpio_set_level(PIN_DC, 1); // Re-set data mode after yield
|
||||
ESP_LOGI(TAG, "Partial refresh progress: %zu/%zu bytes (%.1f%%)", i+1, DISPLAY_BUFFER_SIZE,
|
||||
(float)(i+1) * 100.0f / DISPLAY_BUFFER_SIZE);
|
||||
}
|
||||
}
|
||||
ESP_LOGI(TAG, "Completed SPI data transmission for partial refresh");
|
||||
xSemaphoreGive(_spi_mutex);
|
||||
|
||||
// Step 5: Trigger partial display refresh (DRF)
|
||||
@@ -459,16 +482,50 @@ void EInkDisplayHandler::_perform_partial_refresh(const uint8_t* framebuffer) {
|
||||
|
||||
void EInkDisplayHandler::_wait_for_busy() {
|
||||
ESP_LOGI(TAG, "Waiting for display ready (BUSY pin)...");
|
||||
ESP_LOGI(TAG, "Initial BUSY pin level: %d", gpio_get_level(PIN_BUSY));
|
||||
|
||||
int timeout = 0;
|
||||
while (gpio_get_level(PIN_BUSY) == BUSY_ACTIVE_LEVEL) { // 0=BUSY, 1=FREE
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
timeout++;
|
||||
if (timeout > 100) { // 10 second timeout
|
||||
ESP_LOGW(TAG, "Display BUSY timeout!");
|
||||
ESP_LOGE(TAG, "Display BUSY timeout! Pin level: %d", gpio_get_level(PIN_BUSY));
|
||||
ESP_LOGW(TAG, "Attempting hardware reset...");
|
||||
|
||||
// Hardware reset sequence
|
||||
gpio_set_level(PIN_RST, 0);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
gpio_set_level(PIN_RST, 1);
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
// Re-initialize display
|
||||
ESP_LOGI(TAG, "Re-initializing display after reset...");
|
||||
_epd_init();
|
||||
|
||||
// Check if reset worked
|
||||
int reset_timeout = 0;
|
||||
while (gpio_get_level(PIN_BUSY) == BUSY_ACTIVE_LEVEL) {
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
reset_timeout++;
|
||||
if (reset_timeout > 50) { // 5 second timeout after reset
|
||||
ESP_LOGE(TAG, "Display reset failed! Still busy after reset.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (gpio_get_level(PIN_BUSY) != BUSY_ACTIVE_LEVEL) {
|
||||
ESP_LOGI(TAG, "Display reset successful after %d tenths of a second", reset_timeout);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Log every 2 seconds to track progress
|
||||
if (timeout % 20 == 0) {
|
||||
ESP_LOGW(TAG, "Still waiting for BUSY pin, timeout: %d/100, level: %d",
|
||||
timeout, gpio_get_level(PIN_BUSY));
|
||||
}
|
||||
}
|
||||
ESP_LOGI(TAG, "Display ready");
|
||||
ESP_LOGI(TAG, "Display ready after %d tenths of a second", timeout);
|
||||
}
|
||||
|
||||
void EInkDisplayHandler::_convert_buffer_to_epaper(const uint8_t* lvgl_buf, uint8_t* epd_buf, size_t size) {
|
||||
|
||||
Reference in New Issue
Block a user