lcd: support rgb lcd interupt iram safe

This commit is contained in:
morris
2022-03-07 18:04:02 +08:00
parent f06a13ad82
commit 7112009473
14 changed files with 218 additions and 57 deletions

View File

@@ -26,13 +26,17 @@
static const char *TAG = "gdma"; static const char *TAG = "gdma";
#if CONFIG_GDMA_ISR_IRAM_SAFE #if CONFIG_GDMA_ISR_IRAM_SAFE || CONFIG_GDMA_CTRL_FUNC_IN_IRAM
#define GDMA_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_INTRDISABLED)
#define GDMA_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) #define GDMA_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
#else #else
#define GDMA_INTR_ALLOC_FLAGS ESP_INTR_FLAG_INTRDISABLED
#define GDMA_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT #define GDMA_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
#endif // CONFIG_GDMA_ISR_IRAM_SAFE #endif
#if CONFIG_GDMA_ISR_IRAM_SAFE
#define GDMA_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_INTRDISABLED)
#else
#define GDMA_INTR_ALLOC_FLAGS ESP_INTR_FLAG_INTRDISABLED
#endif
#define GDMA_INVALID_PERIPH_TRIG (0x3F) #define GDMA_INVALID_PERIPH_TRIG (0x3F)
#define SEARCH_REQUEST_RX_CHANNEL (1 << 0) #define SEARCH_REQUEST_RX_CHANNEL (1 << 0)
@@ -385,9 +389,7 @@ esp_err_t gdma_register_tx_event_callbacks(gdma_channel_handle_t dma_chan, gdma_
ESP_GOTO_ON_FALSE(esp_ptr_in_iram(cbs->on_trans_eof), ESP_ERR_INVALID_ARG, err, TAG, "on_trans_eof not in IRAM"); ESP_GOTO_ON_FALSE(esp_ptr_in_iram(cbs->on_trans_eof), ESP_ERR_INVALID_ARG, err, TAG, "on_trans_eof not in IRAM");
} }
if (user_data) { if (user_data) {
ESP_GOTO_ON_FALSE(esp_ptr_in_dram(user_data) || ESP_GOTO_ON_FALSE(esp_ptr_internal(user_data), ESP_ERR_INVALID_ARG, err, TAG, "user context not in internal RAM");
esp_ptr_in_diram_dram(user_data) ||
esp_ptr_in_rtc_dram_fast(user_data), ESP_ERR_INVALID_ARG, err, TAG, "user context not in DRAM");
} }
#endif // CONFIG_GDMA_ISR_IRAM_SAFE #endif // CONFIG_GDMA_ISR_IRAM_SAFE
@@ -423,9 +425,7 @@ esp_err_t gdma_register_rx_event_callbacks(gdma_channel_handle_t dma_chan, gdma_
ESP_GOTO_ON_FALSE(esp_ptr_in_iram(cbs->on_recv_eof), ESP_ERR_INVALID_ARG, err, TAG, "on_recv_eof not in IRAM"); ESP_GOTO_ON_FALSE(esp_ptr_in_iram(cbs->on_recv_eof), ESP_ERR_INVALID_ARG, err, TAG, "on_recv_eof not in IRAM");
} }
if (user_data) { if (user_data) {
ESP_GOTO_ON_FALSE(esp_ptr_in_dram(user_data) || ESP_GOTO_ON_FALSE(esp_ptr_internal(user_data), ESP_ERR_INVALID_ARG, err, TAG, "user context not in internal RAM");
esp_ptr_in_diram_dram(user_data) ||
esp_ptr_in_rtc_dram_fast(user_data), ESP_ERR_INVALID_ARG, err, TAG, "user context not in DRAM");
} }
#endif // CONFIG_GDMA_ISR_IRAM_SAFE #endif // CONFIG_GDMA_ISR_IRAM_SAFE

View File

