Skip to content

Commit 58633c0

Browse files
committed
feat(esp_lvgl_port): Add support for esp_lcd_buffered
Support for buffered LCD panel is added as an optional extension. This functionality is available only if esp_lcd_buffered is included in the BUILD_COMPONENTS. esp_lcd_buffered should be added as a private or public dependency to one of the components in the project to use a buffered LCD panel driver with LVGL. Call lvgl_port_add_disp_buffered() to register a buffered panel.
1 parent f2180be commit 58633c0

File tree

4 files changed

+106
-21
lines changed

4 files changed

+106
-21
lines changed

components/esp_lvgl_port/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
### Features
66
- Added display flush wait callback support
7+
- Added support for buffered LCD panel (esp_lcd_buffered)
78

89
## 2.6.2
910

components/esp_lvgl_port/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,12 @@ if("usb_host_hid" IN_LIST build_components)
8484
list(APPEND ADD_SRCS "${PORT_PATH}/esp_lvgl_port_usbhid.c" "images/${PORT_FOLDER}/img_cursor.c")
8585
list(APPEND ADD_LIBS idf::usb_host_hid)
8686
endif()
87+
if("esp_lcd_buffered" IN_LIST build_components)
88+
list(APPEND ADD_LIBS idf::esp_lcd_buffered)
89+
endif()
90+
if("trigger239__esp_lcd_buffered" IN_LIST build_components)
91+
list(APPEND ADD_LIBS idf::trigger239__esp_lcd_buffered)
92+
endif()
8793

8894
# Include SIMD assembly source code for rendering, only for (9.1.0 <= LVG_version < 9.2.0) and only for esp32 and esp32s3
8995
if((lvgl_ver VERSION_GREATER_EQUAL "9.1.0") AND (lvgl_ver VERSION_LESS "9.2.0"))

components/esp_lvgl_port/include/esp_lvgl_port_disp.h

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -20,6 +20,11 @@
2020
#include "esp_lvgl_port_compatibility.h"
2121
#endif
2222

23+
#if __has_include ("esp_lcd_panel_buffered.h")
24+
#include "esp_lcd_panel_buffered.h"
25+
#define ESP_LVGL_PORT_USE_LCD_BUFFERED 1
26+
#endif
27+
2328
#ifdef __cplusplus
2429
extern "C" {
2530
#endif
@@ -85,6 +90,15 @@ typedef struct {
8590
} flags;
8691
} lvgl_port_display_dsi_cfg_t;
8792

93+
#if ESP_LVGL_PORT_USE_LCD_BUFFERED
94+
/**
95+
* @brief Configuration Buffered display structure
96+
*/
97+
typedef struct {
98+
esp_lcd_buffered_panel_sync_wait_cb_t wait_sync; /*!< Sync Wait callback function (use to avoid tearing) */
99+
} lvgl_port_display_buffered_cfg_t;
100+
#endif
101+
88102
/**
89103
* @brief Add I2C/SPI/I8080 display handling to LVGL
90104
*
@@ -117,6 +131,20 @@ lv_display_t *lvgl_port_add_disp_dsi(const lvgl_port_display_cfg_t *disp_cfg, co
117131
*/
118132
lv_display_t *lvgl_port_add_disp_rgb(const lvgl_port_display_cfg_t *disp_cfg, const lvgl_port_display_rgb_cfg_t *rgb_cfg);
119133

