mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
feat(mipi_dsi): update low level functions to include underrun interrupt
This commit is contained in:
parent
e91c5e33ca
commit
28a3227b2f
@ -32,12 +32,12 @@ struct esp_lcd_dpi_panel_t {
|
||||
esp_lcd_panel_t base; // Base class of generic lcd panel
|
||||
esp_lcd_dsi_bus_handle_t bus; // DSI bus handle
|
||||
uint8_t virtual_channel; // Virtual channel ID, index from 0
|
||||
uint8_t cur_fb_index; // Current frame buffer index
|
||||
uint8_t num_fbs; // Number of frame buffers
|
||||
uint8_t cur_fb_index; // Current frame buffer index
|
||||
uint8_t num_fbs; // Number of frame buffers
|
||||
uint8_t *fbs[DPI_PANEL_MAX_FB_NUM]; // Frame buffers
|
||||
uint32_t h_pixels; // Horizontal pixels
|
||||
uint32_t v_pixels; // Vertical pixels
|
||||
size_t frame_buffer_size; // Frame buffer size
|
||||
size_t fb_size; // Frame buffer size, in bytes
|
||||
size_t bits_per_pixel; // Bits per pixel
|
||||
lcd_color_rgb_pixel_format_t pixel_format; // RGB Pixel format
|
||||
dw_gdma_channel_handle_t dma_chan; // DMA channel
|
||||
@ -126,7 +126,7 @@ static esp_err_t dpi_panel_create_dma_link(esp_lcd_dpi_panel_t *dpi_panel)
|
||||
|
||||
// create DMA link lists
|
||||
dw_gdma_link_list_config_t link_list_config = {
|
||||
.num_items = DPI_PANEL_LLI_PER_FRAME,
|
||||
.num_items = DPI_PANEL_MIN_DMA_NODES_PER_LINK,
|
||||
.link_type = DW_GDMA_LINKED_LIST_TYPE_SINGLY,
|
||||
};
|
||||
for (int i = 0; i < dpi_panel->num_fbs; i++) {
|
||||
@ -191,21 +191,21 @@ esp_err_t esp_lcd_new_panel_dpi(esp_lcd_dsi_bus_handle_t bus, const esp_lcd_dpi_
|
||||
uint32_t cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_DATA);
|
||||
// DMA doesn't have requirement on the buffer alignment, but the cache does
|
||||
uint32_t alignment = cache_line_size;
|
||||
size_t frame_buffer_size = panel_config->video_timing.h_size * panel_config->video_timing.v_size * bits_per_pixel / 8;
|
||||
size_t fb_size = panel_config->video_timing.h_size * panel_config->video_timing.v_size * bits_per_pixel / 8;
|
||||
uint8_t *frame_buffer = NULL;
|
||||
for (int i = 0; i < num_fbs; i++) {
|
||||
frame_buffer = heap_caps_aligned_calloc(alignment, 1, frame_buffer_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
frame_buffer = heap_caps_aligned_calloc(alignment, 1, fb_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
ESP_GOTO_ON_FALSE(frame_buffer, ESP_ERR_NO_MEM, err, TAG, "no memory for frame buffer");
|
||||
dpi_panel->fbs[i] = frame_buffer;
|
||||
ESP_LOGD(TAG, "fb[%d] @%p", i, frame_buffer);
|
||||
// preset the frame buffer with black color
|
||||
// the frame buffer address alignment is ensured by `heap_caps_aligned_calloc`
|
||||
// while the value of the frame_buffer_size may not be aligned to the cache line size
|
||||
// while the value of the fb_size may not be aligned to the cache line size
|
||||
// but that's not a problem because the `heap_caps_aligned_calloc` internally allocated a buffer whose size is aligned up to the cache line size
|
||||
ESP_GOTO_ON_ERROR(esp_cache_msync(frame_buffer, frame_buffer_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED),
|
||||
ESP_GOTO_ON_ERROR(esp_cache_msync(frame_buffer, fb_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED),
|
||||
err, TAG, "cache write back failed");
|
||||
}
|
||||
dpi_panel->frame_buffer_size = frame_buffer_size;
|
||||
dpi_panel->fb_size = fb_size;
|
||||
dpi_panel->bits_per_pixel = bits_per_pixel;
|
||||
dpi_panel->h_pixels = panel_config->video_timing.h_size;
|
||||
dpi_panel->v_pixels = panel_config->video_timing.v_size;
|
||||
@ -282,6 +282,7 @@ esp_err_t esp_lcd_new_panel_dpi(esp_lcd_dsi_bus_handle_t bus, const esp_lcd_dpi_
|
||||
mipi_dsi_brg_ll_set_underrun_discard_count(hal->bridge, panel_config->video_timing.h_size);
|
||||
// use the DW_GDMA as the flow controller
|
||||
mipi_dsi_brg_ll_set_flow_controller(hal->bridge, MIPI_DSI_LL_FLOW_CONTROLLER_DMA);
|
||||
mipi_dsi_brg_ll_set_multi_block_number(hal->bridge, DPI_PANEL_MIN_DMA_NODES_PER_LINK);
|
||||
mipi_dsi_brg_ll_set_burst_len(hal->bridge, 256);
|
||||
mipi_dsi_brg_ll_set_empty_threshold(hal->bridge, 1024 - 256);
|
||||
// enable DSI bridge
|
||||
@ -381,7 +382,7 @@ static esp_err_t dpi_panel_init(esp_lcd_panel_t *panel)
|
||||
.burst_len = 16,
|
||||
.width = DW_GDMA_TRANS_WIDTH_64,
|
||||
},
|
||||
.size = dpi_panel->frame_buffer_size * 8 / 64,
|
||||
.size = dpi_panel->fb_size * 8 / 64,
|
||||
};
|
||||
for (int i = 0; i < dpi_panel->num_fbs; i++) {
|
||||
link_list = dpi_panel->link_lists[i];
|
||||
@ -419,7 +420,7 @@ static esp_err_t dpi_panel_draw_bitmap(esp_lcd_panel_t *panel, int x_start, int
|
||||
uint8_t cur_fb_index = dpi_panel->cur_fb_index;
|
||||
uint8_t *frame_buffer = dpi_panel->fbs[cur_fb_index];
|
||||
uint8_t *draw_buffer = (uint8_t *)color_data;
|
||||
size_t frame_buffer_size = dpi_panel->frame_buffer_size;
|
||||
size_t fb_size = dpi_panel->fb_size;
|
||||
size_t bits_per_pixel = dpi_panel->bits_per_pixel;
|
||||
|
||||
// clip to boundaries
|
||||
@ -434,11 +435,11 @@ static esp_err_t dpi_panel_draw_bitmap(esp_lcd_panel_t *panel, int x_start, int
|
||||
uint8_t draw_buf_fb_index = 0;
|
||||
// check if the user draw buffer resides in any frame buffer's memory range
|
||||
// if so, we don't need to copy the data, just do cache write back
|
||||
if (draw_buffer >= dpi_panel->fbs[0] && draw_buffer < dpi_panel->fbs[0] + frame_buffer_size) {
|
||||
if (draw_buffer >= dpi_panel->fbs[0] && draw_buffer < dpi_panel->fbs[0] + fb_size) {
|
||||
draw_buf_fb_index = 0;
|
||||
} else if (draw_buffer >= dpi_panel->fbs[1] && draw_buffer < dpi_panel->fbs[1] + frame_buffer_size) {
|
||||
} else if (draw_buffer >= dpi_panel->fbs[1] && draw_buffer < dpi_panel->fbs[1] + fb_size) {
|
||||
draw_buf_fb_index = 1;
|
||||
} else if (draw_buffer >= dpi_panel->fbs[2] && draw_buffer < dpi_panel->fbs[2] + frame_buffer_size) {
|
||||
} else if (draw_buffer >= dpi_panel->fbs[2] && draw_buffer < dpi_panel->fbs[2] + fb_size) {
|
||||
draw_buf_fb_index = 2;
|
||||
} else {
|
||||
do_copy = true;
|
||||
|
@ -29,9 +29,8 @@
|
||||
#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_LLI_PER_FRAME 1 // NOTE: we assume ONE DMA link item can carry the WHOLE image (1920*1080)
|
||||
#define DPI_PANEL_MAX_FB_NUM 3 // maximum number of frame buffers that can be maintained by the driver
|
||||
#define DPI_PANEL_MIN_DMA_NODES_PER_LINK 1 // NOTE: we assume 1 DMA link item can carry the WHOLE image
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -222,16 +222,16 @@ TEST_CASE("MIPI DSI with multiple frame buffers (ILI9881C)", "[mipi_dsi]")
|
||||
uint16_t *fbs[3];
|
||||
TEST_ESP_OK(esp_lcd_dpi_panel_get_frame_buffer(mipi_dpi_panel, 3, (void **)&fbs[0], (void **)&fbs[1], (void **)&fbs[2]));
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int i = 0; i < 9; i++) {
|
||||
uint16_t color_byte = rand() & 0xFFFF;
|
||||
int x_start = rand() % (MIPI_DSI_LCD_H_RES - 100);
|
||||
int y_start = rand() % (MIPI_DSI_LCD_V_RES - 100);
|
||||
for (int j = y_start; j < y_start + 100; j++) {
|
||||
for (int k = x_start; k < x_start + 100; k++) {
|
||||
fbs[i][j * MIPI_DSI_LCD_H_RES + k] = color_byte;
|
||||
fbs[i % 3][j * MIPI_DSI_LCD_H_RES + k] = color_byte;
|
||||
}
|
||||
}
|
||||
esp_lcd_panel_draw_bitmap(mipi_dpi_panel, x_start, y_start, x_start + 100, y_start + 100, fbs[i]);
|
||||
esp_lcd_panel_draw_bitmap(mipi_dpi_panel, x_start, y_start, x_start + 100, y_start + 100, fbs[i % 3]);
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "hal/lcd_types.h"
|
||||
|
||||
#define MIPI_DSI_LL_GET_BRG(bus_id) (bus_id == 0 ? &MIPI_DSI_BRIDGE : NULL)
|
||||
#define MIPI_DSI_LL_EVENT_UNDERRUN (1 << 0)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -35,6 +36,46 @@ static inline void mipi_dsi_brg_ll_enable(dsi_brg_dev_t *dev, bool en)
|
||||
dev->en.dsi_en = en;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable DSI bridge interrupt for specific event mask
|
||||
*
|
||||
* @param dev Pointer to the DSI bridge controller register base address
|
||||
* @param mask Event mask
|
||||
* @param enable True to enable, False to disable
|
||||
*/
|
||||
static inline void mipi_dsi_brg_ll_enable_interrupt(dsi_brg_dev_t *dev, uint32_t mask, bool enable)
|
||||
{
|
||||
if (enable) {
|
||||
dev->int_ena.val |= mask;
|
||||
} else {
|
||||
dev->int_ena.val &= ~mask;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear DSI bridge interrupt for specific event mask
|
||||
*
|
||||
* @param dev Pointer to the DSI bridge controller register base address
|
||||
* @param mask Event mask
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void mipi_dsi_brg_ll_clear_interrupt_status(dsi_brg_dev_t *dev, uint32_t mask)
|
||||
{
|
||||
dev->int_clr.val = mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get interrupt status for DSI bridge
|
||||
*
|
||||
* @param dev Pointer to the DSI bridge controller register base address
|
||||
* @return Interrupt status
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline uint32_t mipi_dsi_brg_ll_get_interrupt_status(dsi_brg_dev_t *dev)
|
||||
{
|
||||
return dev->int_st.val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the number of 64-bit words in one dma burst transfer
|
||||
*
|
||||
@ -242,7 +283,7 @@ static inline void mipi_dsi_brg_ll_enable_ref_clock(dsi_brg_dev_t *dev, bool en)
|
||||
* @param dev Pointer to the DSI bridge controller register base address
|
||||
* @param controller Flow controller
|
||||
*/
|
||||
static inline void mipi_dsi_brg_ll_set_flow_controller(dsi_brg_dev_t* dev, mipi_dsi_ll_flow_controller_t controller)
|
||||
static inline void mipi_dsi_brg_ll_set_flow_controller(dsi_brg_dev_t *dev, mipi_dsi_ll_flow_controller_t controller)
|
||||
{
|
||||
dev->dma_flow_ctrl.dsi_dma_flow_controller = controller;
|
||||
}
|
||||
@ -255,9 +296,21 @@ static inline void mipi_dsi_brg_ll_set_flow_controller(dsi_brg_dev_t* dev, mipi_
|
||||
* @param dev Pointer to the DSI bridge controller register base address
|
||||
* @param number Number of blocks
|
||||
*/
|
||||
static inline void mipi_dsi_brg_ll_set_multi_block_number(dsi_brg_dev_t* dev, uint32_t number)
|
||||
static inline void mipi_dsi_brg_ll_set_multi_block_number(dsi_brg_dev_t *dev, uint32_t number)
|
||||
{
|
||||
dev->dma_flow_ctrl.dma_flow_multiblk_num = number;
|
||||
dev->dma_frame_interval.dma_multiblk_en = number > 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the FIFO depth of the DSI bridge
|
||||
*
|
||||
* @param dev Pointer to the DSI bridge controller register base address
|
||||
* @return FIFO depth
|
||||
*/
|
||||
static inline uint32_t mipi_dsi_brg_ll_get_fifo_depth(dsi_brg_dev_t *dev)
|
||||
{
|
||||
return dev->fifo_flow_status.raw_buf_depth;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -266,7 +319,7 @@ static inline void mipi_dsi_brg_ll_set_multi_block_number(dsi_brg_dev_t* dev, ui
|
||||
* @param dev Pointer to the DSI bridge controller register base address
|
||||
* @param std YUV-RGB conversion standard
|
||||
*/
|
||||
static inline void mipi_dsi_brg_ll_set_yuv_convert_std(dsi_brg_dev_t* dev, lcd_yuv_conv_std_t std)
|
||||
static inline void mipi_dsi_brg_ll_set_yuv_convert_std(dsi_brg_dev_t *dev, lcd_yuv_conv_std_t std)
|
||||
{
|
||||
switch (std) {
|
||||
case LCD_YUV_CONV_STD_BT601:
|
||||
|
@ -59,7 +59,9 @@
|
||||
#define DR_REG_DDRPHY_BASE (DR_REG_HPPERIPH0_BASE + 0x9D000)
|
||||
#define DR_REG_PVT_BASE (DR_REG_HPPERIPH0_BASE + 0x9E000)
|
||||
#define DR_REG_CSI_HOST_BASE (DR_REG_HPPERIPH0_BASE + 0x9F000)
|
||||
#define DR_REG_CSI_BRG_BASE (DR_REG_HPPERIPH0_BASE + 0x9F800)
|
||||
#define DR_REG_DSI_HOST_BASE (DR_REG_HPPERIPH0_BASE + 0xA0000)
|
||||
#define DR_REG_DSI_BRG_BASE (DR_REG_HPPERIPH0_BASE + 0xA0800)
|
||||
#define DR_REG_ISP_BASE (DR_REG_HPPERIPH0_BASE + 0xA1000)
|
||||
#define DR_REG_RMT_BASE (DR_REG_HPPERIPH0_BASE + 0xA2000)
|
||||
#define DR_REG_BITSCRAM_BASE (DR_REG_HPPERIPH0_BASE + 0xA3000)
|
||||
|
Loading…
x
Reference in New Issue
Block a user