@@ -31,13 +31,17 @@
// If ISR handler is allowed to run whilst cache is disabled, // If ISR handler is allowed to run whilst cache is disabled,
// Make sure all the code and related variables used by the handler are in the SRAM // Make sure all the code and related variables used by the handler are in the SRAM
#if CONFIG_GPTIMER_ISR_IRAM_SAFE #if CONFIG_GPTIMER_ISR_IRAM_SAFE || CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM
#define GPTIMER_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_INTRDISABLED)
#define GPTIMER_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) #define GPTIMER_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
#else #else
#define GPTIMER_INTR_ALLOC_FLAGS ESP_INTR_FLAG_INTRDISABLED
#define GPTIMER_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT #define GPTIMER_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
#endif //CONFIG_GPTIMER_ISR_IRAM_SAFE #endif
#if CONFIG_GPTIMER_ISR_IRAM_SAFE
#define GPTIMER_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_INTRDISABLED)
#else
#define GPTIMER_INTR_ALLOC_FLAGS ESP_INTR_FLAG_INTRDISABLED
#endif
#define GPTIMER_PM_LOCK_NAME_LEN_MAX 16 #define GPTIMER_PM_LOCK_NAME_LEN_MAX 16
@@ -240,9 +244,7 @@ esp_err_t gptimer_register_event_callbacks(gptimer_handle_t timer, const gptimer
ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_alarm), ESP_ERR_INVALID_ARG, TAG, "on_alarm callback not in IRAM"); ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_alarm), ESP_ERR_INVALID_ARG, TAG, "on_alarm callback not in IRAM");
} }
if (user_data) { if (user_data) {
ESP_RETURN_ON_FALSE(esp_ptr_in_dram(user_data) || ESP_RETURN_ON_FALSE(esp_ptr_internal(user_data), ESP_ERR_INVALID_ARG, TAG, "user context not in internal RAM");
esp_ptr_in_diram_dram(user_data) ||
esp_ptr_in_rtc_dram_fast(user_data), ESP_ERR_INVALID_ARG, TAG, "user context not in DRAM");
} }
#endif #endif

View File

@@ -32,13 +32,17 @@
// If ISR handler is allowed to run whilst cache is disabled, // If ISR handler is allowed to run whilst cache is disabled,
// Make sure all the code and related variables used by the handler are in the SRAM // Make sure all the code and related variables used by the handler are in the SRAM
#if CONFIG_PCNT_ISR_IRAM_SAFE #if CONFIG_PCNT_ISR_IRAM_SAFE || CONFIG_PCNT_CTRL_FUNC_IN_IRAM
#define PCNT_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED)
#define PCNT_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) #define PCNT_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
#else #else
#define PCNT_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
#endif
#if CONFIG_PCNT_ISR_IRAM_SAFE
#define PCNT_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED)
#else
#define PCNT_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED) #define PCNT_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED)
#define PCNT_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT #endif
#endif //CONFIG_PCNT_ISR_IRAM_SAFE
#define PCNT_PM_LOCK_NAME_LEN_MAX 16 #define PCNT_PM_LOCK_NAME_LEN_MAX 16
@@ -340,10 +344,7 @@ esp_err_t pcnt_unit_register_event_callbacks(pcnt_unit_handle_t unit, const pcnt
ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_reach), ESP_ERR_INVALID_ARG, TAG, "on_reach callback not in IRAM"); ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_reach), ESP_ERR_INVALID_ARG, TAG, "on_reach callback not in IRAM");
} }
if (user_data) { if (user_data) {
ESP_RETURN_ON_FALSE(esp_ptr_in_dram(user_data) || ESP_RETURN_ON_FALSE(esp_ptr_internal(user_data), ESP_ERR_INVALID_ARG, TAG, "user context not in internal RAM");
esp_ptr_in_diram_dram(user_data) ||
esp_ptr_in_rtc_dram_fast(user_data),
ESP_ERR_INVALID_ARG, TAG, "user context not in DRAM");
} }
#endif #endif

View File

@@ -1,17 +1,23 @@
set(srcs "src/esp_lcd_common.c" set(srcs "src/esp_lcd_common.c"
"src/esp_lcd_panel_io.c" "src/esp_lcd_panel_io.c"
"src/esp_lcd_panel_io_i2c.c" "src/esp_lcd_panel_io_i2c.c"
"src/esp_lcd_panel_io_i2s.c"
"src/esp_lcd_panel_io_spi.c" "src/esp_lcd_panel_io_spi.c"
"src/esp_lcd_panel_io_i80.c"
"src/esp_lcd_panel_nt35510.c" "src/esp_lcd_panel_nt35510.c"
"src/esp_lcd_panel_ssd1306.c" "src/esp_lcd_panel_ssd1306.c"
"src/esp_lcd_panel_st7789.c" "src/esp_lcd_panel_st7789.c"
"src/esp_lcd_panel_ops.c" "src/esp_lcd_panel_ops.c")
"src/esp_lcd_rgb_panel.c")
set(includes "include" "interface") set(includes "include" "interface")
set(priv_requires "driver") set(priv_requires "driver")
if(CONFIG_SOC_I2S_LCD_I80_VARIANT)
list(APPEND srcs "src/esp_lcd_panel_io_i2s.c")
endif()
if(CONFIG_SOC_LCDCAM_SUPPORTED)
list(APPEND srcs "src/esp_lcd_panel_io_i80.c" "src/esp_lcd_rgb_panel.c")
endif()
idf_component_register(SRCS ${srcs} idf_component_register(SRCS ${srcs}
INCLUDE_DIRS ${includes} INCLUDE_DIRS ${includes}
PRIV_REQUIRES ${priv_requires}) PRIV_REQUIRES ${priv_requires}
LDFRAGMENTS linker.lf)

