From 392bf804a224e51b9cda16b30647251a35f17859 Mon Sep 17 00:00:00 2001 From: GW_MC <72297530+GWMCwing@users.noreply.github.com> Date: Thu, 29 Jan 2026 14:41:48 +0800 Subject: [PATCH] Fix partial refresh color inversion problem --- main/display/eink_display_handler.cpp | 70 ++++++++++++++++----------- main/display/eink_display_handler.h | 1 - 2 files changed, 43 insertions(+), 28 deletions(-) diff --git a/main/display/eink_display_handler.cpp b/main/display/eink_display_handler.cpp index c9fa818..7cc7724 100644 --- a/main/display/eink_display_handler.cpp +++ b/main/display/eink_display_handler.cpp @@ -11,6 +11,7 @@ #define DISPLAY_BUFFER_SIZE (EINK_HEIGHT* EINK_WIDTH) / 8 // 1 bit per pixels #define MINIMUM_PIN_SETUP_DELAY_MS 10 #define MINIMUM_POWER_ON_DELAY_MS 100 +#define PARTIAL_REFRESH_THRESHOLD 5 // Full refresh every N partial refreshes static uint8_t* DRAW_BUFFER; // 1 bit per pixel static uint8_t* OLD_DRAW_BUFFER; // 1 bit per pixel @@ -99,32 +100,43 @@ esp_err_t EInkDisplayHandler::deep_sleep_display(void) { esp_err_t EInkDisplayHandler::refresh_display() { esp_err_t err = ESP_OK; - { - ESP_LOGI(TAG, "Waiting for display to be idle..."); - TransactionGuard transaction_guard(this->epd_handler_); - err = transaction_guard.begin(pdMS_TO_TICKS(10000)); - if (err != ESP_OK) { - ESP_LOGE(TAG, "Failed to begin transaction for display refresh: %s", esp_err_to_name(err)); - return err; - } - if (is_deep_sleep_) { - epd_init_internal_(transaction_guard.transaction_id()); - } - epd_handler_.wait_for_idle(); - ESP_LOGI(TAG, "Starting display refresh..."); - err = epd_handler_.epd_write_cmd(0x92, transaction_guard.transaction_id()); // enter normal mode + if (is_deep_sleep_) { + + err = full_write(draw_buffer_, true); if (err != ESP_OK) { - ESP_LOGE(TAG, "Failed to enter normal mode: %s", esp_err_to_name(err)); + ESP_LOGE(TAG, "Full write failed during refresh_display: %s", esp_err_to_name(err)); return err; } - err = epd_handler_.epd_write_cmd(0x12, transaction_guard.transaction_id()); // display refresh - if (err != ESP_OK) { - ESP_LOGE(TAG, "Failed to send display refresh command: %s", esp_err_to_name(err)); - return err; + } else { + // refresh does not correctly work after recovering from deep sleep due to sram reset + { + ESP_LOGI(TAG, "Waiting for display to be idle..."); + TransactionGuard transaction_guard(this->epd_handler_); + err = transaction_guard.begin(pdMS_TO_TICKS(10000)); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to begin transaction for display refresh: %s", esp_err_to_name(err)); + return err; + } + if (is_deep_sleep_) { + epd_init_internal_(transaction_guard.transaction_id()); + } + + epd_handler_.wait_for_idle(); + ESP_LOGI(TAG, "Starting display refresh..."); + err = epd_handler_.epd_write_cmd(0x92, transaction_guard.transaction_id()); // enter normal mode + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to enter normal mode: %s", esp_err_to_name(err)); + return err; + } + err = epd_handler_.epd_write_cmd(0x12, transaction_guard.transaction_id()); // display refresh + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to send display refresh command: %s", esp_err_to_name(err)); + return err; + } + vTaskDelay(pdMS_TO_TICKS(MINIMUM_PIN_SETUP_DELAY_MS)); // at least 200us delay + epd_handler_.wait_for_idle(); } - vTaskDelay(pdMS_TO_TICKS(MINIMUM_PIN_SETUP_DELAY_MS)); // at least 200us delay - epd_handler_.wait_for_idle(); } { @@ -235,6 +247,7 @@ esp_err_t EInkDisplayHandler::partial_refresh(const uint8_t* incoming_partial_fr ESP_LOGI(TAG, "Partial refresh skipped (not last partial update)"); return ESP_OK; } + { TransactionGuard transaction_guard(this->epd_handler_); err = transaction_guard.begin(pdMS_TO_TICKS(5000)); @@ -359,7 +372,7 @@ esp_err_t EInkDisplayHandler::partial_refresh(const uint8_t* incoming_partial_fr // Send only the partial area data, not the full display buffer ESP_LOGI(TAG, "Sending new partial buffer: %zu bytes (area: %dx%d)", partial_buffer_size, area_width_bytes * 8, area_height); - err = epd_handler_.transfer_spi_data(partial_buffer, partial_buffer_size, transaction_guard.transaction_id()); + err = epd_handler_.transfer_spi_data(partial_buffer, partial_buffer_size, transaction_guard.transaction_id(), true); // Inverted for partial refresh if (err != ESP_OK) { ESP_LOGE(TAG, "Failed to send partial_buffer data for partial refresh: %s", esp_err_to_name(err)); heap_caps_free(partial_buffer); @@ -391,6 +404,13 @@ esp_err_t EInkDisplayHandler::partial_refresh(const uint8_t* incoming_partial_fr } } ESP_LOGI(TAG, "Partial refresh complete"); + + err = deep_sleep_display(); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to enter deep sleep after partial refresh: %s", esp_err_to_name(err)); + return err; + } + if (force_full_refresh_) { ESP_LOGI(TAG, "Full refresh already requested, skipping partial refresh count increment"); err = refresh_display(); @@ -400,6 +420,7 @@ esp_err_t EInkDisplayHandler::partial_refresh(const uint8_t* incoming_partial_fr } return ESP_OK; } + { SemaphoreGuard guard(refresh_mutex_); if (guard.take(pdMS_TO_TICKS(5000)) != pdTRUE) { @@ -418,11 +439,6 @@ esp_err_t EInkDisplayHandler::partial_refresh(const uint8_t* incoming_partial_fr } } - err = deep_sleep_display(); - if (err != ESP_OK) { - ESP_LOGE(TAG, "Failed to enter deep sleep after partial refresh: %s", esp_err_to_name(err)); - return err; - } refresh_area_.reset(); diff --git a/main/display/eink_display_handler.h b/main/display/eink_display_handler.h index a115d8f..16127de 100644 --- a/main/display/eink_display_handler.h +++ b/main/display/eink_display_handler.h @@ -8,7 +8,6 @@ #include "epd_handler.h" // Refresh mode configuration -#define PARTIAL_REFRESH_THRESHOLD 10 // Full refresh every N partial refreshes #define DISPLAY_WIDTH 800 #define DISPLAY_HEIGHT 480