Fix touch screen not responding, but screen still not refreshed.

This commit is contained in:
GW_MC
2026-01-25 15:51:49 +08:00
parent 57f698425b
commit 259660a0bc
3 changed files with 117 additions and 44 deletions

View File

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