View File

@@ -6,11 +6,24 @@ menu "LCD and Touch Panel"
help help
LCD driver allocates an internal buffer to transform the data into a proper format, because of LCD driver allocates an internal buffer to transform the data into a proper format, because of
the endian order mismatch. This option is to set the size of the buffer, in bytes. the endian order mismatch. This option is to set the size of the buffer, in bytes.
config LCD_ENABLE_DEBUG_LOG config LCD_ENABLE_DEBUG_LOG
bool "Enable debug log" bool "Enable debug log"
default n default n
help help
Wether to enable the debug log message for LCD driver. Wether to enable the debug log message for LCD driver.
Note that, this option only controls the LCD driver log, won't affect other drivers. Note that, this option only controls the LCD driver log, won't affect other drivers.
if SOC_LCD_RGB_SUPPORTED
config LCD_RGB_ISR_IRAM_SAFE
bool "RGB LCD ISR IRAM-Safe"
default n
select GDMA_CTRL_FUNC_IN_IRAM # need to restart GDMA in the LCD ISR
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_LCD_RGB_SUPPORTED
endmenu endmenu
endmenu endmenu

View File

@@ -0,0 +1,6 @@
[mapping:esp_lcd]
archive: libesp_lcd.a
entries:
if LCD_RGB_ISR_IRAM_SAFE = y:
esp_lcd_common: lcd_com_mount_dma_data (noflash)
esp_lcd_rgb_panel: lcd_rgb_panel_start_transmission (noflash)

View File

