From b6bc597903f5f1acc4407c0a7dd3619bf9bb5dae Mon Sep 17 00:00:00 2001 From: morris Date: Wed, 29 May 2024 22:45:46 +0800 Subject: [PATCH] feat(i80_lcd): add help function to allocate draw buffer with proper alignment --- components/esp_lcd/i80/esp_lcd_panel_io_i2s.c | 10 +++++++++- components/esp_lcd/i80/esp_lcd_panel_io_i80.c | 15 +++++++++++++++ components/esp_lcd/include/esp_lcd_io_i80.h | 12 ++++++++++++ .../main/i80_controller_example_main.c | 18 ++++++------------ 4 files changed, 42 insertions(+), 13 deletions(-) diff --git a/components/esp_lcd/i80/esp_lcd_panel_io_i2s.c b/components/esp_lcd/i80/esp_lcd_panel_io_i2s.c index 3e4e6a1323..68db94d8b3 100644 --- a/components/esp_lcd/i80/esp_lcd_panel_io_i2s.c +++ b/components/esp_lcd/i80/esp_lcd_panel_io_i2s.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -321,6 +321,14 @@ err: return ret; } +void *esp_lcd_i80_alloc_draw_buffer(esp_lcd_panel_io_handle_t io, size_t size, uint32_t caps) +{ + ESP_RETURN_ON_FALSE(io, NULL, TAG, "invalid argument"); + ESP_RETURN_ON_FALSE((caps & MALLOC_CAP_SPIRAM) == 0, NULL, TAG, "external memory is not supported"); + // DMA can only carry internal memory + return heap_caps_aligned_calloc(4, 1, size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT | MALLOC_CAP_DMA); +} + static esp_err_t panel_io_i80_del(esp_lcd_panel_io_t *io) { lcd_panel_io_i80_t *i80_device = __containerof(io, lcd_panel_io_i80_t, base); diff --git a/components/esp_lcd/i80/esp_lcd_panel_io_i80.c b/components/esp_lcd/i80/esp_lcd_panel_io_i80.c index cbaea3f63d..8e7e50ed6f 100644 --- a/components/esp_lcd/i80/esp_lcd_panel_io_i80.c +++ b/components/esp_lcd/i80/esp_lcd_panel_io_i80.c @@ -583,6 +583,21 @@ err: return ret; } +void *esp_lcd_i80_alloc_draw_buffer(esp_lcd_panel_io_handle_t io, size_t size, uint32_t caps) +{ + ESP_RETURN_ON_FALSE(io, NULL, TAG, "invalid argument"); + lcd_panel_io_i80_t *i80_device = __containerof(io, lcd_panel_io_i80_t, base); + esp_lcd_i80_bus_t *bus = i80_device->bus; + void *buf = NULL; + // alloc from external memory + if (caps & MALLOC_CAP_SPIRAM) { + buf = heap_caps_aligned_calloc(bus->ext_mem_align, 1, size, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA); + } else { + buf = heap_caps_aligned_calloc(bus->int_mem_align, 1, size, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA); + } + return buf; +} + static esp_err_t lcd_i80_bus_configure_gpio(esp_lcd_i80_bus_handle_t bus, const esp_lcd_i80_bus_config_t *bus_config) { int bus_id = bus->bus_id; diff --git a/components/esp_lcd/include/esp_lcd_io_i80.h b/components/esp_lcd/include/esp_lcd_io_i80.h index 664afc0000..7b6bd90422 100644 --- a/components/esp_lcd/include/esp_lcd_io_i80.h +++ b/components/esp_lcd/include/esp_lcd_io_i80.h @@ -100,6 +100,18 @@ typedef struct { */ esp_err_t esp_lcd_new_panel_io_i80(esp_lcd_i80_bus_handle_t bus, const esp_lcd_panel_io_i80_config_t *io_config, esp_lcd_panel_io_handle_t *ret_io); +/** + * @brief Allocate a draw buffer that can be used by I80 interfaced LCD panel + * + * @note This function differs from the normal 'heap_caps_*' functions in that it can also automatically handle the alignment required by DMA burst, cache line size, etc. + * + * @param[in] io Panel IO handle, created by `esp_lcd_new_panel_io_i80()` + * @param[in] size Size of memory to be allocated + * @param[in] caps Bitwise OR of MALLOC_CAP_* flags indicating the type of memory desired for the allocation + * @return Pointer to a new buffer of size 'size' with capabilities 'caps', or NULL if allocation failed + */ +void *esp_lcd_i80_alloc_draw_buffer(esp_lcd_panel_io_handle_t io, size_t size, uint32_t caps); + #endif // SOC_LCD_I80_SUPPORTED #ifdef __cplusplus diff --git a/examples/peripherals/lcd/i80_controller/main/i80_controller_example_main.c b/examples/peripherals/lcd/i80_controller/main/i80_controller_example_main.c index 146c28ea7f..259dd4bcb5 100644 --- a/examples/peripherals/lcd/i80_controller/main/i80_controller_example_main.c +++ b/examples/peripherals/lcd/i80_controller/main/i80_controller_example_main.c @@ -9,6 +9,7 @@ #include "freertos/task.h" #include "freertos/semphr.h" #include "esp_timer.h" +#include "esp_heap_caps.h" #include "esp_lcd_panel_io.h" #include "esp_lcd_panel_vendor.h" #include "esp_lcd_panel_ops.h" @@ -18,7 +19,6 @@ #include "driver/i2c.h" #include "esp_err.h" #include "esp_log.h" -#include "esp_dma_utils.h" #include "lvgl.h" #if CONFIG_EXAMPLE_LCD_TOUCH_CONTROLLER_GT911 #include "esp_lcd_touch_gt911.h" @@ -443,18 +443,12 @@ void app_main(void) lv_init(); // 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 - lv_color_t *buf1 = NULL; - lv_color_t *buf2 = NULL; - esp_dma_mem_info_t dma_mem_info = { - .dma_alignment_bytes = 4, + uint32_t draw_buf_alloc_caps = 0; #if CONFIG_EXAMPLE_LCD_I80_COLOR_IN_PSRAM - .extra_heap_caps = MALLOC_CAP_SPIRAM, -#else - .extra_heap_caps = MALLOC_CAP_INTERNAL, -#endif // CONFIG_EXAMPLE_LCD_I80_COLOR_IN_PSRAM - }; - ESP_ERROR_CHECK(esp_dma_capable_malloc(EXAMPLE_LCD_H_RES * 100 * sizeof(lv_color_t), &dma_mem_info, (void *)&buf1, NULL)); - ESP_ERROR_CHECK(esp_dma_capable_malloc(EXAMPLE_LCD_H_RES * 100 * sizeof(lv_color_t), &dma_mem_info, (void *)&buf2, NULL)); + draw_buf_alloc_caps |= MALLOC_CAP_SPIRAM; +#endif + lv_color_t *buf1 = esp_lcd_i80_alloc_draw_buffer(io_handle, EXAMPLE_LCD_H_RES * 100 * sizeof(lv_color_t), draw_buf_alloc_caps); + lv_color_t *buf2 = esp_lcd_i80_alloc_draw_buffer(io_handle, EXAMPLE_LCD_H_RES * 100 * sizeof(lv_color_t), draw_buf_alloc_caps); assert(buf1); assert(buf2); ESP_LOGI(TAG, "buf1@%p, buf2@%p", buf1, buf2);