kopia lustrzana https://github.com/espressif/esp-idf
feat(mipi_dsi): support isr iram safe
rodzic
ef57e5105d
commit
07a3e5eaa8
|
@ -19,7 +19,7 @@ menu "GDMA Configurations"
|
||||||
bool "Enable debug log"
|
bool "Enable debug log"
|
||||||
default n
|
default n
|
||||||
help
|
help
|
||||||
Wether to enable the debug log message for GDMA driver.
|
Whether to enable the debug log message for GDMA driver.
|
||||||
Note that, this option only controls the GDMA driver log, won't affect other drivers.
|
Note that, this option only controls the GDMA driver log, won't affect other drivers.
|
||||||
endmenu # GDMA Configurations
|
endmenu # GDMA Configurations
|
||||||
|
|
||||||
|
@ -40,6 +40,13 @@ menu "DW_GDMA Configurations"
|
||||||
Place DW_GDMA setter functions (e.g. dw_gdma_channel_set_block_markers) into IRAM,
|
Place DW_GDMA setter functions (e.g. dw_gdma_channel_set_block_markers) into IRAM,
|
||||||
so that these functions can be IRAM-safe and able to be called in the other IRAM interrupt context.
|
so that these functions can be IRAM-safe and able to be called in the other IRAM interrupt context.
|
||||||
|
|
||||||
|
config DW_GDMA_GETTER_FUNC_IN_IRAM
|
||||||
|
bool
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
Place DW_GDMA getter functions (e.g. dw_gdma_link_list_get_item) into IRAM,
|
||||||
|
so that these functions can be IRAM-safe and able to be called in the other IRAM interrupt context.
|
||||||
|
|
||||||
config DW_GDMA_ISR_IRAM_SAFE
|
config DW_GDMA_ISR_IRAM_SAFE
|
||||||
bool
|
bool
|
||||||
default n
|
default n
|
||||||
|
@ -52,7 +59,7 @@ menu "DW_GDMA Configurations"
|
||||||
bool "Enable debug log"
|
bool "Enable debug log"
|
||||||
default n
|
default n
|
||||||
help
|
help
|
||||||
Wether to enable the debug log message for DW_GDMA driver.
|
Whether to enable the debug log message for DW_GDMA driver.
|
||||||
Note that, this option only controls the DW_GDMA driver log, won't affect other drivers.
|
Note that, this option only controls the DW_GDMA driver log, won't affect other drivers.
|
||||||
endmenu # DW_GDMA Configurations
|
endmenu # DW_GDMA Configurations
|
||||||
|
|
||||||
|
|
|
@ -78,10 +78,15 @@ entries:
|
||||||
# put DW_GDMA control functions in IRAM
|
# put DW_GDMA control functions in IRAM
|
||||||
if DW_GDMA_CTRL_FUNC_IN_IRAM = y:
|
if DW_GDMA_CTRL_FUNC_IN_IRAM = y:
|
||||||
dw_gdma: dw_gdma_channel_continue (noflash)
|
dw_gdma: dw_gdma_channel_continue (noflash)
|
||||||
|
dw_gdma: dw_gdma_channel_enable_ctrl (noflash)
|
||||||
|
|
||||||
if DW_GDMA_SETTER_FUNC_IN_IRAM = y:
|
if DW_GDMA_SETTER_FUNC_IN_IRAM = y:
|
||||||
dw_gdma: dw_gdma_channel_set_block_markers (noflash)
|
dw_gdma: dw_gdma_channel_set_block_markers (noflash)
|
||||||
dw_gdma: dw_gdma_lli_set_block_markers (noflash)
|
dw_gdma: dw_gdma_lli_set_block_markers (noflash)
|
||||||
|
dw_gdma: dw_gdma_channel_use_link_list (noflash)
|
||||||
|
|
||||||
|
if DW_GDMA_GETTER_FUNC_IN_IRAM = y:
|
||||||
|
dw_gdma: dw_gdma_link_list_get_item (noflash)
|
||||||
|
|
||||||
[mapping:dma2d_driver]
|
[mapping:dma2d_driver]
|
||||||
archive: libesp_hw_support.a
|
archive: libesp_hw_support.a
|
||||||
|
|
|
@ -36,5 +36,20 @@ menu "LCD and Touch Panel"
|
||||||
Only need to enable it when in your application, the DMA can't deliver data
|
Only need to enable it when in your application, the DMA can't deliver data
|
||||||
as fast as the LCD consumes it.
|
as fast as the LCD consumes it.
|
||||||
endif # SOC_LCD_RGB_SUPPORTED
|
endif # SOC_LCD_RGB_SUPPORTED
|
||||||
|
|
||||||
|
if SOC_MIPI_DSI_SUPPORTED
|
||||||
|
config LCD_DSI_ISR_IRAM_SAFE
|
||||||
|
bool "DSI LCD ISR IRAM-Safe"
|
||||||
|
default n
|
||||||
|
select DW_GDMA_ISR_IRAM_SAFE
|
||||||
|
select DW_GDMA_CTRL_FUNC_IN_IRAM
|
||||||
|
select DW_GDMA_SETTER_FUNC_IN_IRAM
|
||||||
|
select DW_GDMA_GETTER_FUNC_IN_IRAM
|
||||||
|
help
|
||||||
|
Ensure the LCD interrupt is IRAM-Safe by allowing the interrupt handler to be
|
||||||
|
executable when the cache is disabled (e.g. SPI Flash write).
|
||||||
|
If you want the LCD driver to keep flushing the screen even when cache ops disabled,
|
||||||
|
you can enable this option. Note, this will also increase the IRAM usage.
|
||||||
|
endif # SOC_MIPI_DSI_SUPPORTED
|
||||||
endmenu
|
endmenu
|
||||||
endmenu
|
endmenu
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "esp_cache.h"
|
#include "esp_cache.h"
|
||||||
#include "mipi_dsi_priv.h"
|
#include "mipi_dsi_priv.h"
|
||||||
#include "esp_async_fbcpy.h"
|
#include "esp_async_fbcpy.h"
|
||||||
|
#include "esp_memory_utils.h"
|
||||||
#include "esp_private/dw_gdma.h"
|
#include "esp_private/dw_gdma.h"
|
||||||
#include "hal/cache_hal.h"
|
#include "hal/cache_hal.h"
|
||||||
#include "hal/cache_ll.h"
|
#include "hal/cache_ll.h"
|
||||||
|
@ -528,6 +529,17 @@ esp_err_t esp_lcd_dpi_panel_register_event_callbacks(esp_lcd_panel_handle_t pane
|
||||||
{
|
{
|
||||||
ESP_RETURN_ON_FALSE(panel && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
ESP_RETURN_ON_FALSE(panel && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||||
esp_lcd_dpi_panel_t *dpi_panel = __containerof(panel, esp_lcd_dpi_panel_t, base);
|
esp_lcd_dpi_panel_t *dpi_panel = __containerof(panel, esp_lcd_dpi_panel_t, base);
|
||||||
|
#if CONFIG_LCD_DSI_ISR_IRAM_SAFE
|
||||||
|
if (cbs->on_color_trans_done) {
|
||||||
|
ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_color_trans_done), ESP_ERR_INVALID_ARG, TAG, "on_color_trans_done callback not in IRAM");
|
||||||
|
}
|
||||||
|
if (cbs->on_refresh_done) {
|
||||||
|
ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_refresh_done), ESP_ERR_INVALID_ARG, TAG, "on_refresh_done callback not in IRAM");
|
||||||
|
}
|
||||||
|
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_RGB_ISR_IRAM_SAFE
|
||||||
dpi_panel->on_color_trans_done = cbs->on_color_trans_done;
|
dpi_panel->on_color_trans_done = cbs->on_color_trans_done;
|
||||||
dpi_panel->on_refresh_done = cbs->on_refresh_done;
|
dpi_panel->on_refresh_done = cbs->on_refresh_done;
|
||||||
dpi_panel->user_ctx = user_ctx;
|
dpi_panel->user_ctx = user_ctx;
|
||||||
|
|
|
@ -23,7 +23,11 @@
|
||||||
#define DSI_RCC_ATOMIC()
|
#define DSI_RCC_ATOMIC()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define DSI_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
|
#if CONFIG_LCD_DSI_ISR_IRAM_SAFE
|
||||||
|
#define DSI_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
|
||||||
|
#else
|
||||||
|
#define DSI_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
|
||||||
|
#endif
|
||||||
|
|
||||||
#define DPI_PANEL_MAX_FB_NUM 3 // maximum number of supported frame buffers for DPI panel
|
#define DPI_PANEL_MAX_FB_NUM 3 // maximum number of supported frame buffers for DPI panel
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ components/esp_lcd/test_apps/mipi_dsi_lcd:
|
||||||
disable_test:
|
disable_test:
|
||||||
- if: IDF_TARGET == "esp32p4"
|
- if: IDF_TARGET == "esp32p4"
|
||||||
temporary: true
|
temporary: true
|
||||||
reason: lack of runners
|
reason: lack of runners, DSI can't work without an LCD connected
|
||||||
|
|
||||||
components/esp_lcd/test_apps/rgb_lcd:
|
components/esp_lcd/test_apps/rgb_lcd:
|
||||||
depends_components:
|
depends_components:
|
||||||
|
|
|
@ -6,3 +6,16 @@ set(COMPONENTS main)
|
||||||
|
|
||||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
project(mipi_dsi_lcd_panel_test)
|
project(mipi_dsi_lcd_panel_test)
|
||||||
|
|
||||||
|
if(CONFIG_COMPILER_DUMP_RTL_FILES)
|
||||||
|
add_custom_target(check_test_app_sections ALL
|
||||||
|
COMMAND ${PYTHON} $ENV{IDF_PATH}/tools/ci/check_callgraph.py
|
||||||
|
--rtl-dirs ${CMAKE_BINARY_DIR}/esp-idf/esp_lcd/,${CMAKE_BINARY_DIR}/esp-idf/hal/
|
||||||
|
--elf-file ${CMAKE_BINARY_DIR}/mipi_dsi_lcd_panel_test.elf
|
||||||
|
find-refs
|
||||||
|
--from-sections=.iram0.text
|
||||||
|
--to-sections=.flash.text,.flash.rodata
|
||||||
|
--exit-code
|
||||||
|
DEPENDS ${elf}
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
|
@ -2,6 +2,10 @@ set(srcs "test_app_main.c"
|
||||||
"test_mipi_dsi_board.c"
|
"test_mipi_dsi_board.c"
|
||||||
"test_mipi_dsi_panel.c")
|
"test_mipi_dsi_panel.c")
|
||||||
|
|
||||||
|
if(CONFIG_LCD_DSI_ISR_IRAM_SAFE)
|
||||||
|
list(APPEND srcs "test_mipi_dsi_iram.c")
|
||||||
|
endif()
|
||||||
|
|
||||||
# In order for the cases defined by `TEST_CASE` to be linked into the final elf,
|
# In order for the cases defined by `TEST_CASE` to be linked into the final elf,
|
||||||
# the component can be registered as WHOLE_ARCHIVE
|
# the component can be registered as WHOLE_ARCHIVE
|
||||||
idf_component_register(SRCS ${srcs}
|
idf_component_register(SRCS ${srcs}
|
||||||
|
|
|
@ -0,0 +1,119 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "unity.h"
|
||||||
|
#include "unity_test_utils.h"
|
||||||
|
#include "esp_lcd_mipi_dsi.h"
|
||||||
|
#include "esp_lcd_panel_ops.h"
|
||||||
|
#include "esp_lcd_panel_io.h"
|
||||||
|
#include "esp_random.h"
|
||||||
|
#include "esp_attr.h"
|
||||||
|
#include "test_mipi_dsi_board.h"
|
||||||
|
#include "esp_lcd_ili9881c.h"
|
||||||
|
|
||||||
|
IRAM_ATTR static bool test_rgb_panel_count_in_callback(esp_lcd_panel_handle_t panel, esp_lcd_dpi_panel_event_data_t *edata, void *user_ctx)
|
||||||
|
{
|
||||||
|
uint32_t *count = (uint32_t *)user_ctx;
|
||||||
|
*count = *count + 1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void IRAM_ATTR test_delay_post_cache_disable(void *args)
|
||||||
|
{
|
||||||
|
esp_rom_delay_us(200000);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TEST_IMG_SIZE (100 * 100 * sizeof(uint16_t))
|
||||||
|
|
||||||
|
TEST_CASE("MIPI DSI draw bitmap (ILI9881C) IRAM Safe", "[mipi_dsi]")
|
||||||
|
{
|
||||||
|
esp_lcd_dsi_bus_handle_t mipi_dsi_bus;
|
||||||
|
esp_lcd_panel_io_handle_t mipi_dbi_io;
|
||||||
|
esp_lcd_panel_handle_t mipi_dpi_panel;
|
||||||
|
esp_lcd_panel_handle_t ili9881c_ctrl_panel;
|
||||||
|
|
||||||
|
test_bsp_enable_dsi_phy_power();
|
||||||
|
|
||||||
|
uint8_t *img = malloc(TEST_IMG_SIZE);
|
||||||
|
TEST_ASSERT_NOT_NULL(img);
|
||||||
|
|
||||||
|
esp_lcd_dsi_bus_config_t bus_config = {
|
||||||
|
.bus_id = 0,
|
||||||
|
.num_data_lanes = 2,
|
||||||
|
.phy_clk_src = MIPI_DSI_PHY_CLK_SRC_DEFAULT,
|
||||||
|
.lane_bit_rate_mbps = 1000, // 1000 Mbps
|
||||||
|
};
|
||||||
|
TEST_ESP_OK(esp_lcd_new_dsi_bus(&bus_config, &mipi_dsi_bus));
|
||||||
|
|
||||||
|
esp_lcd_dbi_io_config_t dbi_config = {
|
||||||
|
.virtual_channel = 0,
|
||||||
|
.lcd_cmd_bits = 8,
|
||||||
|
.lcd_param_bits = 8,
|
||||||
|
};
|
||||||
|
TEST_ESP_OK(esp_lcd_new_panel_io_dbi(mipi_dsi_bus, &dbi_config, &mipi_dbi_io));
|
||||||
|
|
||||||
|
esp_lcd_panel_dev_config_t lcd_dev_config = {
|
||||||
|
.bits_per_pixel = 16,
|
||||||
|
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
|
||||||
|
.reset_gpio_num = -1,
|
||||||
|
};
|
||||||
|
TEST_ESP_OK(esp_lcd_new_panel_ili9881c(mipi_dbi_io, &lcd_dev_config, &ili9881c_ctrl_panel));
|
||||||
|
TEST_ESP_OK(esp_lcd_panel_reset(ili9881c_ctrl_panel));
|
||||||
|
TEST_ESP_OK(esp_lcd_panel_init(ili9881c_ctrl_panel));
|
||||||
|
// turn on display
|
||||||
|
TEST_ESP_OK(esp_lcd_panel_disp_on_off(ili9881c_ctrl_panel, true));
|
||||||
|
|
||||||
|
esp_lcd_dpi_panel_config_t dpi_config = {
|
||||||
|
.dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT,
|
||||||
|
.dpi_clock_freq_mhz = MIPI_DSI_DPI_CLK_MHZ,
|
||||||
|
.virtual_channel = 0,
|
||||||
|
.pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565,
|
||||||
|
.video_timing = {
|
||||||
|
.h_size = MIPI_DSI_LCD_H_RES,
|
||||||
|
.v_size = MIPI_DSI_LCD_V_RES,
|
||||||
|
.hsync_back_porch = MIPI_DSI_LCD_HBP,
|
||||||
|
.hsync_pulse_width = MIPI_DSI_LCD_HSYNC,
|
||||||
|
.hsync_front_porch = MIPI_DSI_LCD_HFP,
|
||||||
|
.vsync_back_porch = MIPI_DSI_LCD_VBP,
|
||||||
|
.vsync_pulse_width = MIPI_DSI_LCD_VSYNC,
|
||||||
|
.vsync_front_porch = MIPI_DSI_LCD_VFP,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
TEST_ESP_OK(esp_lcd_new_panel_dpi(mipi_dsi_bus, &dpi_config, &mipi_dpi_panel));
|
||||||
|
TEST_ESP_OK(esp_lcd_panel_init(mipi_dpi_panel));
|
||||||
|
uint32_t callback_calls = 0;
|
||||||
|
esp_lcd_dpi_panel_event_callbacks_t cbs = {
|
||||||
|
.on_refresh_done = test_rgb_panel_count_in_callback,
|
||||||
|
};
|
||||||
|
TEST_ESP_OK(esp_lcd_dpi_panel_register_event_callbacks(mipi_dpi_panel, &cbs, &callback_calls));
|
||||||
|
|
||||||
|
uint8_t color_byte = rand() & 0xFF;
|
||||||
|
int x_start = rand() % (MIPI_DSI_LCD_H_RES - 100);
|
||||||
|
int y_start = rand() % (MIPI_DSI_LCD_V_RES - 100);
|
||||||
|
memset(img, color_byte, TEST_IMG_SIZE);
|
||||||
|
esp_lcd_panel_draw_bitmap(mipi_dpi_panel, x_start, y_start, x_start + 100, y_start + 100, img);
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(100));
|
||||||
|
|
||||||
|
printf("The LCD driver should keep flushing the color block in the background\r\n");
|
||||||
|
|
||||||
|
// disable the cache for a while, the LCD driver should stay working
|
||||||
|
printf("disable the cache for a while\r\n");
|
||||||
|
unity_utils_run_cache_disable_stub(test_delay_post_cache_disable, NULL);
|
||||||
|
printf("callback calls: %"PRIu32"\r\n", callback_calls);
|
||||||
|
TEST_ASSERT(callback_calls > 2);
|
||||||
|
|
||||||
|
TEST_ESP_OK(esp_lcd_panel_del(mipi_dpi_panel));
|
||||||
|
TEST_ESP_OK(esp_lcd_panel_del(ili9881c_ctrl_panel));
|
||||||
|
TEST_ESP_OK(esp_lcd_panel_io_del(mipi_dbi_io));
|
||||||
|
TEST_ESP_OK(esp_lcd_del_dsi_bus(mipi_dsi_bus));
|
||||||
|
free(img);
|
||||||
|
|
||||||
|
test_bsp_disable_dsi_phy_power();
|
||||||
|
}
|
|
@ -1,11 +1,18 @@
|
||||||
# SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
# SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from pytest_embedded import Dut
|
from pytest_embedded import Dut
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.esp32p4
|
@pytest.mark.esp32p4
|
||||||
@pytest.mark.generic
|
@pytest.mark.generic
|
||||||
def test_rgb_lcd(dut: Dut) -> None:
|
@pytest.mark.parametrize(
|
||||||
|
'config',
|
||||||
|
[
|
||||||
|
'iram_safe',
|
||||||
|
'release',
|
||||||
|
],
|
||||||
|
indirect=True,
|
||||||
|
)
|
||||||
|
def test_dsi_lcd(dut: Dut) -> None:
|
||||||
dut.run_all_single_board_cases()
|
dut.run_all_single_board_cases()
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
CONFIG_COMPILER_DUMP_RTL_FILES=y
|
||||||
|
CONFIG_COMPILER_OPTIMIZATION_NONE=y
|
||||||
|
# silent the error check, as the error string are stored in rodata, causing RTL check failure
|
||||||
|
CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y
|
||||||
|
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
|
||||||
|
# place non-ISR FreeRTOS functions in Flash
|
||||||
|
CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y
|
||||||
|
CONFIG_LCD_DSI_ISR_IRAM_SAFE=y
|
Ładowanie…
Reference in New Issue