feat(display): Implement singleton pattern for EInkDisplayHandler and enhance buffer allocation checks
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
#include "common/constants.h"
|
||||
#include "esp_lcd_touch_gt911.h"
|
||||
#include <driver/i2c.h>
|
||||
#include <esp_cache.h>
|
||||
#define TAG "EPDHandler"
|
||||
|
||||
#define BUSY_ACTIVE_LEVEL 0 // BUSY pin is active low
|
||||
@@ -213,10 +214,29 @@ esp_err_t EPDHandler::transfer_spi_data(const uint8_t* data, const size_t& lengt
|
||||
size_t remaining = length;
|
||||
gpio_set_level(PIN_DC, 1); // Data mode
|
||||
|
||||
// Allocate a temporary buffer for inverted data (only if inverted)
|
||||
// Check if data is in PSRAM (needs cache sync and staging buffer)
|
||||
bool data_in_psram = (esp_ptr_external_ram((void*)data) != 0);
|
||||
|
||||
if (data_in_psram) {
|
||||
// Flush cache to ensure DMA sees the latest data in PSRAM
|
||||
esp_err_t cache_err = esp_cache_msync((void*)data, length, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
|
||||
if (cache_err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "Cache sync failed: %s", esp_err_to_name(cache_err));
|
||||
}
|
||||
}
|
||||
|
||||
// Use staging buffer in internal DMA-capable RAM
|
||||
// PSRAM cannot be allocated with MALLOC_CAP_DMA, so we always use a staging buffer
|
||||
uint8_t* staging_buffer = (uint8_t*)heap_caps_malloc(DMA_TRANSFER_CHUNK_SIZE, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
|
||||
if (staging_buffer == nullptr) {
|
||||
ESP_LOGE(TAG, "Failed to allocate DMA staging buffer");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
// Additional buffer needed only for inverted data
|
||||
uint8_t* temp_transfer_buffer = nullptr;
|
||||
if (inverted) {
|
||||
temp_transfer_buffer = (uint8_t*)heap_caps_malloc(DMA_TRANSFER_CHUNK_SIZE, MALLOC_CAP_DMA);
|
||||
temp_transfer_buffer = (uint8_t*)heap_caps_malloc(DMA_TRANSFER_CHUNK_SIZE, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
|
||||
if (temp_transfer_buffer == nullptr) {
|
||||
ESP_LOGE(TAG, "Failed to allocate memory for inverted data transfer buffer");
|
||||
ESP_LOGI(TAG, "Current free heap size: %u bytes", esp_get_free_heap_size());
|
||||
@@ -229,31 +249,27 @@ esp_err_t EPDHandler::transfer_spi_data(const uint8_t* data, const size_t& lengt
|
||||
while (remaining > 0) {
|
||||
size_t transfer_size = (remaining < DMA_TRANSFER_CHUNK_SIZE) ? remaining : DMA_TRANSFER_CHUNK_SIZE;
|
||||
|
||||
const uint8_t* transfer_buffer = nullptr;
|
||||
// Copy data to DMA-capable staging buffer
|
||||
// Required because PSRAM cannot be allocated with MALLOC_CAP_DMA
|
||||
if (inverted) {
|
||||
// Invert only the current chunk into the temporary buffer
|
||||
// Invert while copying
|
||||
for (size_t i = 0; i < transfer_size; ++i) {
|
||||
temp_transfer_buffer[i] = ~data[offset + i];
|
||||
staging_buffer[i] = ~data[offset + i];
|
||||
}
|
||||
transfer_buffer = temp_transfer_buffer;
|
||||
} else {
|
||||
transfer_buffer = data + offset;
|
||||
// Straight copy from PSRAM to internal DMA buffer
|
||||
memcpy(staging_buffer, data + offset, transfer_size);
|
||||
}
|
||||
|
||||
spi_transaction_t t = {};
|
||||
t.length = transfer_size * 8; // Length in bits
|
||||
t.tx_buffer = transfer_buffer;
|
||||
t.tx_buffer = staging_buffer;
|
||||
|
||||
esp_err_t ret = spi_device_polling_transmit(spi_, &t);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to send SPI chunk at offset %zu: %s", offset, esp_err_to_name(ret));
|
||||
if (ret == ESP_ERR_NO_MEM) {
|
||||
ESP_LOGE(TAG, "Current free heap size: %u bytes", esp_get_free_heap_size());
|
||||
ESP_LOGE(TAG, "Current free DMA-capable memory size: %u bytes",
|
||||
heap_caps_get_free_size(MALLOC_CAP_DMA));
|
||||
}
|
||||
heap_caps_free(staging_buffer);
|
||||
if (inverted && temp_transfer_buffer != nullptr) {
|
||||
// Free the temporary inverted buffer
|
||||
heap_caps_free(temp_transfer_buffer);
|
||||
}
|
||||
return ret;
|
||||
@@ -269,8 +285,8 @@ esp_err_t EPDHandler::transfer_spi_data(const uint8_t* data, const size_t& lengt
|
||||
}
|
||||
}
|
||||
|
||||
heap_caps_free(staging_buffer);
|
||||
if (inverted && temp_transfer_buffer != nullptr) {
|
||||
// Free the temporary inverted buffer
|
||||
heap_caps_free(temp_transfer_buffer);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user