Fix: partial refresh, but color still in negative
This commit is contained in:
@@ -12,16 +12,20 @@
|
||||
#define MINIMUM_PIN_SETUP_DELAY_MS 10
|
||||
#define MINIMUM_POWER_ON_DELAY_MS 100
|
||||
|
||||
static uint8_t black_data[DISPLAY_BUFFER_SIZE]; // all black data
|
||||
static uint8_t white_data[DISPLAY_BUFFER_SIZE]; // all white data
|
||||
static uint8_t DRAW_BUFFER[DISPLAY_WIDTH * DISPLAY_HEIGHT / 8]; // 1 bit per pixel
|
||||
static uint8_t OLD_DRAW_BUFFER[DISPLAY_WIDTH * DISPLAY_HEIGHT / 8]; // 1 bit per pixel
|
||||
static uint8_t* DRAW_BUFFER; // 1 bit per pixel
|
||||
static uint8_t* OLD_DRAW_BUFFER; // 1 bit per pixel
|
||||
static uint8_t* black_data;
|
||||
static uint8_t* white_data;
|
||||
|
||||
EInkDisplayHandler::EInkDisplayHandler() {
|
||||
memset(black_data, 0xFF, sizeof(black_data)); // eink uses 1 for black
|
||||
memset(white_data, 0x00, sizeof(white_data));
|
||||
memset(DRAW_BUFFER, 0x00, sizeof(DRAW_BUFFER)); // start with all white (0 = white in e-ink)
|
||||
memset(OLD_DRAW_BUFFER, 0x00, sizeof(OLD_DRAW_BUFFER)); // start with all white (0 = white in e-ink)
|
||||
black_data = static_cast<uint8_t*>(heap_caps_malloc(DISPLAY_BUFFER_SIZE, MALLOC_CAP_SPIRAM));
|
||||
white_data = static_cast<uint8_t*>(heap_caps_malloc(DISPLAY_BUFFER_SIZE, MALLOC_CAP_SPIRAM));
|
||||
DRAW_BUFFER = static_cast<uint8_t*>(heap_caps_malloc(DISPLAY_BUFFER_SIZE, MALLOC_CAP_SPIRAM));
|
||||
OLD_DRAW_BUFFER = static_cast<uint8_t*>(heap_caps_malloc(DISPLAY_BUFFER_SIZE, MALLOC_CAP_SPIRAM));
|
||||
memset(black_data, 0xFF, DISPLAY_BUFFER_SIZE); // eink uses 1 for black
|
||||
memset(white_data, 0x00, DISPLAY_BUFFER_SIZE);
|
||||
memset(DRAW_BUFFER, 0x00, DISPLAY_BUFFER_SIZE); // start with all white (0 = white in e-ink)
|
||||
memset(OLD_DRAW_BUFFER, 0x00, DISPLAY_BUFFER_SIZE); // start with all white (0 = white in e-ink)
|
||||
draw_buffer_ = DRAW_BUFFER;
|
||||
old_buffer_ = OLD_DRAW_BUFFER;
|
||||
|
||||
@@ -41,6 +45,18 @@ EInkDisplayHandler::~EInkDisplayHandler() {
|
||||
if (tp_io_handle_ != nullptr) {
|
||||
esp_lcd_panel_io_del(tp_io_handle_);
|
||||
}
|
||||
if (black_data != nullptr) {
|
||||
heap_caps_free(black_data);
|
||||
}
|
||||
if (white_data != nullptr) {
|
||||
heap_caps_free(white_data);
|
||||
}
|
||||
if (DRAW_BUFFER != nullptr) {
|
||||
heap_caps_free(DRAW_BUFFER);
|
||||
}
|
||||
if (OLD_DRAW_BUFFER != nullptr) {
|
||||
heap_caps_free(OLD_DRAW_BUFFER);
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t EInkDisplayHandler::deep_sleep_display(void) {
|
||||
@@ -205,27 +221,11 @@ esp_err_t EInkDisplayHandler::full_write(const uint8_t* framebuffer, const bool
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// TODO: Partial refresh is inverted in color
|
||||
esp_err_t EInkDisplayHandler::partial_refresh(const uint8_t* incoming_partial_framebuffer, const RefreshArea& incoming_area, const bool is_last_partial_update) {
|
||||
ESP_LOGI(TAG, "Starting partial refresh (0.3 seconds)...");
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
|
||||
{
|
||||
TransactionGuard transaction_guard(this->epd_handler_);
|
||||
err = transaction_guard.begin(pdMS_TO_TICKS(5000));
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to begin transaction for partial refresh: %s", esp_err_to_name(err));
|
||||
return err;
|
||||
}
|
||||
// Wake display from deep sleep INSIDE the transaction to prevent race conditions
|
||||
if (is_deep_sleep_) {
|
||||
err = epd_init_partial_internal_(transaction_guard.transaction_id());
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to initialize EPD for partial refresh: %s", esp_err_to_name(err));
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
write_to_buffer_(incoming_partial_framebuffer, incoming_area);
|
||||
|
||||
// Always expand refresh_area_ to include incoming_area
|
||||
@@ -235,6 +235,27 @@ 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));
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to begin transaction for partial refresh: %s", esp_err_to_name(err));
|
||||
return err;
|
||||
}
|
||||
// Wake display from deep sleep INSIDE the transaction to prevent race conditions
|
||||
if (is_deep_sleep_) {
|
||||
err = epd_init_internal_(transaction_guard.transaction_id());
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to initialize EPD for partial refresh: %s", esp_err_to_name(err));
|
||||
return err;
|
||||
}
|
||||
err = refresh_old_buffer_(transaction_guard.transaction_id());
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to refresh old buffer during partial refresh init: %s", esp_err_to_name(err));
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RefreshArea area = refresh_area_;
|
||||
if (area.x1 % 8 != 0 || area.x2 % 8 != 7) {
|
||||
@@ -248,7 +269,9 @@ esp_err_t EInkDisplayHandler::partial_refresh(const uint8_t* incoming_partial_fr
|
||||
const uint32_t area_height = area.y2 - area.y1 + 1;
|
||||
const size_t partial_buffer_size = area_width_bytes * area_height;
|
||||
|
||||
uint8_t* partial_buffer = new uint8_t[partial_buffer_size];
|
||||
// uint8_t* partial_buffer = new uint8_t[partial_buffer_size];
|
||||
uint8_t* partial_buffer = static_cast<uint8_t*>(heap_caps_malloc(partial_buffer_size, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL));
|
||||
|
||||
if (partial_buffer == nullptr) {
|
||||
ESP_LOGE(TAG, "Failed to allocate partial buffer for partial refresh");
|
||||
return ESP_ERR_NO_MEM;
|
||||
@@ -329,7 +352,7 @@ esp_err_t EInkDisplayHandler::partial_refresh(const uint8_t* incoming_partial_fr
|
||||
err = epd_handler_.epd_write_cmd(0x13, transaction_guard.transaction_id());
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to send new data command for partial refresh: %s", esp_err_to_name(err));
|
||||
delete[] partial_buffer;
|
||||
heap_caps_free(partial_buffer);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -339,16 +362,19 @@ esp_err_t EInkDisplayHandler::partial_refresh(const uint8_t* incoming_partial_fr
|
||||
err = epd_handler_.transfer_spi_data(partial_buffer, partial_buffer_size, transaction_guard.transaction_id());
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to send partial_buffer data for partial refresh: %s", esp_err_to_name(err));
|
||||
delete[] partial_buffer;
|
||||
heap_caps_free(partial_buffer);
|
||||
return err;
|
||||
}
|
||||
|
||||
memcpy(old_buffer_, draw_buffer_, DISPLAY_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
// Clean up partial buffer
|
||||
delete[] partial_buffer;
|
||||
heap_caps_free(partial_buffer);
|
||||
|
||||
// Step 6: Trigger partial display refresh (DRF)
|
||||
err = epd_handler_.epd_write_cmd(0x11, transaction_guard.transaction_id());
|
||||
// Use 0x12 (Display Update) command - same as full refresh, per sample code
|
||||
err = epd_handler_.epd_write_cmd(0x12, transaction_guard.transaction_id());
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to send display refresh command for partial refresh: %s", esp_err_to_name(err));
|
||||
return err;
|
||||
@@ -398,7 +424,6 @@ esp_err_t EInkDisplayHandler::partial_refresh(const uint8_t* incoming_partial_fr
|
||||
return err;
|
||||
}
|
||||
|
||||
memcpy(old_buffer_, draw_buffer_, DISPLAY_BUFFER_SIZE);
|
||||
|
||||
refresh_area_.reset();
|
||||
|
||||
@@ -702,7 +727,7 @@ esp_err_t EInkDisplayHandler::init_touch_() {
|
||||
}
|
||||
|
||||
esp_err_t EInkDisplayHandler::refresh_old_buffer_(uint32_t transaction_id) {
|
||||
ESP_LOGI(TAG, "Refreshing display SRAM to match current buffers...");
|
||||
ESP_LOGI(TAG, "Refreshing display SRAM to restore state after wake...");
|
||||
esp_err_t err;
|
||||
|
||||
err = epd_handler_.epd_write_cmd(0x92, transaction_id); // enter normal mode
|
||||
@@ -710,7 +735,11 @@ esp_err_t EInkDisplayHandler::refresh_old_buffer_(uint32_t transaction_id) {
|
||||
ESP_LOGE(TAG, "Failed to enter normal mode: %s", esp_err_to_name(err));
|
||||
return err;
|
||||
}
|
||||
// Send command to write old data (0x10)
|
||||
|
||||
// Write OLD data (0x10) as all 0x00 (white in e-ink terms)
|
||||
// This tells the controller: "assume display was all white"
|
||||
// Matches sample's EPD_WhiteScreen_ALL() which uses 0x00 for old SRAM
|
||||
// The differential refresh: old=0 + new=0 → stay white, old=0 + new=1 → drive to black
|
||||
err = epd_handler_.epd_write_cmd(0x10, transaction_id);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to send old data command: %s", esp_err_to_name(err));
|
||||
@@ -720,25 +749,25 @@ esp_err_t EInkDisplayHandler::refresh_old_buffer_(uint32_t transaction_id) {
|
||||
// Send the old buffer as old data
|
||||
err = epd_handler_.transfer_spi_data(old_buffer_, DISPLAY_BUFFER_SIZE, transaction_id);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to send old buffer data: %s", esp_err_to_name(err));
|
||||
ESP_LOGE(TAG, "Failed to send white baseline to old SRAM: %s", esp_err_to_name(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
// Also write to new data register (0x13) to ensure consistent baseline
|
||||
// This prevents undefined state after hardware reset
|
||||
// Write NEW data (0x13) with the actual display content
|
||||
// This restores the display to show old_buffer_ content
|
||||
err = epd_handler_.epd_write_cmd(0x13, transaction_id);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to send new data command: %s", esp_err_to_name(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
// Send the draw buffer as new data (should match old_buffer_ after full refresh)
|
||||
// Send the last displayed content to new SRAM
|
||||
err = epd_handler_.transfer_spi_data(old_buffer_, DISPLAY_BUFFER_SIZE, transaction_id);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to send draw buffer data: %s", esp_err_to_name(err));
|
||||
ESP_LOGE(TAG, "Failed to send display content to new SRAM: %s", esp_err_to_name(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Display SRAM refreshed successfully");
|
||||
ESP_LOGI(TAG, "Display SRAM restored successfully");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user