mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
feat(mipi_dsi): support draw_bitmap by DMA2D engine
This feature can be enabled at runtime, by setting esp_lcd_dpi_panel_config_t:🎏:use_dma2d
This commit is contained in:
parent
b2de1b5665
commit
872058f086
@ -5,6 +5,7 @@
|
||||
*/
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_lcd_panel_interface.h"
|
||||
@ -12,6 +13,7 @@
|
||||
#include "esp_clk_tree.h"
|
||||
#include "esp_cache.h"
|
||||
#include "mipi_dsi_priv.h"
|
||||
#include "esp_async_fbcpy.h"
|
||||
#include "esp_private/dw_gdma.h"
|
||||
#include "hal/cache_hal.h"
|
||||
#include "hal/cache_ll.h"
|
||||
@ -33,10 +35,38 @@ struct esp_lcd_dpi_panel_t {
|
||||
uint32_t v_pixels; // Vertical pixels
|
||||
size_t frame_buffer_size; // Frame buffer size
|
||||
size_t bytes_per_pixel; // Bytes per pixel
|
||||
lcd_color_rgb_pixel_format_t pixel_format; // RGB Pixel format
|
||||
dw_gdma_channel_handle_t dma_chan; // DMA channel
|
||||
dw_gdma_link_list_handle_t link_list; // 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
|
||||
esp_lcd_dpi_panel_color_trans_done_cb_t on_color_trans_done; // Callback invoked when color data transfer has finished
|
||||
void* user_ctx; // User context for the callback
|
||||
};
|
||||
|
||||
IRAM_ATTR
|
||||
static bool async_fbcpy_done_cb(esp_async_fbcpy_handle_t mcp, esp_async_fbcpy_event_data_t *event, void *cb_args)
|
||||
{
|
||||
bool need_yield = false;
|
||||
esp_lcd_dpi_panel_t* dpi_panel = (esp_lcd_dpi_panel_t*)cb_args;
|
||||
|
||||
// release the draw semaphore first
|
||||
BaseType_t task_woken = pdFALSE;
|
||||
xSemaphoreGiveFromISR(dpi_panel->draw_sem, &task_woken);
|
||||
if (task_woken == pdTRUE) {
|
||||
need_yield = true;
|
||||
}
|
||||
|
||||
if (dpi_panel->on_color_trans_done) {
|
||||
if (dpi_panel->on_color_trans_done(&dpi_panel->base, NULL, dpi_panel->user_ctx)) {
|
||||
need_yield = true;
|
||||
}
|
||||
}
|
||||
|
||||
return need_yield;
|
||||
}
|
||||
|
||||
IRAM_ATTR
|
||||
static bool dma_list_invalid_block_cb(dw_gdma_channel_handle_t chan, const dw_gdma_break_event_data_t *event_data, void *user_data)
|
||||
{
|
||||
dw_gdma_lli_handle_t lli = event_data->invalid_lli;
|
||||
@ -104,15 +134,20 @@ esp_err_t esp_lcd_new_panel_dpi(esp_lcd_dsi_bus_handle_t bus, const esp_lcd_dpi_
|
||||
esp_err_t ret = ESP_OK;
|
||||
void *frame_buffer = NULL;
|
||||
esp_lcd_dpi_panel_t *dpi_panel = NULL;
|
||||
esp_async_fbcpy_handle_t fbcpy_ctx = NULL;
|
||||
ESP_RETURN_ON_FALSE(bus && panel_config && ret_panel, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
ESP_RETURN_ON_FALSE(panel_config->virtual_channel < 4, ESP_ERR_INVALID_ARG, TAG, "invalid virtual channel %d", panel_config->virtual_channel);
|
||||
ESP_RETURN_ON_FALSE(panel_config->dpi_clock_freq_mhz, ESP_ERR_INVALID_ARG, TAG, "invalid DPI clock frequency %"PRIu32, panel_config->dpi_clock_freq_mhz);
|
||||
#if !SOC_DMA2D_SUPPORTED
|
||||
ESP_RETURN_ON_FALSE(!panel_config->flags.use_dma2d, ESP_ERR_NOT_SUPPORTED, TAG, "DMA2D is not supported");
|
||||
#endif // !SOC_DMA2D_SUPPORTED
|
||||
int bus_id = bus->bus_id;
|
||||
mipi_dsi_hal_context_t *hal = &bus->hal;
|
||||
|
||||
dpi_panel = heap_caps_calloc(1, sizeof(esp_lcd_dpi_panel_t), DSI_MEM_ALLOC_CAPS);
|
||||
ESP_GOTO_ON_FALSE(dpi_panel, ESP_ERR_NO_MEM, err, TAG, "no memory for DPI panel");
|
||||
dpi_panel->virtual_channel = panel_config->virtual_channel;
|
||||
dpi_panel->pixel_format = panel_config->pixel_format;
|
||||
dpi_panel->bus = bus;
|
||||
|
||||
// allocate frame buffer from PSRAM
|
||||
@ -142,6 +177,17 @@ esp_err_t esp_lcd_new_panel_dpi(esp_lcd_dsi_bus_handle_t bus, const esp_lcd_dpi_
|
||||
// preset the frame buffer with black color
|
||||
ESP_GOTO_ON_ERROR(esp_cache_msync(frame_buffer, frame_buffer_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M), err, TAG, "cache write back failed");
|
||||
|
||||
#if SOC_DMA2D_SUPPORTED
|
||||
if (panel_config->flags.use_dma2d) {
|
||||
esp_async_fbcpy_config_t fbcpy_config = {};
|
||||
ESP_GOTO_ON_ERROR(esp_async_fbcpy_install(&fbcpy_config, &fbcpy_ctx), err, TAG, "install async memcpy 2d failed");
|
||||
dpi_panel->fbcpy_handle = fbcpy_ctx;
|
||||
dpi_panel->draw_sem = xSemaphoreCreateBinaryWithCaps(DSI_MEM_ALLOC_CAPS);
|
||||
ESP_GOTO_ON_FALSE(dpi_panel->draw_sem, ESP_ERR_NO_MEM, err, TAG, "no memory for draw semaphore");
|
||||
xSemaphoreGive(dpi_panel->draw_sem);
|
||||
}
|
||||
#endif // SOC_DMA2D_SUPPORTED
|
||||
|
||||
// if the clock source is not assigned, fallback to the default clock source
|
||||
mipi_dsi_dpi_clock_source_t dpi_clk_src = panel_config->dpi_clk_src;
|
||||
if (dpi_clk_src == 0) {
|
||||
@ -211,9 +257,6 @@ err:
|
||||
if (dpi_panel) {
|
||||
dpi_panel_del(&dpi_panel->base);
|
||||
}
|
||||
if (frame_buffer) {
|
||||
free(frame_buffer);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -229,6 +272,7 @@ static esp_err_t dpi_panel_del(esp_lcd_panel_t *panel)
|
||||
}
|
||||
// disable the DSI bridge
|
||||
mipi_dsi_brg_ll_enable(hal->bridge, false);
|
||||
// free memory
|
||||
if (dpi_panel->dma_chan) {
|
||||
dw_gdma_del_channel(dpi_panel->dma_chan);
|
||||
}
|
||||
@ -238,6 +282,12 @@ static esp_err_t dpi_panel_del(esp_lcd_panel_t *panel)
|
||||
if (dpi_panel->link_list) {
|
||||
dw_gdma_del_link_list(dpi_panel->link_list);
|
||||
}
|
||||
if (dpi_panel->fbcpy_handle) {
|
||||
esp_async_fbcpy_uninstall(dpi_panel->fbcpy_handle);
|
||||
}
|
||||
if (dpi_panel->draw_sem) {
|
||||
vSemaphoreDelete(dpi_panel->draw_sem);
|
||||
}
|
||||
free(dpi_panel);
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -293,18 +343,50 @@ static esp_err_t dpi_panel_draw_bitmap(esp_lcd_panel_t *panel, int x_start, int
|
||||
uint8_t *frame_buffer = dpi_panel->frame_buffer;
|
||||
size_t frame_buffer_size = dpi_panel->frame_buffer_size;
|
||||
|
||||
// TODO: memory copy by 2D-DMA
|
||||
size_t bytes_per_pixel = dpi_panel->bytes_per_pixel;
|
||||
const uint8_t *from = (const uint8_t *)color_data;
|
||||
uint8_t *to = frame_buffer + (y_start * dpi_panel->h_pixels + x_start) * bytes_per_pixel;
|
||||
uint32_t copy_bytes_per_line = (x_end - x_start) * bytes_per_pixel;
|
||||
uint32_t bytes_per_line = bytes_per_pixel * dpi_panel->h_pixels;
|
||||
for (int y = y_start; y < y_end; y++) {
|
||||
memcpy(to, from, copy_bytes_per_line);
|
||||
to += bytes_per_line;
|
||||
from += copy_bytes_per_line;
|
||||
if (!dpi_panel->fbcpy_handle) {
|
||||
size_t bytes_per_pixel = dpi_panel->bytes_per_pixel;
|
||||
const uint8_t *from = (const uint8_t *)color_data;
|
||||
uint8_t *to = frame_buffer + (y_start * dpi_panel->h_pixels + x_start) * bytes_per_pixel;
|
||||
uint32_t copy_bytes_per_line = (x_end - x_start) * bytes_per_pixel;
|
||||
uint32_t bytes_per_line = bytes_per_pixel * dpi_panel->h_pixels;
|
||||
for (int y = y_start; y < y_end; y++) {
|
||||
memcpy(to, from, copy_bytes_per_line);
|
||||
to += bytes_per_line;
|
||||
from += copy_bytes_per_line;
|
||||
}
|
||||
ESP_RETURN_ON_ERROR(esp_cache_msync(frame_buffer, frame_buffer_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M), TAG, "cache write back failed");
|
||||
// invoke the trans done callback
|
||||
if (dpi_panel->on_color_trans_done) {
|
||||
dpi_panel->on_color_trans_done(&dpi_panel->base, NULL, dpi_panel->user_ctx);
|
||||
}
|
||||
} else {
|
||||
// endure the previous draw operation has finish
|
||||
ESP_RETURN_ON_FALSE(xSemaphoreTake(dpi_panel->draw_sem, 0) == pdTRUE, ESP_ERR_INVALID_STATE, TAG, "previous draw operation is not finished");
|
||||
|
||||
// write back the user's draw buffer, so that the DMA can see the correct data
|
||||
size_t color_data_size = (x_end - x_start) * (y_end - y_start) * dpi_panel->bytes_per_pixel;
|
||||
esp_cache_msync((void*)color_data, color_data_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED);
|
||||
|
||||
esp_async_fbcpy_trans_desc_t fbcpy_trans_config = {
|
||||
.src_buffer = color_data,
|
||||
.dst_buffer = dpi_panel->frame_buffer,
|
||||
.src_buffer_size_x = x_end - x_start,
|
||||
.src_buffer_size_y = y_end - y_start,
|
||||
.dst_buffer_size_x = dpi_panel->h_pixels,
|
||||
.dst_buffer_size_y = dpi_panel->v_pixels,
|
||||
.src_offset_x = 0,
|
||||
.src_offset_y = 0,
|
||||
.dst_offset_x = x_start,
|
||||
.dst_offset_y = y_start,
|
||||
.copy_size_x = x_end - x_start,
|
||||
.copy_size_y = y_end - y_start,
|
||||
.pixel_format_unique_id = {
|
||||
.color_space = COLOR_SPACE_RGB,
|
||||
.pixel_format = dpi_panel->pixel_format,
|
||||
},
|
||||
};
|
||||
ESP_RETURN_ON_ERROR(esp_async_fbcpy(dpi_panel->fbcpy_handle, &fbcpy_trans_config, async_fbcpy_done_cb, dpi_panel), TAG, "async memcpy failed");
|
||||
}
|
||||
ESP_RETURN_ON_ERROR(esp_cache_msync(frame_buffer, frame_buffer_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M), TAG, "cache write back failed");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -333,3 +415,13 @@ esp_err_t esp_lcd_dpi_panel_set_pattern(esp_lcd_panel_handle_t panel, mipi_dsi_p
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_lcd_dpi_panel_register_event_callbacks(esp_lcd_panel_handle_t panel, const esp_lcd_dpi_panel_event_callbacks_t *cbs, void *user_ctx)
|
||||
{
|
||||
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);
|
||||
dpi_panel->on_color_trans_done = cbs->on_color_trans_done;
|
||||
dpi_panel->user_ctx = user_ctx;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
@ -83,8 +83,12 @@ typedef struct {
|
||||
uint8_t virtual_channel; /*!< Virtual channel ID, index from 0 */
|
||||
mipi_dsi_dpi_clock_source_t dpi_clk_src; /*!< MIPI DSI DPI clock source */
|
||||
uint32_t dpi_clock_freq_mhz; /*!< DPI clock frequency in MHz */
|
||||
lcd_color_rgb_pixel_format_t pixel_format; /*!< Pixel format */
|
||||
lcd_color_rgb_pixel_format_t pixel_format; /*!< Pixel format that used by the MIPI LCD device */
|
||||
esp_lcd_video_timing_t video_timing; /*!< Video timing */
|
||||
/// Extra configuration flags for MIPI DSI DPI panel
|
||||
struct extra_flags {
|
||||
uint32_t use_dma2d: 1; /*!< Use DMA2D to copy user buffer to the frame buffer when necessary */
|
||||
} flags; /*!< Extra configuration flags */
|
||||
} esp_lcd_dpi_panel_config_t;
|
||||
|
||||
/**
|
||||
@ -97,6 +101,7 @@ typedef struct {
|
||||
* - ESP_OK: Create MIPI DSI data panel successfully
|
||||
* - ESP_ERR_INVALID_ARG: Create MIPI DSI data panel failed because of invalid argument
|
||||
* - ESP_ERR_NO_MEM: Create MIPI DSI data panel failed because of out of memory
|
||||
* - ESP_ERR_NOT_SUPPORTED: Create MIPI DSI data panel failed because of unsupported feature
|
||||
* - ESP_FAIL: Create MIPI DSI data panel failed because of other error
|
||||
*/
|
||||
esp_err_t esp_lcd_new_panel_dpi(esp_lcd_dsi_bus_handle_t bus, const esp_lcd_dpi_panel_config_t *panel_config, esp_lcd_panel_handle_t *ret_panel);
|
||||
@ -104,14 +109,49 @@ esp_err_t esp_lcd_new_panel_dpi(esp_lcd_dsi_bus_handle_t bus, const esp_lcd_dpi_
|
||||
/**
|
||||
* @brief Set pre-defined pattern to the screen for testing or debugging purpose
|
||||
*
|
||||
* @param[in] dbi_panel MIPI DBI panel handle, returned from `esp_lcd_new_panel_dpi`
|
||||
* @param[in] dpi_panel MIPI DPI panel handle, returned from esp_lcd_new_panel_dpi()
|
||||
* @param[in] pattern Pattern type
|
||||
* @return
|
||||
* - ESP_OK: Set pattern successfully
|
||||
* - ESP_ERR_INVALID_ARG: Set pattern failed because of invalid argument
|
||||
* - ESP_FAIL: Set pattern failed because of other error
|
||||
*/
|
||||
esp_err_t esp_lcd_dpi_panel_set_pattern(esp_lcd_panel_handle_t dbi_panel, mipi_dsi_pattern_type_t pattern);
|
||||
esp_err_t esp_lcd_dpi_panel_set_pattern(esp_lcd_panel_handle_t dpi_panel, mipi_dsi_pattern_type_t pattern);
|
||||
|
||||
/**
|
||||
* @brief Type of LCD DPI panel event data
|
||||
*/
|
||||
typedef struct {
|
||||
} esp_lcd_dpi_panel_event_data_t;
|
||||
|
||||
/**
|
||||
* @brief Declare the prototype of the function that will be invoked when DPI panel finishes transferring color data
|
||||
*
|
||||
* @param[in] panel LCD panel handle, which is created by factory API like esp_lcd_new_panel_dpi()
|
||||
* @param[in] edata DPI panel event data, fed by driver
|
||||
* @param[in] user_ctx User data
|
||||
* @return Whether a high priority task has been waken up by this function
|
||||
*/
|
||||
typedef bool (*esp_lcd_dpi_panel_color_trans_done_cb_t)(esp_lcd_panel_handle_t panel, esp_lcd_dpi_panel_event_data_t *edata, void *user_ctx);
|
||||
|
||||
/**
|
||||
* @brief Type of LCD DPI panel callbacks
|
||||
*/
|
||||
typedef struct {
|
||||
esp_lcd_dpi_panel_color_trans_done_cb_t on_color_trans_done; /*!< Callback invoked when color data transfer has finished */
|
||||
} esp_lcd_dpi_panel_event_callbacks_t;
|
||||
|
||||
/**
|
||||
* @brief Register LCD DPI panel callbacks
|
||||
*
|
||||
* @param[in] dpi_panel LCD DPI panel handle, which is returned from esp_lcd_new_panel_dpi()
|
||||
* @param[in] cbs structure with all LCD panel callbacks
|
||||
* @param[in] user_ctx User private data, passed directly to callback's user_ctx
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG: Register callbacks failed because of invalid argument
|
||||
* - ESP_OK: Register callbacks successfully
|
||||
*/
|
||||
esp_err_t esp_lcd_dpi_panel_register_event_callbacks(esp_lcd_panel_handle_t dpi_panel, const esp_lcd_dpi_panel_event_callbacks_t *cbs, void *user_ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -33,15 +33,7 @@
|
||||
#define LCD_CMD_VSCRDEF 0x33 // Vertical scrolling definition
|
||||
#define LCD_CMD_TEOFF 0x34 // Turns off tearing effect
|
||||
#define LCD_CMD_TEON 0x35 // Turns on tearing effect
|
||||
|
||||
#define LCD_CMD_MADCTL 0x36 // Memory data access control
|
||||
#define LCD_CMD_MH_BIT (1 << 2) // Display data latch order, 0: refresh left to right, 1: refresh right to left
|
||||
#define LCD_CMD_BGR_BIT (1 << 3) // RGB/BGR order, 0: RGB, 1: BGR
|
||||
#define LCD_CMD_ML_BIT (1 << 4) // Line address order, 0: refresh top to bottom, 1: refresh bottom to top
|
||||
#define LCD_CMD_MV_BIT (1 << 5) // Row/Column order, 0: normal mode, 1: reverse mode
|
||||
#define LCD_CMD_MX_BIT (1 << 6) // Column address order, 0: left to right, 1: right to left
|
||||
#define LCD_CMD_MY_BIT (1 << 7) // Row address order, 0: top to bottom, 1: bottom to top
|
||||
|
||||
#define LCD_CMD_MADCTL 0x36 // Memory data access control
|
||||
#define LCD_CMD_VSCSAD 0x37 // Vertical scroll start address
|
||||
#define LCD_CMD_IDMOFF 0x38 // Recover from IDLE mode
|
||||
#define LCD_CMD_IDMON 0x39 // Fall into IDLE mode (8 color depth is displayed)
|
||||
@ -52,3 +44,13 @@
|
||||
#define LCD_CMD_GDCAN 0x45 // Get scan line
|
||||
#define LCD_CMD_WRDISBV 0x51 // Write display brightness
|
||||
#define LCD_CMD_RDDISBV 0x52 // Read display brightness value
|
||||
|
||||
/////////// Warning, It turns out that, the following bitmask is not defined as a standard, some manufacturer may use different bit position
|
||||
/////////// Please check the datasheet of your LCD panel before using the following bitmask
|
||||
/////////// IDF will remove them in the next major release (esp-idf 6.0)
|
||||
#define LCD_CMD_MH_BIT (1 << 2) // Display data latch order, 0: refresh left to right, 1: refresh right to left
|
||||
#define LCD_CMD_BGR_BIT (1 << 3) // RGB/BGR order, 0: RGB, 1: BGR
|
||||
#define LCD_CMD_ML_BIT (1 << 4) // Line address order, 0: refresh top to bottom, 1: refresh bottom to top
|
||||
#define LCD_CMD_MV_BIT (1 << 5) // Row/Column order, 0: normal mode, 1: reverse mode
|
||||
#define LCD_CMD_MX_BIT (1 << 6) // Column address order, 0: left to right, 1: right to left
|
||||
#define LCD_CMD_MY_BIT (1 << 7) // Row address order, 0: top to bottom, 1: bottom to top
|
||||
|
@ -45,6 +45,12 @@ The connection between ESP Board and the LCD is as follows:
|
||||
|
||||
Before testing your LCD, you also need to read your LCD spec carefully, and then adjust the values like "resolution" and "blank time" in the [main](./main/mipi_dsi_lcd_example_main.c) file.
|
||||
|
||||
### Configure
|
||||
|
||||
Run `idf.py menuconfig` and go to `Example Configuration`:
|
||||
|
||||
* Choose whether to `Use DMA2D to copy draw buffer to frame buffer` asynchronously. If you choose `No`, the draw buffer will be copied to the frame buffer synchronously by CPU.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Run `idf.py -p PORT build flash monitor` to build, flash and monitor the project. A LVGL widget should show up on the LCD as expected.
|
||||
|
8
examples/peripherals/lcd/mipi_dsi/main/Kconfig.projbuild
Normal file
8
examples/peripherals/lcd/mipi_dsi/main/Kconfig.projbuild
Normal file
@ -0,0 +1,8 @@
|
||||
menu "Example Configuration"
|
||||
config EXAMPLE_USE_DMA2D_COPY_FRAME
|
||||
bool "Use DMA2D to copy draw buffer to frame buffer"
|
||||
default y
|
||||
help
|
||||
Enable this option, DMA2D will be used to copy the LVGL draw buffer to the target frame buffer.
|
||||
This can save some CPU time and improve the performance.
|
||||
endmenu
|
@ -1,3 +1,3 @@
|
||||
dependencies:
|
||||
lvgl/lvgl: "~8.3.0"
|
||||
esp_lcd_ili9881c: ">=0.1.0"
|
||||
esp_lcd_ili9881c: "*"
|
||||
|
@ -75,7 +75,6 @@ static void example_lvgl_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area, lv_
|
||||
int offsety2 = area->y2;
|
||||
// pass the draw buffer to the driver
|
||||
esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, color_map);
|
||||
lv_disp_flush_ready(drv);
|
||||
}
|
||||
|
||||
static void example_increase_lvgl_tick(void *arg)
|
||||
@ -117,6 +116,13 @@ static void example_lvgl_port_task(void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
static bool example_notify_lvgl_flush_ready(esp_lcd_panel_handle_t panel, esp_lcd_dpi_panel_event_data_t *edata, void *user_ctx)
|
||||
{
|
||||
lv_disp_drv_t *disp_driver = (lv_disp_drv_t *)user_ctx;
|
||||
lv_disp_flush_ready(disp_driver);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void example_bsp_enable_dsi_phy_power(void)
|
||||
{
|
||||
// Turn on the power for MIPI DSI PHY, so it can go from "No Power" state to "Shutdown" state
|
||||
@ -210,8 +216,16 @@ void app_main(void)
|
||||
.vsync_pulse_width = EXAMPLE_MIPI_DSI_LCD_VSYNC,
|
||||
.vsync_front_porch = EXAMPLE_MIPI_DSI_LCD_VFP,
|
||||
},
|
||||
#if CONFIG_EXAMPLE_USE_DMA2D_COPY_FRAME
|
||||
.flags.use_dma2d = true,
|
||||
#endif
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_dpi(mipi_dsi_bus, &dpi_config, &mipi_dpi_panel));
|
||||
// register event callbacks
|
||||
esp_lcd_dpi_panel_event_callbacks_t cbs = {
|
||||
.on_color_trans_done = example_notify_lvgl_flush_ready,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_lcd_dpi_panel_register_event_callbacks(mipi_dpi_panel, &cbs, &disp_drv));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_init(mipi_dpi_panel));
|
||||
|
||||
// turn on backlight
|
||||
|
Loading…
Reference in New Issue
Block a user