diff --git a/bsp/esp32_s3_eye/Kconfig b/bsp/esp32_s3_eye/Kconfig index 1e0be15d..34a8a67c 100644 --- a/bsp/esp32_s3_eye/Kconfig +++ b/bsp/esp32_s3_eye/Kconfig @@ -88,7 +88,8 @@ menu "Board Support Package" Maximum time for task sleep in ms. config BSP_DISPLAY_LVGL_BUFFER_IN_PSRAM - bool "Allocate LVGL buffer in PSRAM " + bool "Allocate LVGL buffer in PSRAM" + depends on SPI_DMA_SUPPORT_PSRAM default n help LVGL buffer will be allocated in PSRAM instead of internal RAM with DMA. diff --git a/bsp/esp32_s3_eye/esp32_s3_eye.c b/bsp/esp32_s3_eye/esp32_s3_eye.c index 4c03ab78..211bcbdd 100644 --- a/bsp/esp32_s3_eye/esp32_s3_eye.c +++ b/bsp/esp32_s3_eye/esp32_s3_eye.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -357,13 +357,12 @@ lv_display_t *bsp_display_start(void) .buffer_size = BSP_LCD_DRAW_BUFF_SIZE, .double_buffer = BSP_LCD_DRAW_BUFF_DOUBLE, .flags = { -#if (CONFIG_BSP_DISPLAY_LVGL_BUFFER_IN_PSRAM && CONFIG_SPIRAM) - .buff_dma = false, +#if CONFIG_BSP_DISPLAY_LVGL_BUFFER_IN_PSRAM .buff_spiram = true, #else - .buff_dma = true, .buff_spiram = false, #endif + .buff_dma = true, } }; return bsp_display_start_with_config(&cfg); diff --git a/bsp/esp32_s3_eye/idf_component.yml b/bsp/esp32_s3_eye/idf_component.yml index b0a8ef17..72c663a7 100644 --- a/bsp/esp32_s3_eye/idf_component.yml +++ b/bsp/esp32_s3_eye/idf_component.yml @@ -1,4 +1,4 @@ -version: "4.0.1" +version: "4.0.2" description: Board Support Package (BSP) for ESP32-S3-EYE url: https://github.com/espressif/esp-bsp/tree/master/bsp/esp32_s3_eye diff --git a/bsp/esp32_s3_eye/include/bsp/display.h b/bsp/esp32_s3_eye/include/bsp/display.h index 213b4720..77808fe9 100644 --- a/bsp/esp32_s3_eye/include/bsp/display.h +++ b/bsp/esp32_s3_eye/include/bsp/display.h @@ -24,7 +24,7 @@ /* LCD display color format */ #define BSP_LCD_COLOR_FORMAT (ESP_LCD_COLOR_FORMAT_RGB565) /* LCD display color bytes endianess */ -#define BSP_LCD_BIGENDIAN (1) +#define BSP_LCD_BIGENDIAN (0) /* LCD display color bits */ #define BSP_LCD_BITS_PER_PIXEL (16) /* LCD display color space */ 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 ba05da01..c5d3eaa3 100644 --- a/bsp/esp32_s3_eye/include/bsp/esp32_s3_eye.h +++ b/bsp/esp32_s3_eye/include/bsp/esp32_s3_eye.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,6 +13,7 @@ #include "sdkconfig.h" #include "driver/gpio.h" +#include "driver/i2c_master.h" #include "driver/sdmmc_host.h" #include "esp_codec_dev.h" #include "iot_button.h" @@ -308,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..feafdf1e 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.5" 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..a7633aee 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 @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -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 921954b9..1fb24b32 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 @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -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" @@ -251,6 +254,7 @@ static lv_display_t *lvgl_port_add_disp_priv(const lvgl_port_display_cfg_t *disp ESP_RETURN_ON_FALSE(disp_cfg->color_format == 0 || disp_cfg->color_format == LV_COLOR_FORMAT_RGB565 || disp_cfg->color_format == LV_COLOR_FORMAT_RGB888 || disp_cfg->color_format == LV_COLOR_FORMAT_XRGB8888 || disp_cfg->color_format == LV_COLOR_FORMAT_ARGB8888 || disp_cfg->color_format == LV_COLOR_FORMAT_I1, NULL, TAG, "Not supported display color format!"); lv_color_format_t display_color_format = (disp_cfg->color_format != 0 ? disp_cfg->color_format : LV_COLOR_FORMAT_RGB565); + uint8_t color_bytes = lv_color_format_get_size(display_color_format); if (disp_cfg->flags.swap_bytes) { /* Swap bytes can be used only in RGB565 color format */ ESP_RETURN_ON_FALSE(display_color_format == LV_COLOR_FORMAT_RGB565, NULL, TAG, "Swap bytes can be used only in display color format RGB565!"); @@ -258,7 +262,7 @@ static lv_display_t *lvgl_port_add_disp_priv(const lvgl_port_display_cfg_t *disp if (disp_cfg->flags.buff_dma) { /* DMA buffer can be used only in RGB565 color format */ - ESP_RETURN_ON_FALSE(display_color_format == LV_COLOR_FORMAT_RGB565, NULL, TAG, "DMA buffer can be used only in display color format RGB565 (not alligned copy)!"); + ESP_RETURN_ON_FALSE(display_color_format == LV_COLOR_FORMAT_RGB565, NULL, TAG, "DMA buffer can be used only in display color format RGB565 (not aligned copy)!"); } /* Display context */ @@ -307,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 */ - buf1 = heap_caps_malloc(buffer_size * sizeof(lv_color_t), buff_caps); +#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 * sizeof(lv_color_t), buff_caps); + 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; } @@ -336,7 +362,7 @@ static lv_display_t *lvgl_port_add_disp_priv(const lvgl_port_display_cfg_t *disp ESP_GOTO_ON_FALSE((disp_cfg->hres * disp_cfg->vres == buffer_size), ESP_ERR_INVALID_ARG, err, TAG, "Monochromatic display must using full buffer!"); disp_ctx->flags.monochrome = 1; - lv_display_set_buffers(disp, buf1, buf2, buffer_size * sizeof(lv_color_t), LV_DISPLAY_RENDER_MODE_FULL); + lv_display_set_buffers(disp, buf1, buf2, buffer_size * color_bytes, LV_DISPLAY_RENDER_MODE_FULL); if (display_color_format == LV_COLOR_FORMAT_I1) { /* OLED monochrome buffer */ @@ -350,15 +376,15 @@ static lv_display_t *lvgl_port_add_disp_priv(const lvgl_port_display_cfg_t *disp ESP_GOTO_ON_FALSE((disp_cfg->hres * disp_cfg->vres == buffer_size), ESP_ERR_INVALID_ARG, err, TAG, "Direct mode must using full buffer!"); disp_ctx->flags.direct_mode = 1; - lv_display_set_buffers(disp, buf1, buf2, buffer_size * sizeof(lv_color_t), LV_DISPLAY_RENDER_MODE_DIRECT); + lv_display_set_buffers(disp, buf1, buf2, buffer_size * color_bytes, LV_DISPLAY_RENDER_MODE_DIRECT); } else if (disp_cfg->flags.full_refresh) { /* When using full_refresh, there must be used full bufer! */ ESP_GOTO_ON_FALSE((disp_cfg->hres * disp_cfg->vres == buffer_size), ESP_ERR_INVALID_ARG, err, TAG, "Full refresh must using full buffer!"); disp_ctx->flags.full_refresh = 1; - lv_display_set_buffers(disp, buf1, buf2, buffer_size * sizeof(lv_color_t), LV_DISPLAY_RENDER_MODE_FULL); + lv_display_set_buffers(disp, buf1, buf2, buffer_size * color_bytes, LV_DISPLAY_RENDER_MODE_FULL); } else { - lv_display_set_buffers(disp, buf1, buf2, buffer_size * sizeof(lv_color_t), LV_DISPLAY_RENDER_MODE_PARTIAL); + lv_display_set_buffers(disp, buf1, buf2, buffer_size * color_bytes, LV_DISPLAY_RENDER_MODE_PARTIAL); } lv_display_set_flush_cb(disp, lvgl_port_flush_callback); @@ -371,7 +397,7 @@ static lv_display_t *lvgl_port_add_disp_priv(const lvgl_port_display_cfg_t *disp /* Use SW rotation */ if (disp_cfg->flags.sw_rotate) { - disp_ctx->draw_buffs[2] = heap_caps_malloc(buffer_size * sizeof(lv_color_t), buff_caps); + disp_ctx->draw_buffs[2] = heap_caps_malloc(buffer_size * color_bytes, buff_caps); ESP_GOTO_ON_FALSE(disp_ctx->draw_buffs[2], ESP_ERR_NO_MEM, err, TAG, "Not enough memory for LVGL buffer (rotation buffer) allocation!"); }