From dc2a76e1311f4d6f88b320200d386432bc7d2490 Mon Sep 17 00:00:00 2001 From: GW_MC <72297530+GWMCwing@users.noreply.github.com> Date: Tue, 27 Jan 2026 11:50:12 +0800 Subject: [PATCH] Fixed partial refresh problem, but refresh may blackout un touched pixels --- main/display/eink_display_handler.cpp | 43 ++++++++++++++++++------ main/main.cpp | 48 +++++++++++++++++---------- 2 files changed, 63 insertions(+), 28 deletions(-) diff --git a/main/display/eink_display_handler.cpp b/main/display/eink_display_handler.cpp index 77727da..9896eee 100644 --- a/main/display/eink_display_handler.cpp +++ b/main/display/eink_display_handler.cpp @@ -183,22 +183,43 @@ esp_err_t EInkDisplayHandler::partial_refresh(const uint8_t* partial_framebuffer ESP_LOGE(TAG, "Partial refresh area x1 and x2 must be byte-aligned (x1 %% 8 == 0 and x2 %% 8 == 7)"); return ESP_ERR_INVALID_ARG; } - // no rounding needed, area is expected to be aligned + // ------DD + // DDDDD000 + // ------DD + // DDDDD111 + // ------DD + // DDDDDDDD + // ------DD + // DDDDDDDD + // -------D + + // area should be multiple of 8 in x direction + const int32_t x_bank_start = area.x1 >> 3; + const int32_t x_bank_end = area.x2 >> 3; std::vector window_data = { - // x start - static_cast((area.x1 >> 8) & 0xFF), // x start high byte - static_cast(area.x1 & 0x07), // x start low byte - // x end - static_cast((area.x2 >> 8) & 0xFF), - static_cast(area.x2 & 0x07), - // y start - static_cast((area.y1 >> 8) & 0xFF), + // x start, [9:8] bit -> 6 and 7 bits of x_bank_start + static_cast((x_bank_start >> 5) & 0x03), + // x start, [7:3] bit + 3 bits of 0 -> 5 bits of x_bank_start and pad 3 LSBs as 0 + static_cast((x_bank_start & 0x1F) << 3), + // x end, [9:8] bit + static_cast((x_bank_end >> 5) & 0x03), + // x end, [7:3] bit + 3 bits of 1 + static_cast(((x_bank_end & 0x1F) << 3) | 0x07), + // y start, [9:8] bit + static_cast((area.y1 >> 8) & 0x03), + // y start, [7:0] bit static_cast(area.y1 & 0xFF), - // y end - static_cast((area.y2 >> 8) & 0xFF), + // y end, [9:8] bit + static_cast((area.y2 >> 8) & 0x03), + // y end, [7:0] bit static_cast(area.y2 & 0xFF), 0x01 // Gates scan both inside and outside of the partial window }; + ESP_LOGI(TAG, "Setting partial window: x1=%d, y1=%d, x2=%d, y2=%d", + area.x1, area.y1, area.x2, area.y2); + ESP_LOGI(TAG, "Partial window data: %02X %02X %02X %02X %02X %02X %02X %02X", + window_data[0], window_data[1], window_data[2], window_data[3], window_data[4], + window_data[5], window_data[6], window_data[7]); err = epd_write_cmd_with_data(0x90, window_data, transaction_guard.transaction_id()); // Set partial window if (err != ESP_OK) { ESP_LOGE(TAG, "Failed to send set partial window command: %s", esp_err_to_name(err)); diff --git a/main/main.cpp b/main/main.cpp index b14369f..fba41cf 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -83,20 +83,32 @@ void EInk_Checkerboard( } } // Yield and reset watchdog periodically - if (y % 50 == 0) { + const size_t YIELD_INTERVAL = 16; + if (y % YIELD_INTERVAL == 0) { if (wdt_err == ESP_OK) { esp_task_wdt_reset(); } vTaskDelay(1 / portTICK_PERIOD_MS); + // partial refresh to show progress + int32_t y_start = static_cast((y >= YIELD_INTERVAL - 1) ? (y - (YIELD_INTERVAL - 1)) : 0); + int32_t y_end = static_cast(y); + // get the partial framebuffer for this area + uint8_t* partial_framebuffer = &framebuffer[y_start * (DISPLAY_WIDTH / 8)]; + esp_err_t err = display_handler->partial_refresh(partial_framebuffer, RefreshArea { 0, y_start, DISPLAY_WIDTH - 1, y_end }); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Partial refresh failed at y=%d: %s", y, esp_err_to_name(err)); + } + // wait for 4 seconds to prevent spamming the display + // vTaskDelay(2000 / portTICK_PERIOD_MS); } } // Perform full write to display - esp_err_t err = display_handler->full_write(framebuffer); - if (err != ESP_OK) { - ESP_LOGE(TAG, "Checkerboard full write failed: %s", esp_err_to_name(err)); - } else { - ESP_LOGI(TAG, "Checkerboard pattern displayed successfully."); - } + // esp_err_t err = display_handler->full_write(framebuffer); + // if (err != ESP_OK) { + // ESP_LOGE(TAG, "Checkerboard full write failed: %s", esp_err_to_name(err)); + // } else { + // ESP_LOGI(TAG, "Checkerboard pattern displayed successfully."); + // } delete[] framebuffer; // Remove task from watchdog before deletion @@ -239,18 +251,19 @@ void app_main(void) { // NetworkHandler* network_handler = new NetworkHandler(std::move(wifi_handler)); EInkDisplayHandler* display_handler = new EInkDisplayHandler(); // Initialize display and touch - display_handler->init_devices(); + display_handler->init_devices(system_event_group); + // display_handler->init_devices(); display_handler->clear_display(); ESP_LOGI(TAG, "E-Ink display handler initialized.\n"); // LVGL Handler - std::unique_ptr display_uptr(display_handler); - LVGLHandler lvgl_handler(std::move(display_uptr)); - esp_err_t err = lvgl_handler.initLVGL(system_event_group); - if (err != ESP_OK) { - ESP_LOGE(TAG, "Failed to initialize LVGL handler: %s", esp_err_to_name(err)); - vTaskDelay(5000 / portTICK_PERIOD_MS); - return esp_restart(); - } + // std::unique_ptr display_uptr(display_handler); + // LVGLHandler lvgl_handler(std::move(display_uptr)); + // esp_err_t err = lvgl_handler.initLVGL(system_event_group); + // if (err != ESP_OK) { + // ESP_LOGE(TAG, "Failed to initialize LVGL handler: %s", esp_err_to_name(err)); + // vTaskDelay(5000 / portTICK_PERIOD_MS); + // return esp_restart(); + // } // // kv_storage_handler->init(system_event_group); @@ -270,7 +283,8 @@ void app_main(void) { ESP_LOGI(TAG, "System is ready. Starting main application...\n"); // Show checkerboard pattern on display for testing - LVGL_Checkerboard(&lvgl_handler); + EInk_Checkerboard(display_handler); + // LVGL_Checkerboard(&lvgl_handler); // Register apps with AppRegistry by creating their descriptors // Each descriptor will create and register the app instance