diff --git a/bsp/esp32_s3_lcd_ev_board/idf_component.yml b/bsp/esp32_s3_lcd_ev_board/idf_component.yml index 02e1e8eb8..c7a251c44 100644 --- a/bsp/esp32_s3_lcd_ev_board/idf_component.yml +++ b/bsp/esp32_s3_lcd_ev_board/idf_component.yml @@ -1,4 +1,4 @@ -version: "2.1.0" +version: "3.0.0" description: Board Support Package for ESP32-S3-LCD-EV-Board url: https://github.com/espressif/esp-bsp/tree/master/bsp/esp32_s3_lcd_ev_board @@ -44,5 +44,10 @@ dependencies: version: ">=2.5,<4.0" public: true + esp_lvgl_port: + version: "^2" + override_path: '../../components/esp_lvgl_port' + public: true + examples: - path: ../../examples/display_lvgl_demos diff --git a/bsp/esp32_s3_lcd_ev_board/include/bsp/esp32_s3_lcd_ev_board.h b/bsp/esp32_s3_lcd_ev_board/include/bsp/esp32_s3_lcd_ev_board.h index 7bd5b8ba4..1c91b7446 100644 --- a/bsp/esp32_s3_lcd_ev_board/include/bsp/esp32_s3_lcd_ev_board.h +++ b/bsp/esp32_s3_lcd_ev_board/include/bsp/esp32_s3_lcd_ev_board.h @@ -21,6 +21,7 @@ #include "esp_lcd_gc9503.h" #include "iot_button.h" #include "lvgl.h" +#include "esp_lvgl_port.h" #include "sdkconfig.h" @@ -96,7 +97,7 @@ extern "C" { * */ typedef struct { - void *dummy; /*!< Prepared for future use. */ + lvgl_port_cfg_t lvgl_port_cfg; } bsp_display_cfg_t; /************************************************************************************************** diff --git a/bsp/esp32_s3_lcd_ev_board/priv_include/bsp_lvgl_port.h b/bsp/esp32_s3_lcd_ev_board/priv_include/bsp_lvgl_port.h index 34cc0f478..b01f7efe5 100644 --- a/bsp/esp32_s3_lcd_ev_board/priv_include/bsp_lvgl_port.h +++ b/bsp/esp32_s3_lcd_ev_board/priv_include/bsp_lvgl_port.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -18,36 +18,13 @@ extern "C" { #endif /** - * @brief Initialize LVGL port + * @brief Initialize LCD panel and LVGL portation * - * @param[in] lcd: LCD panel handle - * @param[in] tp: Touch handle - * @param[out] disp: LVGL display device - * @param[out] indev: LVGL input device + * @note This function initialize RGB LCD panel and add add disp to LVGL. * - * @return - * - ESP_OK: Success - * - ESP_ERR_INVALID_ARG: Invalid argument - * - Others: Fail + * @return Pointer to LVGL display or NULL when error occured */ -esp_err_t bsp_lvgl_port_init(esp_lcd_panel_handle_t lcd, esp_lcd_touch_handle_t tp, lv_disp_t **disp, lv_indev_t **indev); - -/** - * @brief Take LVGL mutex - * - * @param[in] timeout_ms: Timeout in [ms]. 0 will block indefinitely. - * - * @return - * - true: Mutex was taken - * - false: Mutex was NOT taken - */ -bool bsp_lvgl_port_lock(uint32_t timeout_ms); - -/** - * @brief Give LVGL mutex - * - */ -void bsp_lvgl_port_unlock(void); +lv_disp_t *bsp_display_lcd_init(); #ifdef __cplusplus } diff --git a/bsp/esp32_s3_lcd_ev_board/src/bsp_lvgl_port.c b/bsp/esp32_s3_lcd_ev_board/src/bsp_lvgl_port.c index a62d67bc3..ca8f796c6 100644 --- a/bsp/esp32_s3_lcd_ev_board/src/bsp_lvgl_port.c +++ b/bsp/esp32_s3_lcd_ev_board/src/bsp_lvgl_port.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -18,8 +18,6 @@ #include "bsp/esp32_s3_lcd_ev_board.h" static const char *TAG = "bsp_lvgl_port"; -static SemaphoreHandle_t lvgl_mux; // LVGL mutex -static TaskHandle_t lvgl_task_handle = NULL; #if CONFIG_BSP_DISPLAY_LVGL_ROTATION_DEGREE != 0 static void *get_next_frame_buffer(esp_lcd_panel_handle_t panel_handle) @@ -186,7 +184,8 @@ static void flush_dirty_copy(void *dst, void *src, lv_port_dirty_area_t *dirty_a static void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map) { - esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t) drv->user_data; + lvgl_port_display_ctx_t *disp_ctx = (lvgl_port_display_ctx_t *)drv->user_data; + esp_lcd_panel_handle_t panel_handle = disp_ctx->panel_handle; const int offsetx1 = area->x1; const int offsetx2 = area->x2; const int offsety1 = area->y1; @@ -297,7 +296,8 @@ static void flush_dirty_copy(void *dst, void *src, lv_port_dirty_area_t *dirty_a static void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map) { - esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t) drv->user_data; + lvgl_port_display_ctx_t *disp_ctx = (lvgl_port_display_ctx_t *)drv->user_data; + esp_lcd_panel_handle_t panel_handle = disp_ctx->panel_handle; const int offsetx1 = area->x1; const int offsetx2 = area->x2; const int offsety1 = area->y1; @@ -360,7 +360,8 @@ static void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t static void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map) { - esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t) drv->user_data; + lvgl_port_display_ctx_t *disp_ctx = (lvgl_port_display_ctx_t *)drv->user_data; + esp_lcd_panel_handle_t panel_handle = disp_ctx->panel_handle; const int offsetx1 = area->x1; const int offsetx2 = area->x2; const int offsety1 = area->y1; @@ -386,7 +387,8 @@ static void *lvgl_port_flush_next_buf = NULL; void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map) { - esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t) drv->user_data; + lvgl_port_display_ctx_t *disp_ctx = (lvgl_port_display_ctx_t *)drv->user_data; + esp_lcd_panel_handle_t panel_handle = disp_ctx->panel_handle; const int offsetx1 = area->x1; const int offsetx2 = area->x2; const int offsety1 = area->y1; @@ -415,9 +417,13 @@ void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color } #endif -static bool lcd_trans_done(esp_lcd_panel_handle_t handle) +static BaseType_t lcd_trans_done(esp_lcd_panel_handle_t panel, void *user_ctx) { BaseType_t need_yield = pdFALSE; + + lvgl_port_display_ctx_t *disp_ctx = ((lv_disp_drv_t *)user_ctx)->user_data; + TaskHandle_t lvgl_task_handle = disp_ctx->lvgl_task_handle; + #if CONFIG_BSP_DISPLAY_LVGL_FULL_REFRESH && (CONFIG_BSP_LCD_RGB_BUFFER_NUMS == 3) && (CONFIG_BSP_DISPLAY_LVGL_ROTATION_DEGREE == 0) if (lvgl_port_rgb_next_buf != lvgl_port_rgb_last_buf) { lvgl_port_flush_next_buf = lvgl_port_rgb_last_buf; @@ -434,7 +440,8 @@ static bool lcd_trans_done(esp_lcd_panel_handle_t handle) void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map) { - esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t) drv->user_data; + lvgl_port_display_ctx_t *disp_ctx = (lvgl_port_display_ctx_t *)drv->user_data; + esp_lcd_panel_handle_t panel_handle = disp_ctx->panel_handle; const int offsetx1 = area->x1; const int offsetx2 = area->x2; const int offsety1 = area->y1; @@ -450,7 +457,10 @@ void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color static void update_callback(lv_disp_drv_t *drv) { - esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t) drv->user_data; + assert(drv != NULL); + lvgl_port_display_ctx_t *disp_ctx = (lvgl_port_display_ctx_t *)drv->user_data; + assert(disp_ctx != NULL); + esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t) disp_ctx->panel_handle; switch (drv->rotated) { case LV_DISP_ROT_NONE: @@ -472,12 +482,14 @@ static void update_callback(lv_disp_drv_t *drv) } } -static lv_disp_t *display_init(esp_lcd_panel_handle_t lcd) +lv_disp_t *bsp_display_lcd_init() { - BSP_NULL_CHECK(lcd, NULL); + esp_lcd_panel_io_handle_t io_handle = NULL; + esp_lcd_panel_handle_t panel_handle = NULL; // LCD panel handle + + bsp_display_config_t disp_config = { 0 }; - static lv_disp_draw_buf_t disp_buf = { 0 }; // Contains internal graphic buffer(s) called draw buffer(s) - static lv_disp_drv_t disp_drv = { 0 }; // Contains LCD panel handle and callback functions + BSP_ERROR_CHECK_RETURN_NULL(bsp_display_new(&disp_config, &panel_handle, &io_handle)); // alloc draw buffers used by LVGL void *buf1 = NULL; @@ -496,167 +508,68 @@ static lv_disp_t *display_init(esp_lcd_panel_handle_t lcd) buffer_size = BSP_LCD_H_RES * BSP_LCD_V_RES; #if (CONFIG_BSP_LCD_RGB_BUFFER_NUMS == 3) && (CONFIG_BSP_DISPLAY_LVGL_ROTATION_DEGREE == 0) && CONFIG_BSP_DISPLAY_LVGL_FULL_REFRESH // With the usage of three buffers and full-refresh, we always have one buffer available for rendering, eliminating the need to wait for the RGB's sync signal - BSP_ERROR_CHECK_RETURN_NULL(esp_lcd_rgb_panel_get_frame_buffer(lcd, 3, &lvgl_port_rgb_last_buf, &buf1, &buf2)); + BSP_ERROR_CHECK_RETURN_NULL(esp_lcd_rgb_panel_get_frame_buffer(panel_handle, 3, &lvgl_port_rgb_last_buf, &buf1, &buf2)); lvgl_port_rgb_next_buf = lvgl_port_rgb_last_buf; lvgl_port_flush_next_buf = buf2; #elif (CONFIG_BSP_LCD_RGB_BUFFER_NUMS == 3) && (CONFIG_BSP_DISPLAY_LVGL_ROTATION_DEGREE != 0) // Here we are using three frame buffers, one for LVGL rendering, and the other two for RGB driver (one of them is used for rotation) void *fbs[3]; - BSP_ERROR_CHECK_RETURN_NULL(esp_lcd_rgb_panel_get_frame_buffer(lcd, 3, &fbs[0], &fbs[1], &fbs[2])); + BSP_ERROR_CHECK_RETURN_NULL(esp_lcd_rgb_panel_get_frame_buffer(panel_handle, 3, &fbs[0], &fbs[1], &fbs[2])); buf1 = fbs[2]; #else - BSP_ERROR_CHECK_RETURN_NULL(esp_lcd_rgb_panel_get_frame_buffer(lcd, 2, &buf1, &buf2)); + BSP_ERROR_CHECK_RETURN_NULL(esp_lcd_rgb_panel_get_frame_buffer(panel_handle, 2, &buf1, &buf2)); #endif #endif /* CONFIG_BSP_DISPLAY_LVGL_AVOID_TEAR */ - // initialize LVGL draw buffers - lv_disp_draw_buf_init(&disp_buf, buf1, buf2, buffer_size); + const lvgl_port_display_cfg_t disp_cfg = { + .io_handle = io_handle, + .panel_handle = panel_handle, + .buffer_size = buffer_size, - ESP_LOGD(TAG, "Register display driver to LVGL"); - lv_disp_drv_init(&disp_drv); #if CONFIG_BSP_DISPLAY_LVGL_ROTATION_90 || CONFIG_BSP_DISPLAY_LVGL_ROTATION_270 - disp_drv.hor_res = BSP_LCD_V_RES; - disp_drv.ver_res = BSP_LCD_H_RES; + .hres = BSP_LCD_V_RES, + .vres = BSP_LCD_H_RES, #else - disp_drv.hor_res = BSP_LCD_H_RES; - disp_drv.ver_res = BSP_LCD_V_RES; -#endif - disp_drv.flush_cb = flush_callback; - disp_drv.drv_update_cb = update_callback; - disp_drv.draw_buf = &disp_buf; - disp_drv.user_data = lcd; -#if CONFIG_BSP_DISPLAY_LVGL_FULL_REFRESH - disp_drv.full_refresh = 1; -#elif CONFIG_BSP_DISPLAY_LVGL_DIRECT_MODE - disp_drv.direct_mode = 1; + .hres = BSP_LCD_H_RES, + .vres = BSP_LCD_V_RES, #endif - return lv_disp_drv_register(&disp_drv); -} - -static void touchpad_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data) -{ - esp_lcd_touch_handle_t tp = (esp_lcd_touch_handle_t)indev_drv->user_data; - assert(tp); - - uint16_t touchpad_x; - uint16_t touchpad_y; - uint8_t touchpad_cnt = 0; - /* Read data from touch controller into memory */ - esp_lcd_touch_read_data(tp); - - /* Read data from touch controller */ - bool touchpad_pressed = esp_lcd_touch_get_coordinates(tp, &touchpad_x, &touchpad_y, NULL, &touchpad_cnt, 1); - if (touchpad_pressed && touchpad_cnt > 0) { - data->point.x = touchpad_x; - data->point.y = touchpad_y; - data->state = LV_INDEV_STATE_PRESSED; - ESP_LOGD(TAG, "Touch position: %d,%d", touchpad_x, touchpad_y); - } else { - data->state = LV_INDEV_STATE_RELEASED; - } -} - -static lv_indev_t *indev_init(esp_lcd_touch_handle_t tp) -{ - BSP_NULL_CHECK(tp, NULL); - - static lv_indev_drv_t indev_drv_tp; - - /* Register a touchpad input device */ - lv_indev_drv_init(&indev_drv_tp); - indev_drv_tp.type = LV_INDEV_TYPE_POINTER; - indev_drv_tp.read_cb = touchpad_read; - indev_drv_tp.user_data = tp; - - return lv_indev_drv_register(&indev_drv_tp); -} - -static void tick_increment(void *arg) -{ - /* Tell LVGL how many milliseconds have elapsed */ - lv_tick_inc(LVGL_TICK_PERIOD_MS); -} - -static esp_err_t tick_init(void) -{ - // Tick interface for LVGL (using esp_timer to generate 2ms periodic event) - const esp_timer_create_args_t lvgl_tick_timer_args = { - .callback = &tick_increment, - .name = "LVGL tick" - }; - esp_timer_handle_t lvgl_tick_timer = NULL; - BSP_ERROR_CHECK_RETURN_ERR(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer)); - return esp_timer_start_periodic(lvgl_tick_timer, LVGL_TICK_PERIOD_MS * 1000); -} - -static void lvgl_port_task(void *arg) -{ - ESP_LOGI(TAG, "Starting LVGL task"); - while (1) { - bsp_display_lock(0); - uint32_t task_delay_ms = lv_timer_handler(); - bsp_display_unlock(); - if (task_delay_ms > 500) { - task_delay_ms = 500; - } else if (task_delay_ms < CONFIG_BSP_DISPLAY_LVGL_TASK_DELAY) { - task_delay_ms = CONFIG_BSP_DISPLAY_LVGL_TASK_DELAY; - } - vTaskDelay(pdMS_TO_TICKS(task_delay_ms)); - } -} -esp_err_t bsp_lvgl_port_init(esp_lcd_panel_handle_t lcd, esp_lcd_touch_handle_t tp, lv_disp_t **disp, lv_indev_t **indev) -{ - BSP_NULL_CHECK(lcd, ESP_ERR_INVALID_ARG); - BSP_NULL_CHECK(tp, ESP_ERR_INVALID_ARG); - BSP_NULL_CHECK(disp, ESP_ERR_INVALID_ARG); - BSP_NULL_CHECK(indev, ESP_ERR_INVALID_ARG); - - lv_init(); - BSP_ERROR_CHECK_RETURN_ERR(tick_init()); - BSP_NULL_CHECK(*disp = display_init(lcd), ESP_FAIL); - BSP_NULL_CHECK(*indev = indev_init(tp), ESP_FAIL); - -#if CONFIG_BSP_DISPLAY_LVGL_ROTATION_90 - esp_lcd_touch_set_swap_xy(tp, true); - esp_lcd_touch_set_mirror_y(tp, true); -#elif CONFIG_BSP_DISPLAY_LVGL_ROTATION_180 - esp_lcd_touch_set_mirror_x(tp, true); - esp_lcd_touch_set_mirror_y(tp, true); -#elif CONFIG_BSP_DISPLAY_LVGL_ROTATION_270 - esp_lcd_touch_set_swap_xy(tp, true); - esp_lcd_touch_set_mirror_x(tp, true); -#endif + .flags = { + .interface_RGB = true, + }, - lvgl_mux = xSemaphoreCreateRecursiveMutex(); - BSP_NULL_CHECK(lvgl_mux, ESP_FAIL); - ESP_LOGI(TAG, "Create LVGL task"); - BaseType_t core_id = (CONFIG_BSP_DISPLAY_LVGL_TASK_CORE_ID < 0) ? tskNO_AFFINITY : CONFIG_BSP_DISPLAY_LVGL_TASK_CORE_ID; - BaseType_t ret = xTaskCreatePinnedToCore( - lvgl_port_task, "LVGL", CONFIG_BSP_DISPLAY_LVGL_TASK_STACK_SIZE_KB * 1024, NULL, - CONFIG_BSP_DISPLAY_LVGL_TASK_PRIORITY, &lvgl_task_handle, core_id - ); - if (ret != pdPASS) { - ESP_LOGE(TAG, "Failed to create LVGL task"); - return ESP_FAIL; - } + .user_lv_flush_cb = flush_callback, + .user_lv_update_cb = update_callback, #if CONFIG_BSP_DISPLAY_LVGL_AVOID_TEAR - bsp_display_register_trans_done_callback(lcd_trans_done); + .user_lcd_transdone_cb = lcd_trans_done, #endif + .user_buf1 = buf1, + .user_buf2 = buf2, - return ESP_OK; -} - -bool bsp_lvgl_port_lock(uint32_t timeout_ms) -{ - assert(lvgl_mux && "bsp_lvgl_port_init must be called first"); +#if CONFIG_BSP_DISPLAY_LVGL_FULL_REFRESH + .refresh_mode.full_refresh = 1, +#elif CONFIG_BSP_DISPLAY_LVGL_DIRECT_MODE + .refresh_mode.direct_mode = 1, +#endif - const TickType_t timeout_ticks = (timeout_ms == 0) ? portMAX_DELAY : pdMS_TO_TICKS(timeout_ms); - return xSemaphoreTakeRecursive(lvgl_mux, timeout_ticks) == pdTRUE; -} +#if CONFIG_BSP_LCD_RGB_REFRESH_MANUALLY + .trans_mode = { + .manual_mode = 1, + .flags = { + .ref_period = CONFIG_BSP_LCD_RGB_REFRESH_TASK_PERIOD, + .ref_priority = CONFIG_BSP_LCD_RGB_REFRESH_TASK_PRIORITY, + } + }, +#elif CONFIG_BSP_LCD_RGB_BOUNCE_BUFFER_MODE + .trans_mode = { + .bb_mode = 1, + } +#elif CONFIG_BSP_LCD_RGB_REFRESH_AUTO + .trans_mode = { + .audo_mode = 1, + } +#endif + }; -void bsp_lvgl_port_unlock(void) -{ - assert(lvgl_mux && "bsp_lvgl_port_init must be called first"); - xSemaphoreGiveRecursive(lvgl_mux); + return lvgl_port_add_disp(&disp_cfg); } diff --git a/bsp/esp32_s3_lcd_ev_board/src/bsp_sub_board.c b/bsp/esp32_s3_lcd_ev_board/src/bsp_sub_board.c index 164d6a6cf..d81ab02f8 100644 --- a/bsp/esp32_s3_lcd_ev_board/src/bsp_sub_board.c +++ b/bsp/esp32_s3_lcd_ev_board/src/bsp_sub_board.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -35,45 +35,12 @@ #endif static const char *TAG = "bsp_sub_board"; -static bsp_display_trans_done_cb_t trans_done = NULL; -#if CONFIG_BSP_LCD_RGB_REFRESH_MANUALLY -static TaskHandle_t lcd_task_handle = NULL; -#endif /************************************************************************************************** * * Display Panel Function * **************************************************************************************************/ -IRAM_ATTR static bool rgb_lcd_on_vsync_event(esp_lcd_panel_handle_t panel, const esp_lcd_rgb_panel_event_data_t *edata, void *user_ctx) -{ - BaseType_t need_yield = pdFALSE; -#if CONFIG_BSP_LCD_RGB_REFRESH_MANUALLY - xTaskNotifyFromISR(lcd_task_handle, ULONG_MAX, eNoAction, &need_yield); -#endif - if (trans_done) { - if (trans_done(panel)) { - need_yield = pdTRUE; - } - } - - return (need_yield == pdTRUE); -} - -#if CONFIG_BSP_LCD_RGB_REFRESH_MANUALLY -static void lcd_task(void *arg) -{ - ESP_LOGI(TAG, "Starting LCD refresh task"); - - TickType_t tick; - for (;;) { - esp_lcd_rgb_panel_refresh((esp_lcd_panel_handle_t)arg); - tick = xTaskGetTickCount(); - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - vTaskDelayUntil(&tick, pdMS_TO_TICKS(CONFIG_BSP_LCD_RGB_REFRESH_TASK_PERIOD)); - } -} -#endif esp_err_t bsp_display_new(const bsp_display_config_t *config, esp_lcd_panel_handle_t *ret_panel, esp_lcd_panel_io_handle_t *ret_io) { @@ -196,14 +163,6 @@ drift, please enable `ESP32S3_DATA_CACHE_LINE_32B` instead"); #else BSP_ERROR_CHECK_RETURN_ERR(esp_lcd_new_panel_gc9503(io_handle, &rgb_conf, &panel_handle)); #endif - esp_lcd_rgb_panel_event_callbacks_t cbs = { -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 2) && CONFIG_BSP_LCD_RGB_BOUNCE_BUFFER_MODE - .on_bounce_frame_finish = rgb_lcd_on_vsync_event, -#else - .on_vsync = rgb_lcd_on_vsync_event, -#endif - }; - esp_lcd_rgb_panel_register_event_callbacks(panel_handle, &cbs, NULL); break; } case SUB_BOARD_TYPE_3_800_480: { @@ -252,14 +211,6 @@ drift, please enable `ESP32S3_DATA_CACHE_LINE_32B` instead"); panel_conf.data_gpio_nums[7] = BSP_LCD_SUB_BOARD_2_3_DATA7_R16; } BSP_ERROR_CHECK_RETURN_ERR(esp_lcd_new_rgb_panel(&panel_conf, &panel_handle)); - esp_lcd_rgb_panel_event_callbacks_t cbs = { -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 2) && CONFIG_BSP_LCD_RGB_BOUNCE_BUFFER_MODE - .on_bounce_frame_finish = rgb_lcd_on_vsync_event, -#else - .on_vsync = rgb_lcd_on_vsync_event, -#endif - }; - esp_lcd_rgb_panel_register_event_callbacks(panel_handle, &cbs, NULL); break; } default: @@ -267,15 +218,6 @@ drift, please enable `ESP32S3_DATA_CACHE_LINE_32B` instead"); } BSP_ERROR_CHECK_RETURN_ERR(esp_lcd_panel_init(panel_handle)); -#if CONFIG_BSP_LCD_RGB_REFRESH_MANUALLY - ESP_LOGI(TAG, "Create LCD task"); - BaseType_t ret = xTaskCreate(lcd_task, "LCD", 2048, panel_handle, CONFIG_BSP_LCD_RGB_REFRESH_TASK_PRIORITY, &lcd_task_handle); - if (ret != pdPASS) { - ESP_LOGE(TAG, "Failed to create LCD task"); - return ESP_FAIL; - } -#endif - if (ret_panel) { *ret_panel = panel_handle; } @@ -286,18 +228,6 @@ drift, please enable `ESP32S3_DATA_CACHE_LINE_32B` instead"); return ESP_OK; } -esp_err_t bsp_display_register_trans_done_callback(bsp_display_trans_done_cb_t callback) -{ -#if CONFIG_LCD_RGB_ISR_IRAM_SAFE - if (callback) { - ESP_RETURN_ON_FALSE(esp_ptr_in_iram(callback), ESP_ERR_INVALID_ARG, TAG, "Callback not in IRAM"); - } -#endif - trans_done = callback; - - return ESP_OK; -} - /************************************************************************************************** * * Touch Panel Function diff --git a/bsp/esp32_s3_lcd_ev_board/src/esp32_s3_lcd_ev_board.c b/bsp/esp32_s3_lcd_ev_board/src/esp32_s3_lcd_ev_board.c index a95695280..06c87f59a 100644 --- a/bsp/esp32_s3_lcd_ev_board/src/esp32_s3_lcd_ev_board.c +++ b/bsp/esp32_s3_lcd_ev_board/src/esp32_s3_lcd_ev_board.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -26,6 +26,8 @@ #include "bsp_lvgl_port.h" #include "bsp_probe.h" +#include "esp_lvgl_port.h" + #define BSP_ES7210_CODEC_ADDR (0x82) /* Can be used for `i2s_std_gpio_config_t` and/or `i2s_std_config_t` initialization */ @@ -58,9 +60,12 @@ static const audio_codec_data_if_t *i2s_data_if = NULL; /* Codec data interface static i2s_chan_handle_t i2s_tx_chan = NULL; static i2s_chan_handle_t i2s_rx_chan = NULL; static esp_io_expander_handle_t io_expander = NULL; // IO expander tca9554 handle -static lv_indev_t *disp_indev = NULL; static adc_oneshot_unit_handle_t bsp_adc_handle = NULL; +static lv_disp_t *disp; +static lv_indev_t *disp_indev = NULL; +static esp_lcd_touch_handle_t tp; // LCD touch handle + static const button_config_t bsp_button_config[BSP_BUTTON_NUM] = { { .type = BUTTON_TYPE_GPIO, @@ -311,6 +316,30 @@ esp_err_t bsp_audio_poweramp_enable(bool enable) return ESP_OK; } +static lv_indev_t *bsp_display_indev_init(lv_disp_t *disp) +{ + BSP_ERROR_CHECK_RETURN_NULL(bsp_touch_new(NULL, &tp)); + assert(tp); + +#if CONFIG_BSP_DISPLAY_LVGL_ROTATION_90 + esp_lcd_touch_set_swap_xy(tp, true); + esp_lcd_touch_set_mirror_y(tp, true); +#elif CONFIG_BSP_DISPLAY_LVGL_ROTATION_180 + esp_lcd_touch_set_mirror_x(tp, true); + esp_lcd_touch_set_mirror_y(tp, true); +#elif CONFIG_BSP_DISPLAY_LVGL_ROTATION_270 + esp_lcd_touch_set_swap_xy(tp, true); + esp_lcd_touch_set_mirror_x(tp, true); +#endif + /* Add touch input (for selected screen) */ + const lvgl_port_touch_cfg_t touch_cfg = { + .disp = disp, + .handle = tp, + }; + + return lvgl_port_add_touch(&touch_cfg); +} + /********************************************************************************************************** * * Display Function @@ -318,20 +347,21 @@ esp_err_t bsp_audio_poweramp_enable(bool enable) **********************************************************************************************************/ lv_disp_t *bsp_display_start(void) { - return bsp_display_start_with_config(NULL); + bsp_display_cfg_t cfg = { + .lvgl_port_cfg = ESP_LVGL_PORT_INIT_CONFIG() + }; + cfg.lvgl_port_cfg.task_stack = CONFIG_BSP_DISPLAY_LVGL_TASK_STACK_SIZE_KB * 1024; + + return bsp_display_start_with_config(&cfg); } lv_disp_t *bsp_display_start_with_config(const bsp_display_cfg_t *cfg) { - (void)cfg; - bsp_display_config_t disp_config = { 0 }; - esp_lcd_panel_handle_t lcd = NULL; // LCD panel handle - esp_lcd_touch_handle_t tp = NULL; // LCD touch panel handle - lv_disp_t *disp = NULL; + BSP_ERROR_CHECK_RETURN_NULL(lvgl_port_init(&cfg->lvgl_port_cfg)); /* lvgl task, tick etc*/ - BSP_ERROR_CHECK_RETURN_NULL(bsp_display_new(&disp_config, &lcd, NULL)); - BSP_ERROR_CHECK_RETURN_NULL(bsp_touch_new(NULL, &tp)); - BSP_ERROR_CHECK_RETURN_NULL(bsp_lvgl_port_init(lcd, tp, &disp, &disp_indev)); + BSP_NULL_CHECK(disp = bsp_display_lcd_init(), NULL); + + BSP_NULL_CHECK(disp_indev = bsp_display_indev_init(disp), NULL); return disp; } @@ -368,12 +398,12 @@ void bsp_display_rotate(lv_disp_t *disp, lv_disp_rot_t rotation) bool bsp_display_lock(uint32_t timeout_ms) { - return bsp_lvgl_port_lock(timeout_ms); + return lvgl_port_lock(timeout_ms); } void bsp_display_unlock(void) { - bsp_lvgl_port_unlock(); + lvgl_port_unlock(); } /************************************************************************************************** diff --git a/components/esp_lvgl_port/CMakeLists.txt b/components/esp_lvgl_port/CMakeLists.txt index 9a9edb3f2..ab38ef541 100644 --- a/components/esp_lvgl_port/CMakeLists.txt +++ b/components/esp_lvgl_port/CMakeLists.txt @@ -1,6 +1,6 @@ file(GLOB_RECURSE IMAGE_SOURCES images/*.c) -idf_component_register(SRCS "esp_lvgl_port.c" ${IMAGE_SOURCES} INCLUDE_DIRS "include" REQUIRES "esp_lcd" PRIV_REQUIRES "esp_timer") +idf_component_register(SRCS "esp_lvgl_port.c" "esp_lvgl_rgb.c" ${IMAGE_SOURCES} INCLUDE_DIRS "include" "priv_include" REQUIRES "esp_lcd" PRIV_REQUIRES "esp_timer") idf_build_get_property(build_components BUILD_COMPONENTS) if("espressif__button" IN_LIST build_components) diff --git a/components/esp_lvgl_port/esp_lvgl_port.c b/components/esp_lvgl_port/esp_lvgl_port.c index 85c47b258..5b677d993 100644 --- a/components/esp_lvgl_port/esp_lvgl_port.c +++ b/components/esp_lvgl_port/esp_lvgl_port.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -14,7 +14,9 @@ #include "freertos/semphr.h" #include "esp_lcd_panel_io.h" #include "esp_lcd_panel_ops.h" +#include "esp_lcd_panel_rgb.h" #include "esp_lvgl_port.h" +#include "esp_lvgl_rgb.h" #include "lvgl.h" @@ -80,13 +82,6 @@ typedef struct lvgl_port_ctx_s { #endif } lvgl_port_ctx_t; -typedef struct { - esp_lcd_panel_io_handle_t io_handle; /* LCD panel IO handle */ - esp_lcd_panel_handle_t panel_handle; /* LCD panel handle */ - lvgl_port_rotation_cfg_t rotation; /* Default values of the screen rotation */ - lv_disp_drv_t disp_drv; /* LVGL display driver */ -} lvgl_port_display_ctx_t; - #ifdef ESP_LVGL_PORT_TOUCH_COMPONENT typedef struct { esp_lcd_touch_handle_t handle; /* LCD touch IO handle */ @@ -126,6 +121,7 @@ typedef struct { *******************************************************************************/ static lvgl_port_ctx_t lvgl_port_ctx; static int lvgl_port_timer_period_ms = 5; +static TaskHandle_t lvgl_port_task_handle = NULL; /******************************************************************************* * Function definitions @@ -189,9 +185,9 @@ esp_err_t lvgl_port_init(const lvgl_port_cfg_t *cfg) BaseType_t res; if (cfg->task_affinity < 0) { - res = xTaskCreate(lvgl_port_task, "LVGL task", cfg->task_stack, NULL, cfg->task_priority, NULL); + res = xTaskCreate(lvgl_port_task, "LVGL task", cfg->task_stack, NULL, cfg->task_priority, &lvgl_port_task_handle); } else { - res = xTaskCreatePinnedToCore(lvgl_port_task, "LVGL task", cfg->task_stack, NULL, cfg->task_priority, NULL, cfg->task_affinity); + res = xTaskCreatePinnedToCore(lvgl_port_task, "LVGL task", cfg->task_stack, NULL, cfg->task_priority, &lvgl_port_task_handle, cfg->task_affinity); } ESP_GOTO_ON_FALSE(res == pdPASS, ESP_FAIL, err, TAG, "Create LVGL task fail!"); @@ -268,23 +264,33 @@ lv_disp_t *lvgl_port_add_disp(const lvgl_port_display_cfg_t *disp_cfg) disp_ctx->rotation.mirror_x = disp_cfg->rotation.mirror_x; disp_ctx->rotation.mirror_y = disp_cfg->rotation.mirror_y; - uint32_t buff_caps = MALLOC_CAP_DEFAULT; - 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!"); - } else if (disp_cfg->flags.buff_dma) { - buff_caps = MALLOC_CAP_DMA; - } else if (disp_cfg->flags.buff_spiram) { - buff_caps = MALLOC_CAP_SPIRAM; - } + disp_ctx->lcd_transdone_cb = disp_cfg->user_lcd_transdone_cb; + disp_ctx->lcd_manual_mode = disp_cfg->trans_mode.manual_mode; + disp_ctx->lvgl_task_handle = lvgl_port_task_handle; - /* 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(disp_cfg->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(disp_cfg->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!"); + if (disp_cfg->user_buf1 || disp_cfg->user_buf2) { + buf1 = disp_cfg->user_buf1; + buf2 = disp_cfg->user_buf2; + } else { + uint32_t buff_caps = MALLOC_CAP_DEFAULT; + 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!"); + } else if (disp_cfg->flags.buff_dma) { + buff_caps = MALLOC_CAP_DMA; + } else if (disp_cfg->flags.buff_spiram) { + buff_caps = MALLOC_CAP_SPIRAM; + } + + /* 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(disp_cfg->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(disp_cfg->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!"); + } } + lv_disp_draw_buf_t *disp_buf = malloc(sizeof(lv_disp_draw_buf_t)); ESP_GOTO_ON_FALSE(disp_buf, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for LVGL display buffer allocation!"); @@ -295,17 +301,29 @@ lv_disp_t *lvgl_port_add_disp(const lvgl_port_display_cfg_t *disp_cfg) lv_disp_drv_init(&disp_ctx->disp_drv); disp_ctx->disp_drv.hor_res = disp_cfg->hres; disp_ctx->disp_drv.ver_res = disp_cfg->vres; - disp_ctx->disp_drv.flush_cb = lvgl_port_flush_callback; - disp_ctx->disp_drv.drv_update_cb = lvgl_port_update_callback; + disp_ctx->disp_drv.flush_cb = (disp_cfg->user_lv_flush_cb) ? disp_cfg->user_lv_flush_cb : lvgl_port_flush_callback; + disp_ctx->disp_drv.drv_update_cb = (disp_cfg->user_lv_update_cb) ? disp_cfg->user_lv_update_cb : lvgl_port_update_callback; + + disp_ctx->disp_drv.full_refresh = disp_cfg->refresh_mode.full_refresh; + disp_ctx->disp_drv.direct_mode = disp_cfg->refresh_mode.direct_mode; + disp_ctx->disp_drv.draw_buf = disp_buf; disp_ctx->disp_drv.user_data = disp_ctx; + if (disp_cfg->trans_mode.manual_mode) { + lvgl_rgb_create_manual_task(disp_cfg); + } + #if LVGL_PORT_HANDLE_FLUSH_READY /* Register done callback */ - const esp_lcd_panel_io_callbacks_t cbs = { - .on_color_trans_done = lvgl_port_flush_ready_callback, - }; - esp_lcd_panel_io_register_event_callbacks(disp_ctx->io_handle, &cbs, &disp_ctx->disp_drv); + if (disp_cfg->flags.interface_RGB) { + lvgl_rgb_register_event_callbacks(disp_ctx, disp_cfg); + } else { + const esp_lcd_panel_io_callbacks_t cbs = { + .on_color_trans_done = lvgl_port_flush_ready_callback, + }; + esp_lcd_panel_io_register_event_callbacks(disp_ctx->io_handle, &cbs, &disp_ctx->disp_drv); + } #endif /* Monochrome display settings */ @@ -674,8 +692,6 @@ void lvgl_port_flush_ready(lv_disp_t *disp) lv_disp_flush_ready(disp->driver); } - - /******************************************************************************* * Private functions *******************************************************************************/ diff --git a/components/esp_lvgl_port/esp_lvgl_rgb.c b/components/esp_lvgl_port/esp_lvgl_rgb.c new file mode 100644 index 000000000..9b4e512e9 --- /dev/null +++ b/components/esp_lvgl_port/esp_lvgl_rgb.c @@ -0,0 +1,116 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_system.h" +#include "esp_log.h" +#include "esp_err.h" +#include "esp_check.h" +#include "esp_timer.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "esp_lcd_panel_io.h" +#include "esp_lcd_panel_ops.h" +#include "esp_lcd_panel_rgb.h" +#include "esp_lvgl_port.h" + +static const char *TAG = "LV_RGB"; + +#if CONFIG_IDF_TARGET_ESP32S3 && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) + +typedef struct { + esp_lcd_panel_handle_t rgb_handle; + uint32_t rgb_ref_period; +} lvgl_rgb_manual_ctx_t; + +static TaskHandle_t lvgl_rgb_manual_task_handle = NULL; + +IRAM_ATTR static bool lvgl_rgb_on_vsync_callback(esp_lcd_panel_handle_t panel_handle, const esp_lcd_rgb_panel_event_data_t *edata, void *user_ctx) +{ + BaseType_t need_yield = pdFALSE; + + lv_disp_drv_t *disp_drv = (lv_disp_drv_t *)user_ctx; + assert(disp_drv != NULL); + lvgl_port_display_ctx_t *disp_ctx = disp_drv->user_data; + + if (disp_ctx->lcd_manual_mode) { + xTaskNotifyFromISR(lvgl_rgb_manual_task_handle, ULONG_MAX, eNoAction, &need_yield); + } + + if (disp_ctx->lcd_transdone_cb) { + need_yield = disp_ctx->lcd_transdone_cb(panel_handle, user_ctx); + } + + return (need_yield == pdTRUE); +} + +esp_err_t lvgl_rgb_register_event_callbacks(lvgl_port_display_ctx_t *disp_ctx, const lvgl_port_display_cfg_t *disp_cfg) +{ + /* Register done callback */ + const esp_lcd_rgb_panel_event_callbacks_t vsync_cbs = { + .on_vsync = lvgl_rgb_on_vsync_callback, + }; + + const esp_lcd_rgb_panel_event_callbacks_t bb_cbs = { +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 2) + .on_bounce_frame_finish = lvgl_rgb_on_vsync_callback, +#endif + }; + + if (disp_cfg->trans_mode.bb_mode && (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 2))) { + ESP_ERROR_CHECK(esp_lcd_rgb_panel_register_event_callbacks(disp_ctx->panel_handle, &bb_cbs, &disp_ctx->disp_drv)); + } else { + ESP_ERROR_CHECK(esp_lcd_rgb_panel_register_event_callbacks(disp_ctx->panel_handle, &vsync_cbs, &disp_ctx->disp_drv)); + } + return ESP_OK; +} + +static void lvgl_rgb_manual_task(void *arg) +{ + TickType_t tick; + lvgl_rgb_manual_ctx_t *refresh = (lvgl_rgb_manual_ctx_t *)arg; + + ESP_LOGI(TAG, "Starting LCD refresh task"); + + for (;;) { + esp_lcd_rgb_panel_refresh(refresh->rgb_handle); + tick = xTaskGetTickCount(); + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + vTaskDelayUntil(&tick, pdMS_TO_TICKS(refresh->rgb_ref_period)); + } +} + +esp_err_t lvgl_rgb_create_manual_task(const lvgl_port_display_cfg_t *disp_cfg) +{ + static lvgl_rgb_manual_ctx_t refresh; + + refresh.rgb_handle = disp_cfg->panel_handle; + refresh.rgb_ref_period = disp_cfg->trans_mode.flags.ref_period; + + BaseType_t ret = xTaskCreate(lvgl_rgb_manual_task, "LCD", 2048, &refresh, disp_cfg->trans_mode.flags.ref_priority, &lvgl_rgb_manual_task_handle); + if (ret != pdPASS) { + ESP_LOGE(TAG, "Failed to create LCD task"); + return ESP_FAIL; + } + + return ESP_OK; +} + +#else + +esp_err_t lvgl_rgb_register_event_callbacks(lvgl_port_display_ctx_t *disp_ctx, const lvgl_port_display_cfg_t *disp_cfg) +{ + ESP_LOGE(TAG, "RGB mode not supported!"); + return ESP_ERR_NOT_SUPPORTED; +} + +esp_err_t lvgl_rgb_create_manual_task(const lvgl_port_display_cfg_t *disp_cfg) +{ + ESP_LOGE(TAG, "RGB mode not supported!"); + return ESP_ERR_NOT_SUPPORTED; +} + +#endif diff --git a/components/esp_lvgl_port/idf_component.yml b/components/esp_lvgl_port/idf_component.yml index c888f77a4..9607d036a 100644 --- a/components/esp_lvgl_port/idf_component.yml +++ b/components/esp_lvgl_port/idf_component.yml @@ -1,4 +1,4 @@ -version: "1.4.0" +version: "2.0.0" 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/include/esp_lvgl_port.h b/components/esp_lvgl_port/include/esp_lvgl_port.h index 4aac2e0cd..d7777fe45 100644 --- a/components/esp_lvgl_port/include/esp_lvgl_port.h +++ b/components/esp_lvgl_port/include/esp_lvgl_port.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -60,6 +60,36 @@ typedef struct { bool mirror_y; /*!< LCD Screen mirrored Y (in esp_lcd driver) */ } lvgl_port_rotation_cfg_t; + +/** + * @brief Write the internal buffer (draw_buf) to the display + * + */ +typedef void (*lv_flush_cb)(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map); + +/** + * @brief Called when driver parameters are updated + * + */ +typedef void (*lv_update_cb)(lv_disp_drv_t *drv); + +/** + * @brief LCD controller transdone interrupt user callback + * + */ +typedef BaseType_t (*lv_transdone_cb)(esp_lcd_panel_handle_t panel, void *user_ctx); + +typedef struct { + esp_lcd_panel_io_handle_t io_handle; /* LCD panel IO handle */ + esp_lcd_panel_handle_t panel_handle; /* LCD panel handle */ + lvgl_port_rotation_cfg_t rotation; /* Default values of the screen rotation */ + lv_disp_drv_t disp_drv; /* LVGL display driver */ + + TaskHandle_t lvgl_task_handle; /* LVGL task handle */ + lv_transdone_cb lcd_transdone_cb; /* RGB interface, lcd user transdone event */ + bool lcd_manual_mode; /* RGB interface, manually refresh or not */ +} lvgl_port_display_ctx_t; + /** * @brief Configuration display structure */ @@ -74,9 +104,33 @@ typedef struct { lvgl_port_rotation_cfg_t rotation; /*!< Default values of the screen rotation */ struct { - unsigned int buff_dma: 1; /*!< Allocated LVGL buffer will be DMA capable */ - unsigned int buff_spiram: 1; /*!< Allocated LVGL buffer will be in PSRAM */ + unsigned int buff_dma: 1; /*!< Allocated LVGL buffer will be DMA capable */ + unsigned int buff_spiram: 1; /*!< Allocated LVGL buffer will be in PSRAM */ + unsigned int interface_RGB: 1; /*!< Interface is RGB_TTL */ } flags; + + struct { + unsigned int full_refresh: 1; /*!< 1: Always make the whole screen redrawn */ + unsigned int direct_mode: 1; /*!< 1: Use screen-sized buffers and draw to absolute coordinates */ + } refresh_mode; + + struct { + unsigned int audo_mode: 1; /*!< 1: Always make the whole screen redrawn */ + unsigned int manual_mode: 1; /*!< 1: The host only refresh the frame buffer when `esp_lcd_panel_draw_bitmap` is called */ + unsigned int bb_mode: 1; /*!< 1: The driver allocates two DRAM bounce buffers for DMA use, it's much faster */ + struct { + unsigned int ref_period; /*!< Minimum Period(ms) of LCD refreshing task, depends on manual_mode*/ + unsigned int ref_priority; /*!< Priority of LCD refreshing task */ + } flags; + } trans_mode; + + lv_flush_cb user_lv_flush_cb; /*!< OPTIONAL: Write the draw_buf to the display */ + lv_update_cb user_lv_update_cb; /*!< OPTIONAL: Called when driver parameters are updated */ + lv_transdone_cb user_lcd_transdone_cb; /*!< OPTIONAL: User transmit done event */ + + void *user_buf1; /*!< OPTIONAL: A buffer to be used by LVGL to draw the image */ + void *user_buf2; /*!< OPTIONAL: Optionally specify a second buffer to render and flush */ + } lvgl_port_display_cfg_t; #ifdef ESP_LVGL_PORT_TOUCH_COMPONENT diff --git a/components/esp_lvgl_port/priv_include/esp_lvgl_rgb.h b/components/esp_lvgl_port/priv_include/esp_lvgl_rgb.h new file mode 100644 index 000000000..b3cd18099 --- /dev/null +++ b/components/esp_lvgl_port/priv_include/esp_lvgl_rgb.h @@ -0,0 +1,38 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief ESP LVGL port + */ + +#pragma once + +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Create a manual refresh task for the RGB interface + * + * @return + * - ESP_OK on success + */ +esp_err_t lvgl_rgb_create_manual_task(const lvgl_port_display_cfg_t *disp_cfg); + +/** + * @brief Registers the send completion event for the RGB interface + * + * @return + * - ESP_OK on success + */ +esp_err_t lvgl_rgb_register_event_callbacks(lvgl_port_display_ctx_t *disp_ctx, const lvgl_port_display_cfg_t *disp_cfg); + +#ifdef __cplusplus +} +#endif