11/*
2- * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
2+ * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
33 *
44 * SPDX-License-Identifier: Apache-2.0
55 */
@@ -59,6 +59,7 @@ typedef struct {
5959 uint8_t * oled_buffer ;
6060 lv_display_t * disp_drv ; /* LVGL display driver */
6161 lv_display_rotation_t current_rotation ;
62+ SemaphoreHandle_t flush_smphr ; /* LCD panel Flush Done semaphore (NULL if lv_disp_flush_ready() is used) */
6263 SemaphoreHandle_t trans_sem ; /* Idle transfer mutex */
6364#if LVGL_PORT_PPA
6465 lvgl_port_ppa_handle_t ppa_handle ;
@@ -85,6 +86,7 @@ static bool lvgl_port_flush_rgb_vsync_ready_callback(esp_lcd_panel_handle_t pane
8586static 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 );
8687static 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 );
8788#endif
89+ static void lvgl_port_flush_wait_smphr_callback (lv_display_t * drv );
8890#endif
8991static void lvgl_port_flush_callback (lv_display_t * drv , const lv_area_t * area , uint8_t * color_map );
9092static void lvgl_port_disp_size_update_callback (lv_event_t * e );
@@ -98,7 +100,14 @@ static void lvgl_port_display_invalidate_callback(lv_event_t *e);
98100lv_display_t * lvgl_port_add_disp (const lvgl_port_display_cfg_t * disp_cfg )
99101{
100102 lvgl_port_lock (0 );
101- lv_disp_t * disp = lvgl_port_add_disp_priv (disp_cfg , NULL );
103+ const lvgl_port_disp_priv_cfg_t priv_cfg = {
104+ #if LVGL_PORT_HANDLE_FLUSH_READY
105+ .use_flush_smphr = 1 , /* Always use semaphore for now */
106+ #else
107+ .use_flush_smphr = 0 , /* Don't need semaphore if not handling flush ready */
108+ #endif
109+ };
110+ lv_disp_t * disp = lvgl_port_add_disp_priv (disp_cfg , & priv_cfg );
102111
103112 if (disp != NULL ) {
104113 lvgl_port_display_ctx_t * disp_ctx = (lvgl_port_display_ctx_t * )lv_display_get_driver_data (disp );
@@ -113,6 +122,11 @@ lv_display_t *lvgl_port_add_disp(const lvgl_port_display_cfg_t *disp_cfg)
113122 };
114123 /* Register done callback */
115124 esp_lcd_panel_io_register_event_callbacks (disp_ctx -> io_handle , & cbs , disp );
125+
126+ /* Register wait callback if using semaphore */
127+ if (disp_ctx -> flush_smphr ) {
128+ lv_display_set_flush_wait_cb (disp , lvgl_port_flush_wait_smphr_callback );
129+ }
116130#endif
117131
118132 /* Apply rotation from initial display configuration */
@@ -128,6 +142,7 @@ lv_display_t *lvgl_port_add_disp_dsi(const lvgl_port_display_cfg_t *disp_cfg, co
128142 assert (dsi_cfg != NULL );
129143 const lvgl_port_disp_priv_cfg_t priv_cfg = {
130144 .avoid_tearing = dsi_cfg -> flags .avoid_tearing ,
145+ .use_flush_smphr = 1 , /* Always use semaphore for now */
131146 };
132147 lvgl_port_lock (0 );
133148 lv_disp_t * disp = lvgl_port_add_disp_priv (disp_cfg , & priv_cfg );
@@ -147,6 +162,11 @@ lv_display_t *lvgl_port_add_disp_dsi(const lvgl_port_display_cfg_t *disp_cfg, co
147162 /* Register done callback */
148163 esp_lcd_dpi_panel_register_event_callbacks (disp_ctx -> panel_handle , & cbs , disp );
149164
165+ /* Register wait callback if using semaphore */
166+ if (disp_ctx -> flush_smphr ) {
167+ lv_display_set_flush_wait_cb (disp , lvgl_port_flush_wait_smphr_callback );
168+ }
169+
150170 /* Apply rotation from initial display configuration */
151171 lvgl_port_disp_rotation_update (disp_ctx );
152172
@@ -232,6 +252,10 @@ esp_err_t lvgl_port_remove_disp(lv_display_t *disp)
232252 if (disp_ctx -> trans_sem ) {
233253 vSemaphoreDelete (disp_ctx -> trans_sem );
234254 }
255+
256+ if (disp_ctx -> flush_smphr ) {
257+ vSemaphoreDelete (disp_ctx -> flush_smphr );
258+ }
235259#if LVGL_PORT_PPA
236260 if (disp_ctx -> ppa_handle ) {
237261 lvgl_port_ppa_delete (disp_ctx -> ppa_handle );
@@ -261,6 +285,7 @@ static lv_display_t *lvgl_port_add_disp_priv(const lvgl_port_display_cfg_t *disp
261285 lv_color_t * buf2 = NULL ;
262286 uint32_t buffer_size = 0 ;
263287 SemaphoreHandle_t trans_sem = NULL ;
288+ SemaphoreHandle_t flush_sem = NULL ;
264289 assert (disp_cfg != NULL );
265290 assert (disp_cfg -> panel_handle != NULL );
266291 assert (disp_cfg -> buffer_size > 0 );
@@ -341,6 +366,13 @@ static lv_display_t *lvgl_port_add_disp_priv(const lvgl_port_display_cfg_t *disp
341366 disp_ctx -> draw_buffs [1 ] = buf2 ;
342367 }
343368
369+ /* Use semaphore to signal LCD panel flush done */
370+ if (priv_cfg && priv_cfg -> use_flush_smphr ) {
371+ flush_sem = xSemaphoreCreateBinary ();
372+ ESP_GOTO_ON_FALSE (flush_sem , ESP_ERR_NO_MEM , err , TAG , "Failed to create flush Semaphore" );
373+ disp_ctx -> flush_smphr = flush_sem ;
374+ }
375+
344376 disp = lv_display_create (disp_cfg -> hres , disp_cfg -> vres );
345377
346378 /* Set display color format */
@@ -441,6 +473,9 @@ static lv_display_t *lvgl_port_add_disp_priv(const lvgl_port_display_cfg_t *disp
441473 if (trans_sem ) {
442474 vSemaphoreDelete (trans_sem );
443475 }
476+ if (flush_sem ) {
477+ vSemaphoreDelete (flush_sem );
478+ }
444479 }
445480
446481 return disp ;
@@ -449,19 +484,47 @@ static lv_display_t *lvgl_port_add_disp_priv(const lvgl_port_display_cfg_t *disp
449484#if LVGL_PORT_HANDLE_FLUSH_READY
450485static 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 )
451486{
487+ BaseType_t need_yield = pdFALSE ;
488+
452489 lv_display_t * disp_drv = (lv_display_t * )user_ctx ;
453490 assert (disp_drv != NULL );
454- lv_disp_flush_ready (disp_drv );
455- return false;
491+ lvgl_port_display_ctx_t * disp_ctx = lv_display_get_user_data (disp_drv );
492+ assert (disp_ctx != NULL );
493+
494+ if (disp_ctx -> flush_smphr ) {
495+ if (xPortInIsrContext () == pdTRUE ) {
496+ need_yield = xSemaphoreGiveFromISR (disp_ctx -> flush_smphr , & need_yield );
497+ } else {
498+ xSemaphoreGive (disp_ctx -> flush_smphr );
499+ }
500+ } else {
501+ lv_disp_flush_ready (disp_drv );
502+ }
503+
504+ return (need_yield == pdTRUE );
456505}
457506
458507#if (CONFIG_IDF_TARGET_ESP32P4 && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL (5 , 3 , 0 ))
459508static 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 )
460509{
510+ BaseType_t need_yield = pdFALSE ;
511+
461512 lv_display_t * disp_drv = (lv_display_t * )user_ctx ;
462513 assert (disp_drv != NULL );
463- lv_disp_flush_ready (disp_drv );
464- return false;
514+ lvgl_port_display_ctx_t * disp_ctx = lv_display_get_user_data (disp_drv );
515+ assert (disp_ctx != NULL );
516+
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+ }
526+
527+ return (need_yield == pdTRUE );
465528}
466529
467530static 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 )
@@ -498,6 +561,16 @@ static bool lvgl_port_flush_rgb_vsync_ready_callback(esp_lcd_panel_handle_t pane
498561 return (need_yield == pdTRUE );
499562}
500563#endif
564+
565+ static void lvgl_port_flush_wait_smphr_callback (lv_display_t * drv )
566+ {
567+ assert (drv != NULL );
568+
569+ lvgl_port_display_ctx_t * disp_ctx = lv_display_get_driver_data (drv );
570+ assert (disp_ctx != NULL );
571+ assert (disp_ctx -> flush_smphr != NULL ); /* This callback should only be used with semaphore */
572+ xSemaphoreTake (disp_ctx -> flush_smphr , portMAX_DELAY );
573+ }
501574#endif
502575
503576static void _lvgl_port_transform_monochrome (lv_display_t * display , const lv_area_t * area , uint8_t * * color_map )
0 commit comments