From 450d1ecd085e92dd3677109822658b57074c5759 Mon Sep 17 00:00:00 2001 From: Fan Shen Wei Date: Sun, 26 Jan 2025 19:59:24 +0800 Subject: [PATCH] feat: add spi dma support for esp32_s3_eye. --- bsp/esp32_s3_eye/esp32_s3_eye.c | 4 ++ bsp/esp32_s3_eye/include/bsp/esp32_s3_eye.h | 5 ++ components/esp_lvgl_port/CMakeLists.txt | 3 +- components/esp_lvgl_port/idf_component.yml | 2 +- .../src/lvgl8/esp_lvgl_port_disp.c | 49 +++++++++++++++---- .../src/lvgl9/esp_lvgl_port_disp.c | 27 +++++++++- 6 files changed, 78 insertions(+), 12 deletions(-) diff --git a/bsp/esp32_s3_eye/esp32_s3_eye.c b/bsp/esp32_s3_eye/esp32_s3_eye.c index d3013d05..bffc3d7d 100644 --- a/bsp/esp32_s3_eye/esp32_s3_eye.c +++ b/bsp/esp32_s3_eye/esp32_s3_eye.c @@ -358,7 +358,11 @@ lv_display_t *bsp_display_start(void) .double_buffer = BSP_LCD_DRAW_BUFF_DOUBLE, .flags = { #if (CONFIG_BSP_DISPLAY_LVGL_BUFFER_IN_PSRAM && CONFIG_SPIRAM) +#if CONFIG_SPI_DMA_SUPPORT_PSRAM + .buff_dma = true, +#else .buff_dma = false, +#endif .buff_spiram = true, #else .buff_dma = true, diff --git a/bsp/esp32_s3_eye/include/bsp/esp32_s3_eye.h b/bsp/esp32_s3_eye/include/bsp/esp32_s3_eye.h index 4de857ee..7e660de7 100644 --- a/bsp/esp32_s3_eye/include/bsp/esp32_s3_eye.h +++ b/bsp/esp32_s3_eye/include/bsp/esp32_s3_eye.h @@ -309,7 +309,12 @@ esp_err_t bsp_sdcard_unmount(void); * * If you want to use the display without LVGL, see bsp/display.h API and use BSP version with 'noglib' suffix. **************************************************************************************************/ + +#if CONFIG_SPI_DMA_SUPPORT_PSRAM +#define BSP_LCD_PIXEL_CLOCK_HZ (40 * 1000 * 1000) +#else #define BSP_LCD_PIXEL_CLOCK_HZ (80 * 1000 * 1000) +#endif #define BSP_LCD_SPI_NUM (SPI3_HOST) #if (BSP_CONFIG_NO_GRAPHIC_LIB == 0) diff --git a/components/esp_lvgl_port/CMakeLists.txt b/components/esp_lvgl_port/CMakeLists.txt index 4a84cbf0..636ac1f3 100644 --- a/components/esp_lvgl_port/CMakeLists.txt +++ b/components/esp_lvgl_port/CMakeLists.txt @@ -10,7 +10,7 @@ endif() idf_component_register( INCLUDE_DIRS "include" PRIV_INCLUDE_DIRS "priv_include" - REQUIRES "esp_lcd") + REQUIRES "esp_lcd esp_mm") # Get LVGL version idf_build_get_property(build_components BUILD_COMPONENTS) @@ -116,6 +116,7 @@ target_link_libraries(lvgl_port_lib PUBLIC ) target_link_libraries(lvgl_port_lib PRIVATE idf::esp_timer + idf::esp_mm ${ADD_LIBS} ) diff --git a/components/esp_lvgl_port/idf_component.yml b/components/esp_lvgl_port/idf_component.yml index fb7e7619..aed2f92d 100644 --- a/components/esp_lvgl_port/idf_component.yml +++ b/components/esp_lvgl_port/idf_component.yml @@ -1,4 +1,4 @@ -version: "2.4.3" +version: "2.4.4" description: ESP LVGL port url: https://github.com/espressif/esp-bsp/tree/master/components/esp_lvgl_port dependencies: diff --git a/components/esp_lvgl_port/src/lvgl8/esp_lvgl_port_disp.c b/components/esp_lvgl_port/src/lvgl8/esp_lvgl_port_disp.c index d311f147..0d0b081d 100644 --- a/components/esp_lvgl_port/src/lvgl8/esp_lvgl_port_disp.c +++ b/components/esp_lvgl_port/src/lvgl8/esp_lvgl_port_disp.c @@ -17,6 +17,9 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/semphr.h" +#if CONFIG_IDF_TARGET_ESP32S3 && CONFIG_SPIRAM && CONFIG_SPI_DMA_SUPPORT_PSRAM +#include "esp_private/esp_cache_private.h" +#endif #if CONFIG_IDF_TARGET_ESP32S3 && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) #include "esp_lcd_panel_rgb.h" @@ -244,6 +247,21 @@ static lv_disp_t *lvgl_port_add_disp_priv(const lvgl_port_display_cfg_t *disp_cf disp_ctx->trans_size = disp_cfg->trans_size; buffer_size = disp_cfg->buffer_size; + uint32_t buff_caps = 0; +#if SOC_PSRAM_DMA_CAPABLE == 0 + if (disp_cfg->flags.buff_dma && disp_cfg->flags.buff_spiram) { + ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "Alloc DMA capable buffer in SPIRAM is not supported!"); + } +#endif + if (disp_cfg->flags.buff_dma) { + buff_caps |= MALLOC_CAP_DMA; + } + if (disp_cfg->flags.buff_spiram) { + buff_caps |= MALLOC_CAP_SPIRAM; + } + if (buff_caps == 0) { + buff_caps |= MALLOC_CAP_DEFAULT; + } /* Use RGB internal buffers for avoid tearing effect */ if (priv_cfg && priv_cfg->avoid_tearing) { @@ -259,15 +277,6 @@ static lv_disp_t *lvgl_port_add_disp_priv(const lvgl_port_display_cfg_t *disp_cf ESP_GOTO_ON_FALSE(trans_sem, ESP_ERR_NO_MEM, err, TAG, "Failed to create transport counting Semaphore"); disp_ctx->trans_sem = trans_sem; } else { - uint32_t buff_caps = MALLOC_CAP_DEFAULT; - if (disp_cfg->flags.buff_dma && disp_cfg->flags.buff_spiram && (0 == disp_cfg->trans_size)) { - ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "Alloc DMA capable buffer in SPIRAM is not supported!"); - } else if (disp_cfg->flags.buff_dma) { - buff_caps = MALLOC_CAP_DMA; - } else if (disp_cfg->flags.buff_spiram) { - buff_caps = MALLOC_CAP_SPIRAM; - } - if (disp_cfg->trans_size) { buf3 = heap_caps_malloc(disp_cfg->trans_size * sizeof(lv_color_t), MALLOC_CAP_DMA); ESP_GOTO_ON_FALSE(buf3, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for buffer(transport) allocation!"); @@ -280,12 +289,34 @@ static lv_disp_t *lvgl_port_add_disp_priv(const lvgl_port_display_cfg_t *disp_cf /* alloc draw buffers used by LVGL */ /* it's recommended to choose the size of the draw buffer(s) to be at least 1/10 screen sized */ +#if CONFIG_IDF_TARGET_ESP32S3 && CONFIG_SPIRAM && CONFIG_SPI_DMA_SUPPORT_PSRAM + if (disp_cfg->flags.buff_dma && disp_cfg->flags.buff_spiram) { + size_t cache_line_size; + ESP_ERROR_CHECK(esp_cache_get_alignment(MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA, &cache_line_size)); + uint32_t buffer_size_align_bytes = buffer_size * sizeof(lv_color_t); + buffer_size_align_bytes = (buffer_size_align_bytes + cache_line_size - 1) & ~(cache_line_size - 1); + buf1 = heap_caps_aligned_alloc(cache_line_size, buffer_size_align_bytes, buff_caps); + ESP_GOTO_ON_FALSE(buf1, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for LVGL buffer (buf1) allocation!"); + if (disp_cfg->double_buffer) { + buf2 = heap_caps_aligned_alloc(cache_line_size, buffer_size_align_bytes, buff_caps); + ESP_GOTO_ON_FALSE(buf2, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for LVGL buffer (buf2) allocation!"); + } + } else { + buf1 = heap_caps_malloc(buffer_size * sizeof(lv_color_t), buff_caps); + ESP_GOTO_ON_FALSE(buf1, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for LVGL buffer (buf1) allocation!"); + if (disp_cfg->double_buffer) { + buf2 = heap_caps_malloc(buffer_size * sizeof(lv_color_t), buff_caps); + ESP_GOTO_ON_FALSE(buf2, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for LVGL buffer (buf2) allocation!"); + } + } +#else buf1 = heap_caps_malloc(buffer_size * sizeof(lv_color_t), buff_caps); ESP_GOTO_ON_FALSE(buf1, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for LVGL buffer (buf1) allocation!"); if (disp_cfg->double_buffer) { buf2 = heap_caps_malloc(buffer_size * sizeof(lv_color_t), buff_caps); ESP_GOTO_ON_FALSE(buf2, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for LVGL buffer (buf2) allocation!"); } +#endif } lv_disp_draw_buf_t *disp_buf = malloc(sizeof(lv_disp_draw_buf_t)); diff --git a/components/esp_lvgl_port/src/lvgl9/esp_lvgl_port_disp.c b/components/esp_lvgl_port/src/lvgl9/esp_lvgl_port_disp.c index 6ad23987..8d197245 100644 --- a/components/esp_lvgl_port/src/lvgl9/esp_lvgl_port_disp.c +++ b/components/esp_lvgl_port/src/lvgl9/esp_lvgl_port_disp.c @@ -17,6 +17,9 @@ #include "esp_lcd_panel_ops.h" #include "esp_lvgl_port.h" #include "esp_lvgl_port_priv.h" +#if CONFIG_IDF_TARGET_ESP32S3 && CONFIG_SPIRAM && CONFIG_SPI_DMA_SUPPORT_PSRAM +#include "esp_private/esp_cache_private.h" +#endif #if CONFIG_IDF_TARGET_ESP32S3 && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) #include "esp_lcd_panel_rgb.h" @@ -308,13 +311,35 @@ static lv_display_t *lvgl_port_add_disp_priv(const lvgl_port_display_cfg_t *disp } else { /* alloc draw buffers used by LVGL */ /* it's recommended to choose the size of the draw buffer(s) to be at least 1/10 screen sized */ +#if CONFIG_IDF_TARGET_ESP32S3 && CONFIG_SPIRAM && CONFIG_SPI_DMA_SUPPORT_PSRAM + if (disp_cfg->flags.buff_dma && disp_cfg->flags.buff_spiram) { + // the data buffer address and transaction length should both aligned to cache length + size_t cache_line_size; + ESP_ERROR_CHECK(esp_cache_get_alignment(MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA, &cache_line_size)); + uint32_t buffer_size_align_bytes = buffer_size * color_bytes; + buffer_size_align_bytes = (buffer_size_align_bytes + cache_line_size - 1) & ~(cache_line_size - 1); + buf1 = heap_caps_aligned_alloc(cache_line_size, buffer_size_align_bytes, buff_caps); + ESP_GOTO_ON_FALSE(buf1, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for LVGL buffer (buf1) allocation!"); + if (disp_cfg->double_buffer) { + buf2 = heap_caps_aligned_alloc(cache_line_size, buffer_size_align_bytes, buff_caps); + ESP_GOTO_ON_FALSE(buf2, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for LVGL buffer (buf2) allocation!"); + } + } else { + buf1 = heap_caps_malloc(buffer_size * color_bytes, buff_caps); + ESP_GOTO_ON_FALSE(buf1, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for LVGL buffer (buf1) allocation!"); + if (disp_cfg->double_buffer) { + buf2 = heap_caps_malloc(buffer_size * color_bytes, buff_caps); + ESP_GOTO_ON_FALSE(buf2, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for LVGL buffer (buf2) allocation!"); + } + } +#else buf1 = heap_caps_malloc(buffer_size * color_bytes, buff_caps); ESP_GOTO_ON_FALSE(buf1, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for LVGL buffer (buf1) allocation!"); if (disp_cfg->double_buffer) { buf2 = heap_caps_malloc(buffer_size * color_bytes, buff_caps); ESP_GOTO_ON_FALSE(buf2, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for LVGL buffer (buf2) allocation!"); } - +#endif disp_ctx->draw_buffs[0] = buf1; disp_ctx->draw_buffs[1] = buf2; }