@@ -39,6 +39,12 @@
#include "hal/lcd_hal.h" #include "hal/lcd_hal.h"
#include "hal/lcd_ll.h" #include "hal/lcd_ll.h"
#if CONFIG_LCD_RGB_ISR_IRAM_SAFE
#define LCD_RGB_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_INTRDISABLED)
#else
#define LCD_RGB_INTR_ALLOC_FLAGS ESP_INTR_FLAG_INTRDISABLED
#endif
static const char *TAG = "lcd_panel.rgb"; static const char *TAG = "lcd_panel.rgb";
typedef struct esp_rgb_panel_t esp_rgb_panel_t; typedef struct esp_rgb_panel_t esp_rgb_panel_t;
@@ -100,6 +106,16 @@ esp_err_t esp_lcd_new_rgb_panel(const esp_lcd_rgb_panel_config_t *rgb_panel_conf
ESP_GOTO_ON_FALSE(rgb_panel_config && ret_panel, ESP_ERR_INVALID_ARG, err, TAG, "invalid parameter"); ESP_GOTO_ON_FALSE(rgb_panel_config && ret_panel, ESP_ERR_INVALID_ARG, err, TAG, "invalid parameter");
ESP_GOTO_ON_FALSE(rgb_panel_config->data_width == 16, ESP_ERR_NOT_SUPPORTED, err, TAG, ESP_GOTO_ON_FALSE(rgb_panel_config->data_width == 16, ESP_ERR_NOT_SUPPORTED, err, TAG,
"unsupported data width %d", rgb_panel_config->data_width); "unsupported data width %d", rgb_panel_config->data_width);
#if CONFIG_LCD_RGB_ISR_IRAM_SAFE
if (rgb_panel_config->on_frame_trans_done) {
ESP_RETURN_ON_FALSE(esp_ptr_in_iram(rgb_panel_config->on_frame_trans_done), ESP_ERR_INVALID_ARG, TAG, "on_frame_trans_done callback not in IRAM");
}
if (rgb_panel_config->user_ctx) {
ESP_RETURN_ON_FALSE(esp_ptr_internal(rgb_panel_config->user_ctx), ESP_ERR_INVALID_ARG, TAG, "user context not in internal RAM");
}
#endif
// calculate the number of DMA descriptors // calculate the number of DMA descriptors
size_t fb_size = rgb_panel_config->timings.h_res * rgb_panel_config->timings.v_res * rgb_panel_config->data_width / 8; size_t fb_size = rgb_panel_config->timings.h_res * rgb_panel_config->timings.v_res * rgb_panel_config->data_width / 8;
size_t num_dma_nodes = fb_size / DMA_DESCRIPTOR_BUFFER_MAX_SIZE; size_t num_dma_nodes = fb_size / DMA_DESCRIPTOR_BUFFER_MAX_SIZE;
@@ -147,7 +163,7 @@ esp_err_t esp_lcd_new_rgb_panel(const esp_lcd_rgb_panel_config_t *rgb_panel_conf
ret = lcd_rgb_panel_select_periph_clock(rgb_panel, rgb_panel_config->clk_src); ret = lcd_rgb_panel_select_periph_clock(rgb_panel, rgb_panel_config->clk_src);
ESP_GOTO_ON_ERROR(ret, err, TAG, "select periph clock failed"); ESP_GOTO_ON_ERROR(ret, err, TAG, "select periph clock failed");
// install interrupt service, (LCD peripheral shares the interrupt source with Camera by different mask) // install interrupt service, (LCD peripheral shares the interrupt source with Camera by different mask)
int isr_flags = LCD_INTR_ALLOC_FLAGS | ESP_INTR_FLAG_SHARED; int isr_flags = LCD_RGB_INTR_ALLOC_FLAGS | ESP_INTR_FLAG_SHARED;
ret = esp_intr_alloc_intrstatus(lcd_periph_signals.panels[panel_id].irq_id, isr_flags, ret = esp_intr_alloc_intrstatus(lcd_periph_signals.panels[panel_id].irq_id, isr_flags,
(uint32_t)lcd_ll_get_interrupt_status_reg(rgb_panel->hal.dev), (uint32_t)lcd_ll_get_interrupt_status_reg(rgb_panel->hal.dev),
LCD_LL_EVENT_VSYNC_END, lcd_default_isr_handler, rgb_panel, &rgb_panel->intr); LCD_LL_EVENT_VSYNC_END, lcd_default_isr_handler, rgb_panel, &rgb_panel->intr);

View File

@@ -3,3 +3,16 @@ cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake) include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(rgb_lcd_panel_test) project(rgb_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-dir ${CMAKE_BINARY_DIR}/esp-idf/esp_lcd/
--elf-file ${CMAKE_BINARY_DIR}/rgb_lcd_panel_test.elf
find-refs
--from-sections=.iram0.text
--to-sections=.flash.text,.flash.rodata
--exit-code
DEPENDS ${elf}
)
endif()

View File

@@ -1,7 +1,6 @@
set(srcs "test_app_main.c" set(srcs "test_app_main.c"
"test_rgb_panel.c") "test_rgb_panel.c")
idf_component_register(SRCS ${srcs} idf_component_register(SRCS ${srcs})
PRIV_REQUIRES esp_lcd unity)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u test_app_include_rgb_lcd") target_link_libraries(${COMPONENT_LIB} INTERFACE "-u test_app_include_rgb_lcd")

View File

@@ -9,7 +9,7 @@
#include "esp_heap_caps.h" #include "esp_heap_caps.h"
// Some resources are lazy allocated in LCD driver, the threadhold is left for that case // Some resources are lazy allocated in LCD driver, the threadhold is left for that case
#define TEST_MEMORY_LEAK_THRESHOLD (-300) #define TEST_MEMORY_LEAK_THRESHOLD (-500)
static size_t before_free_8bit; static size_t before_free_8bit;
static size_t before_free_32bit; static size_t before_free_32bit;

View File

@@ -5,22 +5,30 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "unity.h" #include "unity.h"
#include "esp_lcd_panel_rgb.h" #include "esp_lcd_panel_rgb.h"
#include "esp_lcd_panel_ops.h" #include "esp_lcd_panel_ops.h"
#include "esp_random.h" #include "esp_random.h"
#include "esp_attr.h"
#include "nvs_flash.h"
#include "test_rgb_board.h" #include "test_rgb_board.h"
#if CONFIG_LCD_RGB_ISR_IRAM_SAFE
#define TEST_LCD_CALLBACK_ATTR IRAM_ATTR
#else
#define TEST_LCD_CALLBACK_ATTR
#endif // CONFIG_LCD_RGB_ISR_IRAM_SAFE
#define TEST_IMG_SIZE (100 * 100 * sizeof(uint16_t))
void test_app_include_rgb_lcd(void) void test_app_include_rgb_lcd(void)
{ {
} }
TEST_CASE("lcd_rgb_lcd_panel", "[lcd]") static esp_lcd_panel_handle_t test_rgb_panel_initialization(bool stream_mode, esp_lcd_rgb_panel_frame_trans_done_cb_t cb, void *user_data)
{ {
#define TEST_IMG_SIZE (100 * 100 * sizeof(uint16_t))
uint8_t *img = malloc(TEST_IMG_SIZE);
TEST_ASSERT_NOT_NULL(img);
esp_lcd_panel_handle_t panel_handle = NULL; esp_lcd_panel_handle_t panel_handle = NULL;
esp_lcd_rgb_panel_config_t panel_config = { esp_lcd_rgb_panel_config_t panel_config = {
.data_width = 16, .data_width = 16,
@@ -59,27 +67,117 @@ TEST_CASE("lcd_rgb_lcd_panel", "[lcd]")
.vsync_back_porch = 18, .vsync_back_porch = 18,
.vsync_front_porch = 4, .vsync_front_porch = 4,
.vsync_pulse_width = 1, .vsync_pulse_width = 1,
.flags.pclk_active_neg = 1, // RGB data is clocked out on falling edge
}, },
.on_frame_trans_done = cb,
.user_ctx = user_data,
.flags.fb_in_psram = 1, // allocate frame buffer in PSRAM .flags.fb_in_psram = 1, // allocate frame buffer in PSRAM
.flags.relax_on_idle = !stream_mode,
}; };
// Test stream mode and one-off mode
for (int i = 0; i < 2; i++) {
panel_config.flags.relax_on_idle = i;
TEST_ESP_OK(esp_lcd_new_rgb_panel(&panel_config, &panel_handle));
TEST_ESP_OK(esp_lcd_panel_reset(panel_handle));
TEST_ESP_OK(esp_lcd_panel_init(panel_handle));
for (int i = 0; i < 200; i++) { TEST_ESP_OK(esp_lcd_new_rgb_panel(&panel_config, &panel_handle));
uint8_t color_byte = esp_random() & 0xFF; TEST_ESP_OK(esp_lcd_panel_reset(panel_handle));
int x_start = esp_random() % (TEST_LCD_H_RES - 100); TEST_ESP_OK(esp_lcd_panel_init(panel_handle));
int y_start = esp_random() % (TEST_LCD_V_RES - 100);
memset(img, color_byte, TEST_IMG_SIZE);
esp_lcd_panel_draw_bitmap(panel_handle, x_start, y_start, x_start + 100, y_start + 100, img);
}
TEST_ESP_OK(esp_lcd_panel_del(panel_handle)); return panel_handle;
}
free(img);
#undef TEST_IMG_SIZE
} }
TEST_CASE("lcd_rgb_panel_stream_mode", "[lcd]")
{
uint8_t *img = malloc(TEST_IMG_SIZE);
TEST_ASSERT_NOT_NULL(img);
printf("initialize RGB panel with stream mode\r\n");
esp_lcd_panel_handle_t panel_handle = test_rgb_panel_initialization(true, NULL, NULL);
printf("flush random color block\r\n");
for (int i = 0; i < 200; i++) {
uint8_t color_byte = esp_random() & 0xFF;
int x_start = esp_random() % (TEST_LCD_H_RES - 100);
int y_start = esp_random() % (TEST_LCD_V_RES - 100);
memset(img, color_byte, TEST_IMG_SIZE);
esp_lcd_panel_draw_bitmap(panel_handle, x_start, y_start, x_start + 100, y_start + 100, img);
}
printf("delete RGB panel\r\n");
TEST_ESP_OK(esp_lcd_panel_del(panel_handle));
free(img);
}
TEST_LCD_CALLBACK_ATTR static bool test_rgb_panel_trans_done(esp_lcd_panel_handle_t panel, esp_lcd_rgb_panel_event_data_t *edata, void *user_ctx)
{
TaskHandle_t task_to_notify = (TaskHandle_t)user_ctx;
BaseType_t high_task_wakeup;
vTaskNotifyGiveFromISR(task_to_notify, &high_task_wakeup);
return high_task_wakeup == pdTRUE;
}
TEST_CASE("lcd_rgb_panel_one_shot_mode", "[lcd]")
{
uint8_t *img = malloc(TEST_IMG_SIZE);
TEST_ASSERT_NOT_NULL(img);
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
printf("initialize RGB panel with ont-shot mode\r\n");
esp_lcd_panel_handle_t panel_handle = test_rgb_panel_initialization(false, test_rgb_panel_trans_done, cur_task);
printf("flush random color block\r\n");
for (int i = 0; i < 200; i++) {
uint8_t color_byte = esp_random() & 0xFF;
int x_start = esp_random() % (TEST_LCD_H_RES - 100);
int y_start = esp_random() % (TEST_LCD_V_RES - 100);
memset(img, color_byte, TEST_IMG_SIZE);
esp_lcd_panel_draw_bitmap(panel_handle, x_start, y_start, x_start + 100, y_start + 100, img);
// wait for flush done
TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(1000)));
}
printf("delete RGB panel\r\n");
TEST_ESP_OK(esp_lcd_panel_del(panel_handle));
free(img);
}
#if CONFIG_LCD_RGB_ISR_IRAM_SAFE
TEST_CASE("lcd_rgb_panel_with_nvs_read_write", "[lcd]")
{
uint8_t *img = malloc(TEST_IMG_SIZE);
TEST_ASSERT_NOT_NULL(img);
printf("initialize RGB panel with stream mode\r\n");
esp_lcd_panel_handle_t panel_handle = test_rgb_panel_initialization(true, NULL, NULL);
printf("flush one clock block to the LCD\r\n");
uint8_t color_byte = esp_random() & 0xFF;
int x_start = esp_random() % (TEST_LCD_H_RES - 100);
int y_start = esp_random() % (TEST_LCD_V_RES - 100);
memset(img, color_byte, TEST_IMG_SIZE);
esp_lcd_panel_draw_bitmap(panel_handle, x_start, y_start, x_start + 100, y_start + 100, img);
printf("The LCD driver should keep flushing the color block in the background (as it's in stream mode)\r\n");
// read/write the SPI Flash by NVS APIs, the LCD driver should stay work
printf("initialize NVS flash\r\n");
esp_err_t err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
// NVS partition was truncated and needs to be erased
TEST_ESP_OK(nvs_flash_erase());
// Retry nvs_flash_init
err = nvs_flash_init();
}
TEST_ESP_OK(err);
printf("open NVS storage\r\n");
nvs_handle_t my_handle;
TEST_ESP_OK(nvs_open("storage", NVS_READWRITE, &my_handle));
TEST_ESP_OK(nvs_erase_all(my_handle));
int test_count;
for (int i = 0; i < 50; i++) {
printf("write %d to NVS partition\r\n", i);
TEST_ESP_OK(nvs_set_i32(my_handle, "test_count", i));
TEST_ESP_OK(nvs_commit(my_handle));
TEST_ESP_OK(nvs_get_i32(my_handle, "test_count", &test_count));
TEST_ASSERT_EQUAL(i, test_count);
vTaskDelay(pdMS_TO_TICKS(50));
}
printf("close NVS storage\r\n");
nvs_close(my_handle);
TEST_ESP_OK(nvs_flash_deinit());
printf("delete RGB panel\r\n");
TEST_ESP_OK(esp_lcd_panel_del(panel_handle));
free(img);
}
#endif // CONFIG_LCD_RGB_ISR_IRAM_SAFE

View File

@@ -10,6 +10,7 @@ from pytest_embedded import Dut
@pytest.mark.parametrize( @pytest.mark.parametrize(
'config', 'config',
[ [
'iram_safe',
'release', 'release',
], ],
indirect=True, indirect=True,

View File

@@ -0,0 +1,5 @@
CONFIG_COMPILER_DUMP_RTL_FILES=y
CONFIG_LCD_RGB_ISR_IRAM_SAFE=y
# silent the error check, as the error string are stored in rodata, causing RTL check failure
CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y

View File

@@ -1,3 +1,4 @@
CONFIG_ESP32S3_SPIRAM_SUPPORT=y CONFIG_ESP32S3_SPIRAM_SUPPORT=y
CONFIG_ESPTOOLPY_OCT_FLASH=y
CONFIG_SPIRAM_MODE_OCT=y CONFIG_SPIRAM_MODE_OCT=y
CONFIG_SPIRAM_SPEED_80M=y CONFIG_SPIRAM_SPEED_80M=y