mirror of
https://github.com/espressif/esp-idf.git
synced 2025-10-02 18:10:57 +02:00
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
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
#include <sys/param.h>
|
||||
#include "esp_lcd_panel_interface.h"
|
||||
#include "esp_lcd_mipi_dsi.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "esp_clk_tree.h"
|
||||
#include "esp_cache.h"
|
||||
#include "mipi_dsi_priv.h"
|
||||
@@ -33,7 +34,8 @@ struct esp_lcd_dpi_panel_t {
|
||||
size_t bits_per_pixel; // Bits per pixel
|
||||
lcd_color_format_t in_color_format; // Input color format
|
||||
lcd_color_format_t out_color_format; // Output color format
|
||||
dw_gdma_channel_handle_t dma_chan; // DMA channel
|
||||
dw_gdma_channel_handle_t dma_chan; // DMA channel
|
||||
intr_handle_t brg_intr; // DSI Bridge interrupt handle
|
||||
dw_gdma_link_list_handle_t link_lists[DPI_PANEL_MAX_FB_NUM]; // DMA link list
|
||||
esp_async_fbcpy_handle_t fbcpy_handle; // Use DMA2D to do frame buffer copy
|
||||
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
|
||||
{
|
||||
bool yield_needed = false;
|
||||
esp_lcd_dpi_panel_t *dpi_panel = (esp_lcd_dpi_panel_t *)user_data;
|
||||
mipi_dsi_hal_context_t *hal = &dpi_panel->bus->hal;
|
||||
uint8_t fb_index = dpi_panel->cur_fb_index;
|
||||
dw_gdma_link_list_handle_t link_list = dpi_panel->link_lists[fb_index];
|
||||
|
||||
// clear the interrupt status
|
||||
uint32_t error_status = mipi_dsi_brg_ll_get_interrupt_status(hal->bridge);
|
||||
mipi_dsi_brg_ll_clear_interrupt_status(hal->bridge, error_status);
|
||||
if (unlikely(error_status & MIPI_DSI_LL_EVENT_UNDERRUN)) {
|
||||
// when an underrun happens, the LCD display may already becomes blue
|
||||
// it's too late to recover the display, so we just print an error message
|
||||
// as a hint to the user that he should optimize the memory bandwidth (with AXI-ICM)
|
||||
ESP_DRAM_LOGE(TAG, "can't fetch data from external memory fast enough, underrun happens");
|
||||
}
|
||||
|
||||
// restart the DMA transfer, keep refreshing the LCD
|
||||
dw_gdma_block_markers_t markers = {
|
||||
.is_valid = true,
|
||||
@@ -94,15 +85,40 @@ bool mipi_dsi_dma_trans_done_cb(dw_gdma_channel_handle_t chan, const dw_gdma_tra
|
||||
dw_gdma_channel_use_link_list(chan, link_list);
|
||||
dw_gdma_channel_enable_ctrl(chan, true);
|
||||
|
||||
#if !MIPI_DSI_BRG_LL_EVENT_VSYNC
|
||||
// the DMA descriptor is large enough to carry a whole frame buffer, so this event can also be treated as a fake "vsync end"
|
||||
if (dpi_panel->on_refresh_done) {
|
||||
if (dpi_panel->on_refresh_done(&dpi_panel->base, NULL, dpi_panel->user_ctx)) {
|
||||
yield_needed = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return yield_needed;
|
||||
}
|
||||
|
||||
void mipi_dsi_bridge_isr_handler(void *args)
|
||||
{
|
||||
esp_lcd_dpi_panel_t* dpi_panel = (esp_lcd_dpi_panel_t *)args;
|
||||
mipi_dsi_hal_context_t *hal = &dpi_panel->bus->hal;
|
||||
// clear the interrupt status
|
||||
uint32_t intr_status = mipi_dsi_brg_ll_get_interrupt_status(hal->bridge);
|
||||
mipi_dsi_brg_ll_clear_interrupt_status(hal->bridge, intr_status);
|
||||
|
||||
if (intr_status & MIPI_DSI_BRG_LL_EVENT_UNDERRUN) {
|
||||
// when an underrun happens, the LCD display may already becomes blue
|
||||
// it's too late to recover the display, so we just print an error message
|
||||
// as a hint to the user that he should optimize the memory bandwidth (with AXI-ICM)
|
||||
ESP_DRAM_LOGE(TAG, "can't fetch data from external memory fast enough, underrun happens");
|
||||
}
|
||||
if (intr_status & MIPI_DSI_BRG_LL_EVENT_VSYNC) {
|
||||
if (dpi_panel->on_refresh_done) {
|
||||
if (dpi_panel->on_refresh_done(&dpi_panel->base, NULL, dpi_panel->user_ctx)) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Please note, errors happened in this function is just propagated to the caller
|
||||
// dpi_panel_del() is actually doing the error handling
|
||||
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_
|
||||
// the deprecated way to set the pixel format
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
bool has_pixel_fmt = panel_config->pixel_format != 0;
|
||||
bool has_in_fmt = panel_config->in_color_format != 0;
|
||||
ESP_RETURN_ON_FALSE(has_pixel_fmt ^ has_in_fmt, ESP_ERR_INVALID_ARG, TAG,
|
||||
"must set exactly one of pixel_format or in_color_format");
|
||||
if (panel_config->pixel_format) {
|
||||
switch (panel_config->pixel_format) {
|
||||
case LCD_COLOR_PIXEL_FORMAT_RGB565:
|
||||
bits_per_pixel = 16;
|
||||
break;
|
||||
case LCD_COLOR_PIXEL_FORMAT_RGB666:
|
||||
// RGB data in the memory must be constructed in 6-6-6 (18 bits) for each pixel
|
||||
bits_per_pixel = 18;
|
||||
break;
|
||||
case LCD_COLOR_PIXEL_FORMAT_RGB888:
|
||||
bits_per_pixel = 24;
|
||||
break;
|
||||
}
|
||||
in_color_format = COLOR_TYPE_ID(COLOR_SPACE_RGB, panel_config->pixel_format);
|
||||
switch (panel_config->pixel_format) {
|
||||
case LCD_COLOR_PIXEL_FORMAT_RGB565:
|
||||
bits_per_pixel = 16;
|
||||
break;
|
||||
case LCD_COLOR_PIXEL_FORMAT_RGB666:
|
||||
// RGB data in the memory must be constructed in 6-6-6 (18 bits) for each pixel
|
||||
bits_per_pixel = 18;
|
||||
break;
|
||||
case LCD_COLOR_PIXEL_FORMAT_RGB888:
|
||||
bits_per_pixel = 24;
|
||||
break;
|
||||
}
|
||||
in_color_format = COLOR_TYPE_ID(COLOR_SPACE_RGB, panel_config->pixel_format);
|
||||
#pragma GCC diagnostic pop
|
||||
// the recommended way to set the input color format
|
||||
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_
|
||||
esp_pm_lock_acquire(dpi_panel->pm_lock);
|
||||
#endif
|
||||
|
||||
// install interrupt service
|
||||
int isr_flags = ESP_INTR_FLAG_LOWMED;
|
||||
#if CONFIG_LCD_DSI_ISR_CACHE_SAFE
|
||||
isr_flags |= ESP_INTR_FLAG_IRAM;
|
||||
#endif
|
||||
ESP_GOTO_ON_ERROR(esp_intr_alloc(soc_mipi_dsi_signals[bus_id].brg_irq_id, isr_flags, mipi_dsi_bridge_isr_handler,
|
||||
dpi_panel, &dpi_panel->brg_intr), err, TAG, "allocate DSI Bridge interrupt failed");
|
||||
|
||||
// create DMA resources
|
||||
ESP_GOTO_ON_ERROR(dpi_panel_create_dma_link(dpi_panel), err, TAG, "initialize DMA link failed");
|
||||
|
||||
@@ -377,6 +395,9 @@ static esp_err_t dpi_panel_del(esp_lcd_panel_t *panel)
|
||||
if (dpi_panel->draw_sem) {
|
||||
vSemaphoreDeleteWithCaps(dpi_panel->draw_sem);
|
||||
}
|
||||
if (dpi_panel->brg_intr) {
|
||||
esp_intr_free(dpi_panel->brg_intr);
|
||||
}
|
||||
#if CONFIG_PM_ENABLE
|
||||
if (dpi_panel->pm_lock) {
|
||||
esp_pm_lock_release(dpi_panel->pm_lock);
|
||||
@@ -458,9 +479,8 @@ static esp_err_t dpi_panel_init(esp_lcd_panel_t *panel)
|
||||
mipi_dsi_brg_ll_enable_dpi_output(hal->bridge, true);
|
||||
mipi_dsi_brg_ll_update_dpi_config(hal->bridge);
|
||||
|
||||
// enable the underrun interrupt, we use this as a signal of bandwidth shortage
|
||||
// note, we opt to not install a dedicated interrupt handler just for this error condition, instead, we check it in the DMA callback
|
||||
mipi_dsi_brg_ll_enable_interrupt(hal->bridge, MIPI_DSI_LL_EVENT_UNDERRUN, true);
|
||||
// always enable the interrupt to detect the underflow condition
|
||||
mipi_dsi_brg_ll_enable_interrupt(hal->bridge, MIPI_DSI_BRG_LL_EVENT_UNDERRUN, true);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -622,10 +642,13 @@ esp_err_t esp_lcd_dpi_panel_register_event_callbacks(esp_lcd_panel_handle_t pane
|
||||
if (user_ctx) {
|
||||
ESP_RETURN_ON_FALSE(esp_ptr_internal(user_ctx), ESP_ERR_INVALID_ARG, TAG, "user context not in internal RAM");
|
||||
}
|
||||
#endif // CONFIG_LCD_DSI_ISR_HANDLER_IN_IRAM
|
||||
#endif // CONFIG_LCD_DSI_ISR_CACHE_SAFE
|
||||
dpi_panel->on_color_trans_done = cbs->on_color_trans_done;
|
||||
dpi_panel->on_refresh_done = cbs->on_refresh_done;
|
||||
dpi_panel->user_ctx = user_ctx;
|
||||
|
||||
// enable the vsync interrupt if the callback is provided
|
||||
mipi_dsi_brg_ll_enable_interrupt(dpi_panel->bus->hal.bridge, MIPI_DSI_BRG_LL_EVENT_VSYNC, cbs->on_refresh_done != NULL);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
@@ -12,7 +12,7 @@
|
||||
// Set the maximum log level for gptimer driver
|
||||
#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE
|
||||
#endif
|
||||
#include "soc/soc_caps_full.h"
|
||||
#include "soc/mipi_dsi_periph.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
@@ -3,6 +3,7 @@ archive: libesp_lcd.a
|
||||
entries:
|
||||
if LCD_DSI_ISR_HANDLER_IN_IRAM = y:
|
||||
esp_lcd_panel_dpi: mipi_dsi_dma_trans_done_cb (noflash)
|
||||
esp_lcd_panel_dpi: mipi_dsi_bridge_isr_handler (noflash)
|
||||
|
||||
[mapping:esp_lcd_dsi_dma]
|
||||
archive: libesp_hw_support.a
|
||||
|
@@ -330,6 +330,8 @@ TEST_CASE("MIPI DSI draw YUV422 image (EK79007)", "[mipi_dsi]")
|
||||
test_bsp_disable_dsi_phy_power();
|
||||
}
|
||||
|
||||
#if !(CONFIG_IDF_TARGET_ESP32P4 && CONFIG_ESP32P4_REV_MIN_FULL < 300)
|
||||
|
||||
TEST_CASE("MIPI DSI draw Gray8 image (EK79007)", "[mipi_dsi]")
|
||||
{
|
||||
esp_lcd_dsi_bus_handle_t mipi_dsi_bus;
|
||||
@@ -407,3 +409,5 @@ TEST_CASE("MIPI DSI draw Gray8 image (EK79007)", "[mipi_dsi]")
|
||||
|
||||
test_bsp_disable_dsi_phy_power();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -15,8 +15,13 @@
|
||||
#include "hal/config.h"
|
||||
|
||||
#define MIPI_DSI_LL_GET_BRG(bus_id) (bus_id == 0 ? &MIPI_DSI_BRIDGE : NULL)
|
||||
#define MIPI_DSI_LL_EVENT_UNDERRUN (1 << 0)
|
||||
#define MIPI_DSI_LL_EVENT_VSYNC (1 << 1)
|
||||
|
||||
#define MIPI_DSI_BRG_LL_EVENT_UNDERRUN (1 << 0)
|
||||
#if HAL_CONFIG(CHIP_SUPPORT_MIN_REV) >= 300
|
||||
#define MIPI_DSI_BRG_LL_EVENT_VSYNC (1 << 1)
|
||||
#else
|
||||
#define MIPI_DSI_BRG_LL_EVENT_VSYNC 0 // not supported
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@@ -37,3 +37,6 @@
|
||||
/*--------------------------- ETM (Event Task Matrix) ----------------------------*/
|
||||
#define _SOC_CAPS_ETM_INST_NUM 1 // Number of ETM instances
|
||||
#define _SOC_CAPS_ETM_CHANS_PER_INST 50 // Number of channels in each ETM instance
|
||||
|
||||
/*--------------------------- MIPI DSI -------------------------------------------*/
|
||||
#define _SOC_CAPS_MIPI_DSI_INST_NUM 1 // Number of MIPI DSI instances
|
||||
|
@@ -24,6 +24,7 @@ PROVIDE ( AXI_ICM_QOS = 0x500A4400 );
|
||||
PROVIDE ( HP_PERI_PMS = 0x500A5000 );
|
||||
PROVIDE ( LP2HP_PERI_PMS = 0x500A5800 );
|
||||
PROVIDE ( DMA_PMS = 0x500A6000 );
|
||||
PROVIDE ( AXI_PERF_MON = 0x500A8000 );
|
||||
PROVIDE ( LEDC = 0x500D3000 );
|
||||
PROVIDE ( LEDC_GAMMA_RAM = 0x500D3400 );
|
||||
PROVIDE ( TIMERG0 = 0x500C2000 );
|
||||
|
@@ -1,10 +1,11 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "soc/mipi_dsi_periph.h"
|
||||
#include "soc/interrupts.h"
|
||||
|
||||
const soc_mipi_dsi_phy_pll_freq_range_t soc_mipi_dsi_phy_pll_ranges[] = {
|
||||
{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[] = {
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
const soc_mipi_dsi_signal_desc_t soc_mipi_dsi_signals[1] = {
|
||||
[0] = {
|
||||
.brg_irq_id = ETS_DSI_BRIDGE_INTR_SOURCE,
|
||||
}
|
||||
};
|
||||
|
@@ -144,12 +144,12 @@ typedef struct {
|
||||
volatile icm_axi_hw_cfg_reg_reg_t hw_cfg_reg;
|
||||
volatile icm_axi_cmd_reg_t cmd;
|
||||
volatile icm_axi_data_reg_t data;
|
||||
} icm_axi_dev_t;
|
||||
} axi_icm_qos_dev_t;
|
||||
|
||||
extern icm_axi_dev_t ICM_SYS;
|
||||
extern axi_icm_qos_dev_t AXI_ICM_QOS;
|
||||
|
||||
#ifndef __cplusplus
|
||||
_Static_assert(sizeof(icm_axi_dev_t) == 0x10, "Invalid size of icm_axi_dev_t structure");
|
||||
_Static_assert(sizeof(axi_icm_qos_dev_t) == 0x10, "Invalid size of axi_icm_qos_dev_t structure");
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@@ -508,12 +508,12 @@ typedef struct {
|
||||
volatile icm_rdn_eco_cs_reg_t rdn_eco_cs;
|
||||
volatile icm_rdn_eco_low_reg_t rdn_eco_low;
|
||||
volatile icm_rdn_eco_high_reg_t rdn_eco_high;
|
||||
} icm_dev_t;
|
||||
} axi_icm_dev_t;
|
||||
|
||||
extern icm_dev_t ICM_SYS;
|
||||
extern axi_icm_dev_t AXI_ICM;
|
||||
|
||||
#ifndef __cplusplus
|
||||
_Static_assert(sizeof(icm_dev_t) == 0x5c, "Invalid size of icm_dev_t structure");
|
||||
_Static_assert(sizeof(axi_icm_dev_t) == 0x5c, "Invalid size of axi_icm_dev_t structure");
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -8,11 +8,17 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "soc/soc_caps_full.h"
|
||||
|
||||
// helper macros to access module attributes
|
||||
#define SOC_MIPI_DSI_ATTR(_attr) SOC_MODULE_ATTR(MIPI_DSI, _attr)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if SOC_HAS(MIPI_DSI)
|
||||
|
||||
/**
|
||||
* @brief MIPI DSI PHY PLL frequency range
|
||||
*/
|
||||
@@ -25,6 +31,14 @@ typedef struct {
|
||||
extern const soc_mipi_dsi_phy_pll_freq_range_t soc_mipi_dsi_phy_pll_ranges[];
|
||||
extern const size_t num_of_soc_mipi_dsi_phy_pll_ranges;
|
||||
|
||||
typedef struct {
|
||||
const int brg_irq_id; // interrupt source ID for MIPI DSI Bridge
|
||||
} soc_mipi_dsi_signal_desc_t;
|
||||
|
||||
extern const soc_mipi_dsi_signal_desc_t soc_mipi_dsi_signals[SOC_MIPI_DSI_ATTR(INST_NUM)];
|
||||
|
||||
#endif // SOC_HAS(MIPI_DSI)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user