From 89c9f317c13721c81041f217a8c95022d9d1708e Mon Sep 17 00:00:00 2001 From: Adolfo Reyna Date: Sat, 11 Jul 2026 22:40:55 -0400 Subject: [PATCH] fix(rlcd): fix ST7305 DMA fragmentation and lockup bug - Moved temporary draw buffer allocation to the initialization phase and made it persistent in the driver struct. - Resolved severe heap fragmentation caused by allocating and freeing 15KB per UI frame. - Fixed a use-after-free corruption where the SPI DMA would read from a freed temporary buffer. - Fixed WDT timeout caused by OOM failure in esp_lcd_panel_draw_bitmap that left LVGL hanging in wait_for_flushing. - Added explicit RAM clear command to boot sequence to wipe lingering hardware freeze artifacts. --- Drivers/ST7305/Source/esp_lcd_st7305.c | 38 ++++++++++++++++++-------- 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/Drivers/ST7305/Source/esp_lcd_st7305.c b/Drivers/ST7305/Source/esp_lcd_st7305.c index 48386305..394d7151 100644 --- a/Drivers/ST7305/Source/esp_lcd_st7305.c +++ b/Drivers/ST7305/Source/esp_lcd_st7305.c @@ -40,6 +40,7 @@ typedef struct { uint8_t madctl_val; const st7305_lcd_init_cmd_t *init_cmds; uint16_t init_cmds_size; + uint8_t *draw_buffer; } st7305_panel_t; static const st7305_lcd_init_cmd_t st7305_init_cmds[] = { @@ -103,6 +104,10 @@ esp_err_t esp_lcd_new_panel_st7305(const esp_lcd_panel_io_handle_t io, const esp st7305->init_cmds = st7305_init_cmds; st7305->init_cmds_size = sizeof(st7305_init_cmds) / sizeof(st7305_lcd_init_cmd_t); } + + st7305->draw_buffer = heap_caps_malloc(15000, MALLOC_CAP_DMA); + ESP_GOTO_ON_FALSE(st7305->draw_buffer, ESP_ERR_NO_MEM, err, TAG, "no mem for st7305 draw buffer"); + memset(st7305->draw_buffer, 0, 15000); st7305->base.del = panel_st7305_del; st7305->base.reset = panel_st7305_reset; st7305->base.init = panel_st7305_init; @@ -126,6 +131,9 @@ err: if (panel_dev_config->reset_gpio_num >= 0) { gpio_reset_pin(panel_dev_config->reset_gpio_num); } + if (st7305->draw_buffer) { + free(st7305->draw_buffer); + } free(st7305); } return ret; @@ -137,6 +145,9 @@ static esp_err_t panel_st7305_del(esp_lcd_panel_t *panel) if (st7305->reset_gpio_num >= 0) { gpio_reset_pin(st7305->reset_gpio_num); } + if (st7305->draw_buffer) { + free(st7305->draw_buffer); + } free(st7305); return ESP_OK; } @@ -172,6 +183,18 @@ static esp_err_t panel_st7305_init(esp_lcd_panel_t *panel) vTaskDelay(pdMS_TO_TICKS(st7305->init_cmds[i].delay_ms)); } } + + // Explicitly clear display RAM to white + if (st7305->draw_buffer) { + memset(st7305->draw_buffer, 0xFF, 15000); // 0xFF is White + uint8_t caset[] = {0x12, 0x2A}; + uint8_t raset[] = {0x00, 0xC7}; + esp_lcd_panel_io_tx_param(io, ST7305_CMD_CASET, caset, sizeof(caset)); + esp_lcd_panel_io_tx_param(io, ST7305_CMD_RASET, raset, sizeof(raset)); + esp_lcd_panel_io_tx_color(io, ST7305_CMD_RAMWR, st7305->draw_buffer, 15000); + vTaskDelay(pdMS_TO_TICKS(50)); + } + return ESP_OK; } @@ -180,14 +203,6 @@ static esp_err_t panel_st7305_draw_bitmap(esp_lcd_panel_t *panel, int x_start, i st7305_panel_t *st7305 = __containerof(panel, st7305_panel_t, base); esp_lcd_panel_io_handle_t io = st7305->io; - // Output buffer size is 15000 bytes (400 * 300 / 8) - size_t lcd_buf_size = 15000; - uint8_t *temp_buffer = heap_caps_malloc(lcd_buf_size, MALLOC_CAP_DMA); - if (!temp_buffer) { - return ESP_ERR_NO_MEM; - } - memset(temp_buffer, 0, lcd_buf_size); - const uint8_t *src = (const uint8_t *)color_data; // Convert from vertical-page format (SSD1306-style) to ST7305 landscape 2x4 block format @@ -218,9 +233,9 @@ static esp_err_t panel_st7305_draw_bitmap(esp_lcd_panel_t *panel, int x_start, i // In ST7305 display RAM, White/Light is 1, Black/Dark is 0. // So we write: 1 (White) if is_pixel_set is false (light), and 0 (Black) if is_pixel_set is true (dark). if (!is_pixel_set) { - temp_buffer[dest_byte_idx] |= (1 << dest_bit_pos); + st7305->draw_buffer[dest_byte_idx] |= (1 << dest_bit_pos); } else { - temp_buffer[dest_byte_idx] &= ~(1 << dest_bit_pos); + st7305->draw_buffer[dest_byte_idx] &= ~(1 << dest_bit_pos); } } } @@ -230,9 +245,8 @@ static esp_err_t panel_st7305_draw_bitmap(esp_lcd_panel_t *panel, int x_start, i esp_lcd_panel_io_tx_param(io, ST7305_CMD_CASET, caset, sizeof(caset)); esp_lcd_panel_io_tx_param(io, ST7305_CMD_RASET, raset, sizeof(raset)); - esp_lcd_panel_io_tx_color(io, ST7305_CMD_RAMWR, temp_buffer, lcd_buf_size); + esp_lcd_panel_io_tx_color(io, ST7305_CMD_RAMWR, st7305->draw_buffer, 15000); - free(temp_buffer); return ESP_OK; }