feat(lcd): support color conversion for mipi dsi driver

This commit is contained in:
morris
2024-10-30 15:25:16 +08:00
parent 5e056de1e7
commit 0ed4c19c5e
32 changed files with 376 additions and 113 deletions

View File

@@ -7,6 +7,9 @@ set(COMPONENTS main)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(mipi_dsi_lcd_panel_test)
target_add_binary_data(mipi_dsi_lcd_panel_test.elf "resources/pictures/hello.yuv" BINARY)
target_add_binary_data(mipi_dsi_lcd_panel_test.elf "resources/pictures/world.yuv" BINARY)
if(CONFIG_COMPILER_DUMP_RTL_FILES)
add_custom_target(check_test_app_sections ALL
COMMAND ${PYTHON} $ENV{IDF_PATH}/tools/ci/check_callgraph.py

View File

@@ -1,2 +1,2 @@
dependencies:
esp_lcd_ili9881c: "~0.2.0"
esp_lcd_ek79007: "^1.0.0"

View File

@@ -9,16 +9,16 @@
extern "C" {
#endif
// Refresh Rate = 80000000/(40+140+40+800)/(4+16+16+1280) = 60Hz
#define MIPI_DSI_DPI_CLK_MHZ 80
#define MIPI_DSI_LCD_H_RES 800
#define MIPI_DSI_LCD_V_RES 1280
#define MIPI_DSI_LCD_HSYNC 40
#define MIPI_DSI_LCD_HBP 140
#define MIPI_DSI_LCD_HFP 40
#define MIPI_DSI_LCD_VSYNC 4
#define MIPI_DSI_LCD_VBP 16
#define MIPI_DSI_LCD_VFP 16
// Refresh Rate = 48000000/(10+120+120+1024)/(1+20+10+600) = 60Hz
#define MIPI_DSI_DPI_CLK_MHZ 48
#define MIPI_DSI_LCD_H_RES 1024
#define MIPI_DSI_LCD_V_RES 600
#define MIPI_DSI_LCD_HSYNC 10
#define MIPI_DSI_LCD_HBP 120
#define MIPI_DSI_LCD_HFP 120
#define MIPI_DSI_LCD_VSYNC 1
#define MIPI_DSI_LCD_VBP 20
#define MIPI_DSI_LCD_VFP 20
#define TEST_MIPI_DSI_PHY_PWR_LDO_CHAN 3
#define TEST_MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV 2500

View File

@@ -16,7 +16,7 @@
#include "esp_random.h"
#include "esp_attr.h"
#include "test_mipi_dsi_board.h"
#include "esp_lcd_ili9881c.h"
#include "esp_lcd_ek79007.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)
{
@@ -32,12 +32,11 @@ static void IRAM_ATTR test_delay_post_cache_disable(void *args)
#define TEST_IMG_SIZE (100 * 100 * sizeof(uint16_t))
TEST_CASE("MIPI DSI draw bitmap (ILI9881C) IRAM Safe", "[mipi_dsi]")
TEST_CASE("MIPI DSI draw bitmap (EK79007) 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();
@@ -59,22 +58,11 @@ TEST_CASE("MIPI DSI draw bitmap (ILI9881C) IRAM Safe", "[mipi_dsi]")
};
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,
.in_color_format = LCD_COLOR_FMT_RGB565,
.video_timing = {
.h_size = MIPI_DSI_LCD_H_RES,
.v_size = MIPI_DSI_LCD_V_RES,
@@ -86,8 +74,22 @@ TEST_CASE("MIPI DSI draw bitmap (ILI9881C) IRAM Safe", "[mipi_dsi]")
.vsync_front_porch = MIPI_DSI_LCD_VFP,
},
};
TEST_ESP_OK(esp_lcd_new_panel_dpi(mipi_dsi_bus, &dpi_config, &mipi_dpi_panel));
ek79007_vendor_config_t vendor_config = {
.mipi_config = {
.dsi_bus = mipi_dsi_bus,
.dpi_config = &dpi_config,
},
};
esp_lcd_panel_dev_config_t lcd_dev_config = {
.reset_gpio_num = -1,
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
.bits_per_pixel = 16,
.vendor_config = &vendor_config,
};
TEST_ESP_OK(esp_lcd_new_panel_ek79007(mipi_dbi_io, &lcd_dev_config, &mipi_dpi_panel));
TEST_ESP_OK(esp_lcd_panel_reset(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,
@@ -110,7 +112,6 @@ TEST_CASE("MIPI DSI draw bitmap (ILI9881C) IRAM Safe", "[mipi_dsi]")
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);

View File

@@ -15,14 +15,13 @@
#include "esp_random.h"
#include "esp_attr.h"
#include "test_mipi_dsi_board.h"
#include "esp_lcd_ili9881c.h"
#include "esp_lcd_ek79007.h"
TEST_CASE("MIPI DSI Pattern Generator (ILI9881C)", "[mipi_dsi]")
TEST_CASE("MIPI DSI Pattern Generator (EK79007)", "[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();
@@ -41,22 +40,11 @@ TEST_CASE("MIPI DSI Pattern Generator (ILI9881C)", "[mipi_dsi]")
};
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,
.in_color_format = LCD_COLOR_FMT_RGB888,
.video_timing = {
.h_size = MIPI_DSI_LCD_H_RES,
.v_size = MIPI_DSI_LCD_V_RES,
@@ -68,7 +56,20 @@ TEST_CASE("MIPI DSI Pattern Generator (ILI9881C)", "[mipi_dsi]")
.vsync_front_porch = MIPI_DSI_LCD_VFP,
},
};
TEST_ESP_OK(esp_lcd_new_panel_dpi(mipi_dsi_bus, &dpi_config, &mipi_dpi_panel));
ek79007_vendor_config_t vendor_config = {
.mipi_config = {
.dsi_bus = mipi_dsi_bus,
.dpi_config = &dpi_config,
},
};
esp_lcd_panel_dev_config_t lcd_dev_config = {
.reset_gpio_num = -1,
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
.bits_per_pixel = 24,
.vendor_config = &vendor_config,
};
TEST_ESP_OK(esp_lcd_new_panel_ek79007(mipi_dbi_io, &lcd_dev_config, &mipi_dpi_panel));
TEST_ESP_OK(esp_lcd_panel_reset(mipi_dpi_panel));
TEST_ESP_OK(esp_lcd_panel_init(mipi_dpi_panel));
TEST_ESP_OK(esp_lcd_dpi_panel_set_pattern(mipi_dpi_panel, MIPI_DSI_PATTERN_BAR_HORIZONTAL));
@@ -80,7 +81,6 @@ TEST_CASE("MIPI DSI Pattern Generator (ILI9881C)", "[mipi_dsi]")
TEST_ESP_OK(esp_lcd_dpi_panel_set_pattern(mipi_dpi_panel, MIPI_DSI_PATTERN_NONE));
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));
@@ -89,12 +89,11 @@ TEST_CASE("MIPI DSI Pattern Generator (ILI9881C)", "[mipi_dsi]")
#define TEST_IMG_SIZE (100 * 100 * sizeof(uint16_t))
TEST_CASE("MIPI DSI draw bitmap (ILI9881C)", "[mipi_dsi]")
TEST_CASE("MIPI DSI draw bitmap (EK79007)", "[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();
@@ -116,22 +115,11 @@ TEST_CASE("MIPI DSI draw bitmap (ILI9881C)", "[mipi_dsi]")
};
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,
.in_color_format = LCD_COLOR_FMT_RGB565,
.video_timing = {
.h_size = MIPI_DSI_LCD_H_RES,
.v_size = MIPI_DSI_LCD_V_RES,
@@ -143,7 +131,20 @@ TEST_CASE("MIPI DSI draw bitmap (ILI9881C)", "[mipi_dsi]")
.vsync_front_porch = MIPI_DSI_LCD_VFP,
},
};
TEST_ESP_OK(esp_lcd_new_panel_dpi(mipi_dsi_bus, &dpi_config, &mipi_dpi_panel));
ek79007_vendor_config_t vendor_config = {
.mipi_config = {
.dsi_bus = mipi_dsi_bus,
.dpi_config = &dpi_config,
},
};
esp_lcd_panel_dev_config_t lcd_dev_config = {
.reset_gpio_num = -1,
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
.bits_per_pixel = 16,
.vendor_config = &vendor_config,
};
TEST_ESP_OK(esp_lcd_new_panel_ek79007(mipi_dbi_io, &lcd_dev_config, &mipi_dpi_panel));
TEST_ESP_OK(esp_lcd_panel_reset(mipi_dpi_panel));
TEST_ESP_OK(esp_lcd_panel_init(mipi_dpi_panel));
for (int i = 0; i < 100; i++) {
@@ -156,7 +157,6 @@ TEST_CASE("MIPI DSI draw bitmap (ILI9881C)", "[mipi_dsi]")
}
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);
@@ -164,12 +164,11 @@ TEST_CASE("MIPI DSI draw bitmap (ILI9881C)", "[mipi_dsi]")
test_bsp_disable_dsi_phy_power();
}
TEST_CASE("MIPI DSI with multiple frame buffers (ILI9881C)", "[mipi_dsi]")
TEST_CASE("MIPI DSI with multiple frame buffers (EK79007)", "[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();
@@ -188,22 +187,11 @@ TEST_CASE("MIPI DSI with multiple frame buffers (ILI9881C)", "[mipi_dsi]")
};
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,
.in_color_format = LCD_COLOR_FMT_RGB565,
.num_fbs = 3, // the driver will allocate and maintain 3 frame buffers
.video_timing = {
.h_size = MIPI_DSI_LCD_H_RES,
@@ -216,7 +204,21 @@ TEST_CASE("MIPI DSI with multiple frame buffers (ILI9881C)", "[mipi_dsi]")
.vsync_front_porch = MIPI_DSI_LCD_VFP,
},
};
TEST_ESP_OK(esp_lcd_new_panel_dpi(mipi_dsi_bus, &dpi_config, &mipi_dpi_panel));
ek79007_vendor_config_t vendor_config = {
.mipi_config = {
.dsi_bus = mipi_dsi_bus,
.dpi_config = &dpi_config,
},
};
esp_lcd_panel_dev_config_t lcd_dev_config = {
.reset_gpio_num = -1,
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
.bits_per_pixel = 16,
.vendor_config = &vendor_config,
};
TEST_ESP_OK(esp_lcd_new_panel_ek79007(mipi_dbi_io, &lcd_dev_config, &mipi_dpi_panel));
TEST_ESP_OK(esp_lcd_panel_reset(mipi_dpi_panel));
TEST_ESP_OK(esp_lcd_panel_init(mipi_dpi_panel));
uint16_t *fbs[3];
@@ -236,9 +238,106 @@ TEST_CASE("MIPI DSI with multiple frame buffers (ILI9881C)", "[mipi_dsi]")
}
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));
test_bsp_disable_dsi_phy_power();
}
TEST_CASE("MIPI DSI draw YUV422 (EK79007)", "[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;
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_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,
// YUV422 -> RGB888
.in_color_format = LCD_COLOR_FMT_YUV422,
.out_color_format = LCD_COLOR_FMT_RGB888,
.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,
},
.flags = {
.use_dma2d = true,
}
};
ek79007_vendor_config_t vendor_config = {
.mipi_config = {
.dsi_bus = mipi_dsi_bus,
.dpi_config = &dpi_config,
},
};
esp_lcd_panel_dev_config_t lcd_dev_config = {
.reset_gpio_num = -1,
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
.bits_per_pixel = 24,
.vendor_config = &vendor_config,
};
TEST_ESP_OK(esp_lcd_new_panel_ek79007(mipi_dbi_io, &lcd_dev_config, &mipi_dpi_panel));
// Set color conversion configuration
esp_lcd_color_conv_config_t convert_config = {
.in_color_range = LCD_COLOR_RANGE_FULL,
.out_color_range = LCD_COLOR_RANGE_FULL,
.spec.yuv = {
.conv_std = LCD_YUV_CONV_STD_BT601,
.yuv422.in_pack_order = LCD_YUV422_PACK_ORDER_YUYV,
}
};
TEST_ESP_OK(esp_lcd_dpi_panel_set_color_conversion(mipi_dpi_panel, &convert_config));
TEST_ESP_OK(esp_lcd_panel_reset(mipi_dpi_panel));
TEST_ESP_OK(esp_lcd_panel_init(mipi_dpi_panel));
// YUV images are embedded in the firmware binary
extern const uint8_t image_hello_yuv_start[] asm("_binary_hello_yuv_start");
extern const uint8_t image_world_yuv_start[] asm("_binary_world_yuv_start");
printf("Draw YUV images\r\n");
for (int i = 0; i < 4; i++) {
TEST_ESP_OK(esp_lcd_panel_draw_bitmap(mipi_dpi_panel, 0, 0, 320, 320, image_hello_yuv_start));
vTaskDelay(pdMS_TO_TICKS(1000));
TEST_ESP_OK(esp_lcd_panel_draw_bitmap(mipi_dpi_panel, 0, 0, 320, 320, image_world_yuv_start));
vTaskDelay(pdMS_TO_TICKS(1000));
}
TEST_ESP_OK(esp_lcd_panel_del(mipi_dpi_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();
}

View File

@@ -0,0 +1,13 @@
# How to generate the YUV image from the PNG image
```bash
ffmpeg -i hello.png -pix_fmt yuyv422 hello.yuv
```
## Supported YUV422 packing order
| NAME | NB_COMPONENTS | BITS_PER_PIXEL | BIT_DEPTHS |
|----------|----------------|----------------|------------|
| yuyv422 | 3 | 16 | 8-8-8 |
| yvyu422 | 3 | 16 | 8-8-8 |
| uyvy422 | 3 | 16 | 8-8-8 |

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

File diff suppressed because one or more lines are too long