134+
#if ESP_LVGL_PORT_USE_LCD_BUFFERED
135+
/**
136+
* @brief Add Buffered display handling to LVGL
137+
*
138+
* @note Allocated memory in this function is not free in deinit. You must call lvgl_port_remove_disp for free all memory!
139+
*
140+
* @param disp_cfg Display configuration structure
141+
* @param buffered_cfg Buffered display specific configuration structure
142+
* @return Pointer to LVGL display or NULL when error occurred
143+
*/
144+
lv_display_t *lvgl_port_add_disp_buffered(const lvgl_port_display_cfg_t *disp_cfg,
145+
const lvgl_port_display_buffered_cfg_t *buffered_cfg);
146+
#endif
147+
120148
/**
121149
* @brief Remove display handling from LVGL
122150
*

components/esp_lvgl_port/src/lvgl9/esp_lvgl_port_disp.c

Lines changed: 70 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ typedef struct {
7979
static lv_display_t *lvgl_port_add_disp_priv(const lvgl_port_display_cfg_t *disp_cfg, const lvgl_port_disp_priv_cfg_t *priv_cfg);
8080
#if LVGL_PORT_HANDLE_FLUSH_READY
8181
static bool lvgl_port_flush_io_ready_callback(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx);
82+
#if ESP_LVGL_PORT_USE_LCD_BUFFERED
83+
static void lvgl_port_flush_buffered_ready_callback(esp_lcd_panel_handle_t panel,
84+
esp_lcd_buffered_panel_event_data_t *edata,
85+
void *user_ctx);
86+
#endif
8287
#if CONFIG_IDF_TARGET_ESP32S3 && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
8388
static bool lvgl_port_flush_rgb_vsync_ready_callback(esp_lcd_panel_handle_t panel_io, const esp_lcd_rgb_panel_event_data_t *edata, void *user_ctx);
8489
#endif
@@ -224,6 +229,51 @@ lv_display_t *lvgl_port_add_disp_rgb(const lvgl_port_display_cfg_t *disp_cfg, co
224229
return disp;
225230
}
226231

232+
#if ESP_LVGL_PORT_USE_LCD_BUFFERED
233+
lv_display_t *lvgl_port_add_disp_buffered(const lvgl_port_display_cfg_t *disp_cfg,
234+
const lvgl_port_display_buffered_cfg_t *buffered_cfg)
235+
{
236+
assert(buffered_cfg != NULL);
237+
const lvgl_port_disp_priv_cfg_t priv_cfg = {
238+
#if LVGL_PORT_HANDLE_FLUSH_READY
239+
.use_flush_smphr = 1, /* Always use semaphore for now */
240+
#else
241+
.use_flush_smphr = 0, /* Don't need semaphore if not handling flush ready */
242+
#endif
243+
};
244+
lvgl_port_lock(0);
245+
lv_disp_t *disp = lvgl_port_add_disp_priv(disp_cfg, &priv_cfg);
246+
247+
if (disp != NULL) {
248+
lvgl_port_display_ctx_t *disp_ctx = (lvgl_port_display_ctx_t *)lv_display_get_driver_data(disp);
249+
/* Set display type */
250+
disp_ctx->disp_type = LVGL_PORT_DISP_TYPE_OTHER;
251+
252+
assert(disp_cfg->io_handle != NULL);
253+
254+
#if LVGL_PORT_HANDLE_FLUSH_READY
255+
const esp_lcd_buffered_panel_event_callbacks_t cbs = {
256+
.wait_sync = buffered_cfg->wait_sync,
257+
.on_color_trans_done = lvgl_port_flush_buffered_ready_callback,
258+
};
259+
/* Register done callback */
260+
esp_lcd_buffered_panel_register_event_callbacks(disp_ctx->panel_handle, &cbs, disp);
261+
262+
/* Register wait callback if using semaphore */
263+
if (disp_ctx->flush_smphr) {
264+
lv_display_set_flush_wait_cb(disp, lvgl_port_flush_wait_smphr_callback);
265+
}
266+
#endif
267+
268+
/* Apply rotation from initial display configuration */
269+
lvgl_port_disp_rotation_update(disp_ctx);
270+
}
271+
lvgl_port_unlock();
272+
273+
return disp;
274+
}
275+
#endif
276+
227277
esp_err_t lvgl_port_remove_disp(lv_display_t *disp)
228278
{
229279
assert(disp);
@@ -256,6 +306,7 @@ esp_err_t lvgl_port_remove_disp(lv_display_t *disp)
256306
if (disp_ctx->flush_smphr) {
257307
vSemaphoreDelete(disp_ctx->flush_smphr);
258308
}
309+
259310
#if LVGL_PORT_PPA
260311
if (disp_ctx->ppa_handle) {
261312
lvgl_port_ppa_delete(disp_ctx->ppa_handle);
@@ -482,13 +533,12 @@ static lv_display_t *lvgl_port_add_disp_priv(const lvgl_port_display_cfg_t *disp
482533
}
483534

484535
#if LVGL_PORT_HANDLE_FLUSH_READY
485-
static bool lvgl_port_flush_io_ready_callback(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx)
536+
static bool lvgl_port_flush_common_ready_callback(lv_display_t *disp_drv)
486537
{
487538
BaseType_t need_yield = pdFALSE;
488539

489-
lv_display_t *disp_drv = (lv_display_t *)user_ctx;
490540
assert(disp_drv != NULL);
491-
lvgl_port_display_ctx_t *disp_ctx = lv_display_get_user_data(disp_drv);
541+
lvgl_port_display_ctx_t *disp_ctx = lv_display_get_driver_data(disp_drv);
492542
assert(disp_ctx != NULL);
493543

494544
if (disp_ctx->flush_smphr) {
@@ -504,27 +554,27 @@ static bool lvgl_port_flush_io_ready_callback(esp_lcd_panel_io_handle_t panel_io
504554
return (need_yield == pdTRUE);
505555
}
506556

507-
#if (CONFIG_IDF_TARGET_ESP32P4 && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0))
508-
static bool lvgl_port_flush_dpi_panel_ready_callback(esp_lcd_panel_handle_t panel_io, esp_lcd_dpi_panel_event_data_t *edata, void *user_ctx)
557+
static bool lvgl_port_flush_io_ready_callback(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx)
509558
{
510-
BaseType_t need_yield = pdFALSE;
511-
512559
lv_display_t *disp_drv = (lv_display_t *)user_ctx;
513-
assert(disp_drv != NULL);
514-
lvgl_port_display_ctx_t *disp_ctx = lv_display_get_user_data(disp_drv);
515-
assert(disp_ctx != NULL);
560+
return lvgl_port_flush_common_ready_callback(disp_drv);
561+
}
516562

517-
if (disp_ctx->flush_smphr) {
518-
if (xPortInIsrContext() == pdTRUE) {
519-
need_yield = xSemaphoreGiveFromISR(disp_ctx->flush_smphr, &need_yield);
520-
} else {
521-
xSemaphoreGive(disp_ctx->flush_smphr);
522-
}
523-
} else {
524-
lv_disp_flush_ready(disp_drv);
525-
}
563+
#if ESP_LVGL_PORT_USE_LCD_BUFFERED
564+
static void lvgl_port_flush_buffered_ready_callback(esp_lcd_panel_handle_t panel,
565+
esp_lcd_buffered_panel_event_data_t *edata,
566+
void *user_ctx)
567+
{
568+
lv_display_t *disp_drv = (lv_display_t *)user_ctx;
569+
lvgl_port_flush_common_ready_callback(disp_drv);
570+
}
571+
#endif
526572

527-
return (need_yield == pdTRUE);
573+
#if (CONFIG_IDF_TARGET_ESP32P4 && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0))
574+
static bool lvgl_port_flush_dpi_panel_ready_callback(esp_lcd_panel_handle_t panel_io, esp_lcd_dpi_panel_event_data_t *edata, void *user_ctx)
575+
{
576+
lv_display_t *disp_drv = (lv_display_t *)user_ctx;
577+
return lvgl_port_flush_common_ready_callback(disp_drv);
528578
}
529579

530580
static bool lvgl_port_flush_dpi_vsync_ready_callback(esp_lcd_panel_handle_t panel_io, esp_lcd_dpi_panel_event_data_t *edata, void *user_ctx)

0 commit comments

Comments
 (0)