Fixed partial refresh problem, but refresh may blackout un touched pixels

This commit is contained in:
GW_MC
2026-01-27 11:50:12 +08:00
parent 5f491dff6e
commit dc2a76e131
2 changed files with 63 additions and 28 deletions

View File

@@ -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)"); 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; 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<uint8_t> window_data = { std::vector<uint8_t> window_data = {
// x start // x start, [9:8] bit -> 6 and 7 bits of x_bank_start
static_cast<uint8_t>((area.x1 >> 8) & 0xFF), // x start high byte static_cast<uint8_t>((x_bank_start >> 5) & 0x03),
static_cast<uint8_t>(area.x1 & 0x07), // x start low byte // x start, [7:3] bit + 3 bits of 0 -> 5 bits of x_bank_start and pad 3 LSBs as 0
// x end static_cast<uint8_t>((x_bank_start & 0x1F) << 3),
static_cast<uint8_t>((area.x2 >> 8) & 0xFF), // x end, [9:8] bit
static_cast<uint8_t>(area.x2 & 0x07), static_cast<uint8_t>((x_bank_end >> 5) & 0x03),
// y start // x end, [7:3] bit + 3 bits of 1
static_cast<uint8_t>((area.y1 >> 8) & 0xFF), static_cast<uint8_t>(((x_bank_end & 0x1F) << 3) | 0x07),
// y start, [9:8] bit
static_cast<uint8_t>((area.y1 >> 8) & 0x03),
// y start, [7:0] bit
static_cast<uint8_t>(area.y1 & 0xFF), static_cast<uint8_t>(area.y1 & 0xFF),
// y end // y end, [9:8] bit
static_cast<uint8_t>((area.y2 >> 8) & 0xFF), static_cast<uint8_t>((area.y2 >> 8) & 0x03),
// y end, [7:0] bit
static_cast<uint8_t>(area.y2 & 0xFF), static_cast<uint8_t>(area.y2 & 0xFF),
0x01 // Gates scan both inside and outside of the partial window 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 err = epd_write_cmd_with_data(0x90, window_data, transaction_guard.transaction_id()); // Set partial window
if (err != ESP_OK) { if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to send set partial window command: %s", esp_err_to_name(err)); ESP_LOGE(TAG, "Failed to send set partial window command: %s", esp_err_to_name(err));

View File

@@ -83,20 +83,32 @@ void EInk_Checkerboard(
} }
} }
// Yield and reset watchdog periodically // 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) { if (wdt_err == ESP_OK) {
esp_task_wdt_reset(); esp_task_wdt_reset();
} }
vTaskDelay(1 / portTICK_PERIOD_MS); vTaskDelay(1 / portTICK_PERIOD_MS);
// partial refresh to show progress
int32_t y_start = static_cast<int32_t>((y >= YIELD_INTERVAL - 1) ? (y - (YIELD_INTERVAL - 1)) : 0);
int32_t y_end = static_cast<int32_t>(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 // Perform full write to display
esp_err_t err = display_handler->full_write(framebuffer); // esp_err_t err = display_handler->full_write(framebuffer);
if (err != ESP_OK) { // if (err != ESP_OK) {
ESP_LOGE(TAG, "Checkerboard full write failed: %s", esp_err_to_name(err)); // ESP_LOGE(TAG, "Checkerboard full write failed: %s", esp_err_to_name(err));
} else { // } else {
ESP_LOGI(TAG, "Checkerboard pattern displayed successfully."); // ESP_LOGI(TAG, "Checkerboard pattern displayed successfully.");
} // }
delete[] framebuffer; delete[] framebuffer;
// Remove task from watchdog before deletion // Remove task from watchdog before deletion
@@ -239,18 +251,19 @@ void app_main(void) {
// NetworkHandler* network_handler = new NetworkHandler(std::move(wifi_handler)); // NetworkHandler* network_handler = new NetworkHandler(std::move(wifi_handler));
EInkDisplayHandler* display_handler = new EInkDisplayHandler(); EInkDisplayHandler* display_handler = new EInkDisplayHandler();
// Initialize display and touch // Initialize display and touch
display_handler->init_devices(); display_handler->init_devices(system_event_group);
// display_handler->init_devices();
display_handler->clear_display(); display_handler->clear_display();
ESP_LOGI(TAG, "E-Ink display handler initialized.\n"); ESP_LOGI(TAG, "E-Ink display handler initialized.\n");
// LVGL Handler // LVGL Handler
std::unique_ptr<EInkDisplayHandler> display_uptr(display_handler); // std::unique_ptr<EInkDisplayHandler> display_uptr(display_handler);
LVGLHandler lvgl_handler(std::move(display_uptr)); // LVGLHandler lvgl_handler(std::move(display_uptr));
esp_err_t err = lvgl_handler.initLVGL(system_event_group); // esp_err_t err = lvgl_handler.initLVGL(system_event_group);
if (err != ESP_OK) { // if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize LVGL handler: %s", esp_err_to_name(err)); // ESP_LOGE(TAG, "Failed to initialize LVGL handler: %s", esp_err_to_name(err));
vTaskDelay(5000 / portTICK_PERIOD_MS); // vTaskDelay(5000 / portTICK_PERIOD_MS);
return esp_restart(); // return esp_restart();
} // }
// //
// kv_storage_handler->init(system_event_group); // 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"); ESP_LOGI(TAG, "System is ready. Starting main application...\n");
// Show checkerboard pattern on display for testing // 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 // Register apps with AppRegistry by creating their descriptors
// Each descriptor will create and register the app instance // Each descriptor will create and register the app instance