Skip to content

Commit a15ab23

Browse files
committed
Merge branch 'feat/mipi_dsi_vsync_event' into 'master'
feat(dsi): add vsync interrupt handling Closes IDF-13503 See merge request espressif/esp-idf!42163
2 parents 61aaaf3 + 415d1ab commit a15ab23

File tree

11 files changed

+104
-46
lines changed

11 files changed

+104
-46
lines changed

components/esp_lcd/dsi/esp_lcd_panel_dpi.c

Lines changed: 58 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <sys/param.h>
77
#include "esp_lcd_panel_interface.h"
88
#include "esp_lcd_mipi_dsi.h"
9+
#include "esp_intr_alloc.h"
910
#include "esp_clk_tree.h"
1011
#include "esp_cache.h"
1112
#include "mipi_dsi_priv.h"
@@ -33,7 +34,8 @@ struct esp_lcd_dpi_panel_t {
3334
size_t bits_per_pixel; // Bits per pixel
3435
lcd_color_format_t in_color_format; // Input color format
3536
lcd_color_format_t out_color_format; // Output color format
36-
dw_gdma_channel_handle_t dma_chan; // DMA channel
37+
dw_gdma_channel_handle_t dma_chan; // DMA channel
38+
intr_handle_t brg_intr; // DSI Bridge interrupt handle
3739
dw_gdma_link_list_handle_t link_lists[DPI_PANEL_MAX_FB_NUM]; // DMA link list
3840
esp_async_fbcpy_handle_t fbcpy_handle; // Use DMA2D to do frame buffer copy
3941
SemaphoreHandle_t draw_sem; // A semaphore used to synchronize the draw operations when DMA2D is used
@@ -71,20 +73,9 @@ bool mipi_dsi_dma_trans_done_cb(dw_gdma_channel_handle_t chan, const dw_gdma_tra
7173
{
7274
bool yield_needed = false;
7375
esp_lcd_dpi_panel_t *dpi_panel = (esp_lcd_dpi_panel_t *)user_data;
74-
mipi_dsi_hal_context_t *hal = &dpi_panel->bus->hal;
7576
uint8_t fb_index = dpi_panel->cur_fb_index;
7677
dw_gdma_link_list_handle_t link_list = dpi_panel->link_lists[fb_index];
7778

78-
// clear the interrupt status
79-
uint32_t error_status = mipi_dsi_brg_ll_get_interrupt_status(hal->bridge);
80-
mipi_dsi_brg_ll_clear_interrupt_status(hal->bridge, error_status);
81-
if (unlikely(error_status & MIPI_DSI_LL_EVENT_UNDERRUN)) {
82-
// when an underrun happens, the LCD display may already becomes blue
83-
// it's too late to recover the display, so we just print an error message
84-
// as a hint to the user that he should optimize the memory bandwidth (with AXI-ICM)
85-
ESP_DRAM_LOGE(TAG, "can't fetch data from external memory fast enough, underrun happens");
86-
}
87-
8879
// restart the DMA transfer, keep refreshing the LCD
8980
dw_gdma_block_markers_t markers = {
9081
.is_valid = true,
@@ -94,15 +85,40 @@ bool mipi_dsi_dma_trans_done_cb(dw_gdma_channel_handle_t chan, const dw_gdma_tra
9485
dw_gdma_channel_use_link_list(chan, link_list);
9586
dw_gdma_channel_enable_ctrl(chan, true);
9687

88+
#if !MIPI_DSI_BRG_LL_EVENT_VSYNC
9789
// the DMA descriptor is large enough to carry a whole frame buffer, so this event can also be treated as a fake "vsync end"
9890
if (dpi_panel->on_refresh_done) {
9991
if (dpi_panel->on_refresh_done(&dpi_panel->base, NULL, dpi_panel->user_ctx)) {
10092
yield_needed = true;
10193
}
10294
}
95+
#endif
10396
return yield_needed;
10497
}
10598

99+
void mipi_dsi_bridge_isr_handler(void *args)
100+
{
101+
esp_lcd_dpi_panel_t* dpi_panel = (esp_lcd_dpi_panel_t *)args;
102+
mipi_dsi_hal_context_t *hal = &dpi_panel->bus->hal;
103+
// clear the interrupt status
104+
uint32_t intr_status = mipi_dsi_brg_ll_get_interrupt_status(hal->bridge);
105+
mipi_dsi_brg_ll_clear_interrupt_status(hal->bridge, intr_status);
106+
107+
if (intr_status & MIPI_DSI_BRG_LL_EVENT_UNDERRUN) {
108+
// when an underrun happens, the LCD display may already becomes blue
109+
// it's too late to recover the display, so we just print an error message
110+
// as a hint to the user that he should optimize the memory bandwidth (with AXI-ICM)
111+
ESP_DRAM_LOGE(TAG, "can't fetch data from external memory fast enough, underrun happens");
112+
}
113+
if (intr_status & MIPI_DSI_BRG_LL_EVENT_VSYNC) {
114+
if (dpi_panel->on_refresh_done) {
115+
if (dpi_panel->on_refresh_done(&dpi_panel->base, NULL, dpi_panel->user_ctx)) {
116+
portYIELD_FROM_ISR();
117+
}
118+
}
119+
}
120+
}
121+
106122
// Please note, errors happened in this function is just propagated to the caller
107123
// dpi_panel_del() is actually doing the error handling
108124
static esp_err_t dpi_panel_create_dma_link(esp_lcd_dpi_panel_t *dpi_panel)
@@ -172,25 +188,19 @@ esp_err_t esp_lcd_new_panel_dpi(esp_lcd_dsi_bus_handle_t bus, const esp_lcd_dpi_
172188
// the deprecated way to set the pixel format
173189
#pragma GCC diagnostic push
174190
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
175-
bool has_pixel_fmt = panel_config->pixel_format != 0;
176-
bool has_in_fmt = panel_config->in_color_format != 0;
177-
ESP_RETURN_ON_FALSE(has_pixel_fmt ^ has_in_fmt, ESP_ERR_INVALID_ARG, TAG,
178-
"must set exactly one of pixel_format or in_color_format");
179-
if (panel_config->pixel_format) {
180-
switch (panel_config->pixel_format) {
181-
case LCD_COLOR_PIXEL_FORMAT_RGB565:
182-
bits_per_pixel = 16;
183-
break;
184-
case LCD_COLOR_PIXEL_FORMAT_RGB666:
185-
// RGB data in the memory must be constructed in 6-6-6 (18 bits) for each pixel
186-
bits_per_pixel = 18;
187-
break;
188-
case LCD_COLOR_PIXEL_FORMAT_RGB888:
189-
bits_per_pixel = 24;
190-
break;
191-
}
192-
in_color_format = COLOR_TYPE_ID(COLOR_SPACE_RGB, panel_config->pixel_format);
193-
}
191+
switch (panel_config->pixel_format) {
192+
case LCD_COLOR_PIXEL_FORMAT_RGB565:
193+
bits_per_pixel = 16;
194+
break;
195+
case LCD_COLOR_PIXEL_FORMAT_RGB666:
196+
// RGB data in the memory must be constructed in 6-6-6 (18 bits) for each pixel
197+
bits_per_pixel = 18;
198+
break;
199+
case LCD_COLOR_PIXEL_FORMAT_RGB888:
200+
bits_per_pixel = 24;
201+
break;
202+
}
203+
in_color_format = COLOR_TYPE_ID(COLOR_SPACE_RGB, panel_config->pixel_format);
194204
#pragma GCC diagnostic pop
195205
// the recommended way to set the input color format
196206
if (panel_config->in_color_format) {
@@ -278,6 +288,14 @@ esp_err_t esp_lcd_new_panel_dpi(esp_lcd_dsi_bus_handle_t bus, const esp_lcd_dpi_
278288
esp_pm_lock_acquire(dpi_panel->pm_lock);
279289
#endif
280290

291+
// install interrupt service
292+
int isr_flags = ESP_INTR_FLAG_LOWMED;
293+
#if CONFIG_LCD_DSI_ISR_CACHE_SAFE
294+
isr_flags |= ESP_INTR_FLAG_IRAM;
295+
#endif
296+
ESP_GOTO_ON_ERROR(esp_intr_alloc(soc_mipi_dsi_signals[bus_id].brg_irq_id, isr_flags, mipi_dsi_bridge_isr_handler,
297+
dpi_panel, &dpi_panel->brg_intr), err, TAG, "allocate DSI Bridge interrupt failed");
298+
281299
// create DMA resources
282300
ESP_GOTO_ON_ERROR(dpi_panel_create_dma_link(dpi_panel), err, TAG, "initialize DMA link failed");
283301

@@ -377,6 +395,9 @@ static esp_err_t dpi_panel_del(esp_lcd_panel_t *panel)
377395
if (dpi_panel->draw_sem) {
378396
vSemaphoreDeleteWithCaps(dpi_panel->draw_sem);
379397
}
398+
if (dpi_panel->brg_intr) {
399+
esp_intr_free(dpi_panel->brg_intr);
400+
}
380401
#if CONFIG_PM_ENABLE
381402
if (dpi_panel->pm_lock) {
382403
esp_pm_lock_release(dpi_panel->pm_lock);
@@ -458,9 +479,8 @@ static esp_err_t dpi_panel_init(esp_lcd_panel_t *panel)
458479
mipi_dsi_brg_ll_enable_dpi_output(hal->bridge, true);
459480
mipi_dsi_brg_ll_update_dpi_config(hal->bridge);
460481

461-
// enable the underrun interrupt, we use this as a signal of bandwidth shortage
462-
// note, we opt to not install a dedicated interrupt handler just for this error condition, instead, we check it in the DMA callback
463-
mipi_dsi_brg_ll_enable_interrupt(hal->bridge, MIPI_DSI_LL_EVENT_UNDERRUN, true);
482+
// always enable the interrupt to detect the underflow condition
483+
mipi_dsi_brg_ll_enable_interrupt(hal->bridge, MIPI_DSI_BRG_LL_EVENT_UNDERRUN, true);
464484

465485
return ESP_OK;
466486
}
@@ -622,10 +642,13 @@ esp_err_t esp_lcd_dpi_panel_register_event_callbacks(esp_lcd_panel_handle_t pane
622642
if (user_ctx) {
623643
ESP_RETURN_ON_FALSE(esp_ptr_internal(user_ctx), ESP_ERR_INVALID_ARG, TAG, "user context not in internal RAM");
624644
}
625-
#endif // CONFIG_LCD_DSI_ISR_HANDLER_IN_IRAM
645+
#endif // CONFIG_LCD_DSI_ISR_CACHE_SAFE
626646
dpi_panel->on_color_trans_done = cbs->on_color_trans_done;
627647
dpi_panel->on_refresh_done = cbs->on_refresh_done;
628648
dpi_panel->user_ctx = user_ctx;
629649

650+
// enable the vsync interrupt if the callback is provided
651+
mipi_dsi_brg_ll_enable_interrupt(dpi_panel->bus->hal.bridge, MIPI_DSI_BRG_LL_EVENT_VSYNC, cbs->on_refresh_done != NULL);
652+
630653
return ESP_OK;
631654
}

components/esp_lcd/dsi/mipi_dsi_priv.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
// Set the maximum log level for gptimer driver
1313
#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE
1414
#endif
15-
#include "soc/soc_caps_full.h"
15+
#include "soc/mipi_dsi_periph.h"
1616
#include "freertos/FreeRTOS.h"
1717
#include "freertos/task.h"
1818
#include "freertos/semphr.h"

components/esp_lcd/linker.lf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ archive: libesp_lcd.a
33
entries:
44
if LCD_DSI_ISR_HANDLER_IN_IRAM = y:
55
esp_lcd_panel_dpi: mipi_dsi_dma_trans_done_cb (noflash)
6+
esp_lcd_panel_dpi: mipi_dsi_bridge_isr_handler (noflash)
67

78
[mapping:esp_lcd_dsi_dma]
89
archive: libesp_hw_support.a

components/esp_lcd/test_apps/mipi_dsi_lcd/main/test_mipi_dsi_panel.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,8 @@ TEST_CASE("MIPI DSI draw YUV422 image (EK79007)", "[mipi_dsi]")
330330
test_bsp_disable_dsi_phy_power();
331331
}
332332

333+
#if !(CONFIG_IDF_TARGET_ESP32P4 && CONFIG_ESP32P4_REV_MIN_FULL < 300)
334+
333335
TEST_CASE("MIPI DSI draw Gray8 image (EK79007)", "[mipi_dsi]")
334336
{
335337
esp_lcd_dsi_bus_handle_t mipi_dsi_bus;
@@ -407,3 +409,5 @@ TEST_CASE("MIPI DSI draw Gray8 image (EK79007)", "[mipi_dsi]")
407409

408410
test_bsp_disable_dsi_phy_power();
409411
}
412+
413+
#endif

components/hal/esp32p4/include/hal/mipi_dsi_brg_ll.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,13 @@
1515
#include "hal/config.h"
1616

1717
#define MIPI_DSI_LL_GET_BRG(bus_id) (bus_id == 0 ? &MIPI_DSI_BRIDGE : NULL)
18-
#define MIPI_DSI_LL_EVENT_UNDERRUN (1 << 0)
19-
#define MIPI_DSI_LL_EVENT_VSYNC (1 << 1)
18+
19+
#define MIPI_DSI_BRG_LL_EVENT_UNDERRUN (1 << 0)
20+
#if HAL_CONFIG(CHIP_SUPPORT_MIN_REV) >= 300
21+
#define MIPI_DSI_BRG_LL_EVENT_VSYNC (1 << 1)
22+
#else
23+
#define MIPI_DSI_BRG_LL_EVENT_VSYNC 0 // not supported
24+
#endif
2025

2126
#ifdef __cplusplus
2227
extern "C" {

components/soc/esp32p4/include/soc/soc_caps_full.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,6 @@
3737
/*--------------------------- ETM (Event Task Matrix) ----------------------------*/
3838
#define _SOC_CAPS_ETM_INST_NUM 1 // Number of ETM instances
3939
#define _SOC_CAPS_ETM_CHANS_PER_INST 50 // Number of channels in each ETM instance
40+
41+
/*--------------------------- MIPI DSI -------------------------------------------*/
42+
#define _SOC_CAPS_MIPI_DSI_INST_NUM 1 // Number of MIPI DSI instances

components/soc/esp32p4/ld/esp32p4.peripherals.ld

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ PROVIDE ( AXI_ICM_QOS = 0x500A4400 );
2424
PROVIDE ( HP_PERI_PMS = 0x500A5000 );
2525
PROVIDE ( LP2HP_PERI_PMS = 0x500A5800 );
2626
PROVIDE ( DMA_PMS = 0x500A6000 );
27+
PROVIDE ( AXI_PERF_MON = 0x500A8000 );
2728
PROVIDE ( LEDC = 0x500D3000 );
2829
PROVIDE ( LEDC_GAMMA_RAM = 0x500D3400 );
2930
PROVIDE ( TIMERG0 = 0x500C2000 );

components/soc/esp32p4/mipi_dsi_periph.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
/*
2-
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
66

77
#include "soc/mipi_dsi_periph.h"
8+
#include "soc/interrupts.h"
89

910
const soc_mipi_dsi_phy_pll_freq_range_t soc_mipi_dsi_phy_pll_ranges[] = {
1011
{80, 89, 0x00}, // [80,90) Mbps
@@ -49,3 +50,9 @@ const soc_mipi_dsi_phy_pll_freq_range_t soc_mipi_dsi_phy_pll_ranges[] = {
4950
};
5051

5152
const size_t num_of_soc_mipi_dsi_phy_pll_ranges = sizeof(soc_mipi_dsi_phy_pll_ranges) / sizeof(soc_mipi_dsi_phy_pll_freq_range_t);
53+
54+
const soc_mipi_dsi_signal_desc_t soc_mipi_dsi_signals[1] = {
55+
[0] = {
56+
.brg_irq_id = ETS_DSI_BRIDGE_INTR_SOURCE,
57+
}
58+
};

components/soc/esp32p4/register/hw_ver3/soc/icm_sys_qos_struct.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,12 +144,12 @@ typedef struct {
144144
volatile icm_axi_hw_cfg_reg_reg_t hw_cfg_reg;
145145
volatile icm_axi_cmd_reg_t cmd;
146146
volatile icm_axi_data_reg_t data;
147-
} icm_axi_dev_t;
147+
} axi_icm_qos_dev_t;
148148

149-
extern icm_axi_dev_t ICM_SYS;
149+
extern axi_icm_qos_dev_t AXI_ICM_QOS;
150150

151151
#ifndef __cplusplus
152-
_Static_assert(sizeof(icm_axi_dev_t) == 0x10, "Invalid size of icm_axi_dev_t structure");
152+
_Static_assert(sizeof(axi_icm_qos_dev_t) == 0x10, "Invalid size of axi_icm_qos_dev_t structure");
153153
#endif
154154

155155
#ifdef __cplusplus

components/soc/esp32p4/register/hw_ver3/soc/icm_sys_struct.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -508,12 +508,12 @@ typedef struct {
508508
volatile icm_rdn_eco_cs_reg_t rdn_eco_cs;
509509
volatile icm_rdn_eco_low_reg_t rdn_eco_low;
510510
volatile icm_rdn_eco_high_reg_t rdn_eco_high;
511-
} icm_dev_t;
511+
} axi_icm_dev_t;
512512

513-
extern icm_dev_t ICM_SYS;
513+
extern axi_icm_dev_t AXI_ICM;
514514

515515
#ifndef __cplusplus
516-
_Static_assert(sizeof(icm_dev_t) == 0x5c, "Invalid size of icm_dev_t structure");
516+
_Static_assert(sizeof(axi_icm_dev_t) == 0x5c, "Invalid size of axi_icm_dev_t structure");
517517
#endif
518518

519519
#ifdef __cplusplus

0 commit comments

Comments
 (0)