mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
lcd: support multi framebuffers for RGB LCD driver
This commit is contained in:
parent
22b82efbe5
commit
698fd7abb3
@ -14,7 +14,7 @@ if(CONFIG_SOC_I2S_LCD_I80_VARIANT)
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_LCDCAM_SUPPORTED)
|
||||
list(APPEND srcs "src/esp_lcd_panel_io_i80.c" "src/esp_lcd_rgb_panel.c")
|
||||
list(APPEND srcs "src/esp_lcd_panel_io_i80.c" "src/esp_lcd_panel_rgb.c")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
|
@ -118,6 +118,7 @@ typedef struct {
|
||||
size_t data_width; /*!< Number of data lines */
|
||||
size_t bits_per_pixel; /*!< Frame buffer color depth, in bpp, specially, if set to zero, it will default to `data_width`.
|
||||
When using a Serial RGB interface, this value could be different from `data_width` */
|
||||
size_t num_fbs; /*!< Number of screen-sized frame buffers that allocated by the driver. By default (set to either 0 or 1) only one frame buffer will be used. Maximum number of buffers are 3 */
|
||||
size_t bounce_buffer_size_px; /*!< If it's non-zero, the driver allocates two DRAM bounce buffers for DMA use.
|
||||
DMA fetching from DRAM bounce buffer is much faster than PSRAM frame buffer. */
|
||||
size_t sram_trans_align; /*!< Alignment of buffers (frame buffer or bounce buffer) that allocated in SRAM */
|
||||
@ -133,7 +134,7 @@ typedef struct {
|
||||
uint32_t refresh_on_demand: 1; /*!< If this flag is enabled, the host only refresh the frame buffer when `esp_lcd_panel_draw_bitmap` is called.
|
||||
This is useful when the LCD screen has a GRAM and can refresh the LCD by itself. */
|
||||
uint32_t fb_in_psram: 1; /*!< If this flag is enabled, the frame buffer will be allocated from PSRAM, preferentially */
|
||||
uint32_t double_fb: 1; /*!< If this flag is enabled, the driver will allocate two screen sized frame buffer */
|
||||
uint32_t double_fb: 1; /*!< If this flag is enabled, the driver will allocate two screen sized frame buffer, same as num_fbs=2 */
|
||||
uint32_t no_fb: 1; /*!< If this flag is enabled, the driver won't allocate frame buffer.
|
||||
Instead, user should fill in the bounce buffer manually in the `on_bounce_empty` callback */
|
||||
uint32_t bb_invalidate_cache: 1; /*!< If this flag is enabled, in bounce back mode we'll do a cache invalidate on the read data, freeing the cache.
|
||||
|
@ -49,6 +49,10 @@
|
||||
#define LCD_RGB_INTR_ALLOC_FLAGS ESP_INTR_FLAG_INTRDISABLED
|
||||
#endif
|
||||
|
||||
#define RGB_LCD_PANEL_MAX_FB_NUM 3 // maximum supported frame buffer number
|
||||
#define RGB_LCD_PANEL_BOUNCE_BUF_NUM 2 // bounce buffer number
|
||||
#define RGB_LCD_PANEL_DMA_LINKS_REPLICA MAX(RGB_LCD_PANEL_MAX_FB_NUM, RGB_LCD_PANEL_BOUNCE_BUF_NUM)
|
||||
|
||||
#define RGB_PANEL_SWAP_XY 0
|
||||
#define RGB_PANEL_MIRROR_Y 1
|
||||
#define RGB_PANEL_MIRROR_X 2
|
||||
@ -84,6 +88,7 @@ struct esp_rgb_panel_t {
|
||||
lcd_hal_context_t hal; // Hal layer object
|
||||
size_t data_width; // Number of data lines
|
||||
size_t fb_bits_per_pixel; // Frame buffer color depth, in bpp
|
||||
size_t num_fbs; // Number of frame buffers
|
||||
size_t output_bits_per_pixel; // Color depth seen from the output data line. Default to fb_bits_per_pixel, but can be changed by YUV-RGB conversion
|
||||
size_t sram_trans_align; // Alignment for framebuffer that allocated in SRAM
|
||||
size_t psram_trans_align; // Alignment for framebuffer that allocated in PSRAM
|
||||
@ -91,7 +96,7 @@ struct esp_rgb_panel_t {
|
||||
intr_handle_t intr; // LCD peripheral interrupt handle
|
||||
esp_pm_lock_handle_t pm_lock; // Power management lock
|
||||
size_t num_dma_nodes; // Number of DMA descriptors that used to carry the frame buffer
|
||||
uint8_t *fbs[2]; // Frame buffers
|
||||
uint8_t *fbs[RGB_LCD_PANEL_MAX_FB_NUM]; // Frame buffers
|
||||
uint8_t cur_fb_index; // Current frame buffer index (0 or 1)
|
||||
size_t fb_size; // Size of frame buffer
|
||||
int data_gpio_nums[SOC_LCD_RGB_DATA_WIDTH]; // GPIOs used for data lines, we keep these GPIOs for action like "invert_color"
|
||||
@ -99,7 +104,7 @@ struct esp_rgb_panel_t {
|
||||
esp_lcd_rgb_timing_t timings; // RGB timing parameters (e.g. pclk, sync pulse, porch width)
|
||||
size_t bb_size; // If not-zero, the driver uses two bounce buffers allocated from internal memory
|
||||
int bounce_pos_px; // Position in whatever source material is used for the bounce buffer, in pixels
|
||||
uint8_t *bounce_buffer[2]; // Pointer to the bounce buffers
|
||||
uint8_t *bounce_buffer[RGB_LCD_PANEL_BOUNCE_BUF_NUM]; // Pointer to the bounce buffers
|
||||
gdma_channel_handle_t dma_chan; // DMA channel handle
|
||||
esp_lcd_rgb_panel_vsync_cb_t on_vsync; // VSYNC event callback
|
||||
esp_lcd_rgb_panel_bounce_buf_fill_cb_t on_bounce_empty; // callback used to fill a bounce buffer rather than copying from the frame buffer
|
||||
@ -112,13 +117,12 @@ struct esp_rgb_panel_t {
|
||||
struct {
|
||||
uint32_t disp_en_level: 1; // The level which can turn on the screen by `disp_gpio_num`
|
||||
uint32_t stream_mode: 1; // If set, the LCD transfers data continuously, otherwise, it stops refreshing the LCD when transaction done
|
||||
uint32_t no_fb: 1; // No frame buffer allocated in the driver
|
||||
uint32_t fb_in_psram: 1; // Whether the frame buffer is in PSRAM
|
||||
uint32_t need_update_pclk: 1; // Whether to update the PCLK before start a new transaction
|
||||
uint32_t need_restart: 1; // Whether to restart the LCD controller and the DMA
|
||||
uint32_t bb_invalidate_cache: 1; // Whether to do cache invalidation in bounce buffer mode
|
||||
} flags;
|
||||
dma_descriptor_t *dma_links[2]; // fbs[0] <-> dma_links[0], fbs[1] <-> dma_links[1]
|
||||
dma_descriptor_t *dma_links[RGB_LCD_PANEL_DMA_LINKS_REPLICA]; // fbs[0] <-> dma_links[0], fbs[1] <-> dma_links[1], etc
|
||||
dma_descriptor_t dma_restart_node; // DMA descriptor used to restart the transfer
|
||||
dma_descriptor_t dma_nodes[]; // DMA descriptors pool
|
||||
};
|
||||
@ -132,7 +136,7 @@ static esp_err_t lcd_rgb_panel_alloc_frame_buffers(const esp_lcd_rgb_panel_confi
|
||||
rgb_panel->sram_trans_align = sram_trans_align;
|
||||
|
||||
// alloc frame buffer
|
||||
if (!rgb_panel_config->flags.no_fb) {
|
||||
if (rgb_panel->num_fbs > 0) {
|
||||
// fb_in_psram is only an option, if there's no PSRAM on board, we fallback to alloc from SRAM
|
||||
if (rgb_panel_config->flags.fb_in_psram) {
|
||||
#if CONFIG_SPIRAM_USE_MALLOC || CONFIG_SPIRAM_USE_CAPS_ALLOC
|
||||
@ -141,7 +145,7 @@ static esp_err_t lcd_rgb_panel_alloc_frame_buffers(const esp_lcd_rgb_panel_confi
|
||||
}
|
||||
#endif
|
||||
}
|
||||
for (int i = 0; i < (rgb_panel_config->flags.double_fb ? 2 : 1); i++) {
|
||||
for (int i = 0; i < rgb_panel->num_fbs; i++) {
|
||||
if (fb_in_psram) {
|
||||
// the low level malloc function will help check the validation of alignment
|
||||
rgb_panel->fbs[i] = heap_caps_aligned_calloc(psram_trans_align, 1, rgb_panel->fb_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
@ -154,7 +158,7 @@ static esp_err_t lcd_rgb_panel_alloc_frame_buffers(const esp_lcd_rgb_panel_confi
|
||||
|
||||
// alloc bounce buffer
|
||||
if (rgb_panel->bb_size) {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int i = 0; i < RGB_LCD_PANEL_BOUNCE_BUF_NUM; i++) {
|
||||
// bounce buffer must come from SRAM
|
||||
rgb_panel->bounce_buffer[i] = heap_caps_aligned_calloc(sram_trans_align, 1, rgb_panel->bb_size, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA);
|
||||
ESP_RETURN_ON_FALSE(rgb_panel->bounce_buffer[i], ESP_ERR_NO_MEM, TAG, "no mem for bounce buffer");
|
||||
@ -173,11 +177,10 @@ static esp_err_t lcd_rgb_panel_destory(esp_rgb_panel_t *rgb_panel)
|
||||
periph_module_disable(lcd_periph_signals.panels[rgb_panel->panel_id].module);
|
||||
lcd_com_remove_device(LCD_COM_DEVICE_TYPE_RGB, rgb_panel->panel_id);
|
||||
}
|
||||
if (rgb_panel->fbs[0]) {
|
||||
free(rgb_panel->fbs[0]);
|
||||
}
|
||||
if (rgb_panel->fbs[1]) {
|
||||
free(rgb_panel->fbs[1]);
|
||||
for (size_t i = 0; i < rgb_panel->num_fbs; i++) {
|
||||
if (rgb_panel->fbs[i]) {
|
||||
free(rgb_panel->fbs[i]);
|
||||
}
|
||||
}
|
||||
if (rgb_panel->bounce_buffer[0]) {
|
||||
free(rgb_panel->bounce_buffer[0]);
|
||||
@ -211,7 +214,11 @@ 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->data_width == 16 || rgb_panel_config->data_width == 8,
|
||||
ESP_ERR_NOT_SUPPORTED, err, TAG, "unsupported data width %d", rgb_panel_config->data_width);
|
||||
ESP_GOTO_ON_FALSE(!(rgb_panel_config->flags.double_fb && rgb_panel_config->flags.no_fb),
|
||||
ESP_ERR_INVALID_ARG, err, TAG, "invalid frame buffer number");
|
||||
ESP_ERR_INVALID_ARG, err, TAG, "double_fb conflicts with no_fb");
|
||||
ESP_GOTO_ON_FALSE(!(rgb_panel_config->num_fbs > 0 && rgb_panel_config->num_fbs != 2 && rgb_panel_config->flags.double_fb),
|
||||
ESP_ERR_INVALID_ARG, err, TAG, "num_fbs conflicts with double_fb");
|
||||
ESP_GOTO_ON_FALSE(!(rgb_panel_config->num_fbs > 0 && rgb_panel_config->flags.no_fb),
|
||||
ESP_ERR_INVALID_ARG, err, TAG, "num_fbs conflicts with no_fb");
|
||||
ESP_GOTO_ON_FALSE(!(rgb_panel_config->flags.no_fb && rgb_panel_config->bounce_buffer_size_px == 0),
|
||||
ESP_ERR_INVALID_ARG, err, TAG, "must set bounce buffer if there's no frame buffer");
|
||||
ESP_GOTO_ON_FALSE(!(rgb_panel_config->flags.refresh_on_demand && rgb_panel_config->bounce_buffer_size_px),
|
||||
@ -221,7 +228,19 @@ esp_err_t esp_lcd_new_rgb_panel(const esp_lcd_rgb_panel_config_t *rgb_panel_conf
|
||||
ESP_ERR_INVALID_ARG, err, TAG, "bounce buffer mode is not IRAM Safe");
|
||||
#endif
|
||||
|
||||
// determine number of framebuffers
|
||||
size_t num_fbs = 1;
|
||||
if (rgb_panel_config->flags.no_fb) {
|
||||
num_fbs = 0;
|
||||
} else if (rgb_panel_config->flags.double_fb) {
|
||||
num_fbs = 2;
|
||||
} else if (rgb_panel_config->num_fbs > 0) {
|
||||
num_fbs = rgb_panel_config->num_fbs;
|
||||
}
|
||||
ESP_GOTO_ON_FALSE(num_fbs <= RGB_LCD_PANEL_MAX_FB_NUM, ESP_ERR_INVALID_ARG, err, TAG, "too many frame buffers");
|
||||
|
||||
// bpp defaults to the number of data lines, but for serial RGB interface, they're not equal
|
||||
// e.g. for serial RGB 8-bit interface, data lines are 8, whereas the bpp is 24 (RGB888)
|
||||
size_t fb_bits_per_pixel = rgb_panel_config->data_width;
|
||||
if (rgb_panel_config->bits_per_pixel) { // override bpp if it's set
|
||||
fb_bits_per_pixel = rgb_panel_config->bits_per_pixel;
|
||||
@ -247,11 +266,11 @@ esp_err_t esp_lcd_new_rgb_panel(const esp_lcd_rgb_panel_config_t *rgb_panel_conf
|
||||
}
|
||||
|
||||
// DMA descriptors must be placed in internal SRAM (requested by DMA)
|
||||
// multiply 2 because of double frame buffer mode (two frame buffer) and bounce buffer mode (two bounce buffer)
|
||||
rgb_panel = heap_caps_calloc(1, sizeof(esp_rgb_panel_t) + num_dma_nodes * sizeof(dma_descriptor_t) * 2,
|
||||
rgb_panel = heap_caps_calloc(1, sizeof(esp_rgb_panel_t) + num_dma_nodes * sizeof(dma_descriptor_t) * RGB_LCD_PANEL_DMA_LINKS_REPLICA,
|
||||
MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
|
||||
ESP_GOTO_ON_FALSE(rgb_panel, ESP_ERR_NO_MEM, err, TAG, "no mem for rgb panel");
|
||||
rgb_panel->num_dma_nodes = num_dma_nodes;
|
||||
rgb_panel->num_fbs = num_fbs;
|
||||
rgb_panel->fb_size = fb_size;
|
||||
rgb_panel->bb_size = bb_size;
|
||||
rgb_panel->panel_id = -1;
|
||||
@ -303,7 +322,6 @@ esp_err_t esp_lcd_new_rgb_panel(const esp_lcd_rgb_panel_config_t *rgb_panel_conf
|
||||
rgb_panel->output_bits_per_pixel = fb_bits_per_pixel; // by default, the output bpp is the same as the frame buffer bpp
|
||||
rgb_panel->disp_gpio_num = rgb_panel_config->disp_gpio_num;
|
||||
rgb_panel->flags.disp_en_level = !rgb_panel_config->flags.disp_active_low;
|
||||
rgb_panel->flags.no_fb = rgb_panel_config->flags.no_fb;
|
||||
rgb_panel->flags.bb_invalidate_cache = rgb_panel_config->flags.bb_invalidate_cache;
|
||||
rgb_panel->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
||||
// fill function table
|
||||
@ -318,9 +336,12 @@ esp_err_t esp_lcd_new_rgb_panel(const esp_lcd_rgb_panel_config_t *rgb_panel_conf
|
||||
rgb_panel->base.set_gap = rgb_panel_set_gap;
|
||||
// return base class
|
||||
*ret_panel = &(rgb_panel->base);
|
||||
ESP_LOGD(TAG, "new rgb panel(%d) @%p, fb0 @%p, fb1 @%p, fb_size=%zu, bb0 @%p, bb1 @%p, bb_size=%zu",
|
||||
rgb_panel->panel_id, rgb_panel, rgb_panel->fbs[0], rgb_panel->fbs[1], rgb_panel->fb_size,
|
||||
ESP_LOGD(TAG, "new rgb panel(%d) @%p, num_fbs=%zu, fb_size=%zu, bb0 @%p, bb1 @%p, bb_size=%zu",
|
||||
rgb_panel->panel_id, rgb_panel, rgb_panel->num_fbs, rgb_panel->fb_size,
|
||||
rgb_panel->bounce_buffer[0], rgb_panel->bounce_buffer[1], rgb_panel->bb_size);
|
||||
for (size_t i = 0; i < rgb_panel->num_fbs; i++) {
|
||||
ESP_LOGD(TAG, "fb[%zu] @%p", i, rgb_panel->fbs[i]);
|
||||
}
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
@ -379,8 +400,8 @@ esp_err_t esp_lcd_rgb_panel_restart(esp_lcd_panel_handle_t panel)
|
||||
esp_err_t esp_lcd_rgb_panel_get_frame_buffer(esp_lcd_panel_handle_t panel, uint32_t fb_num, void **fb0, ...)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(panel, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
ESP_RETURN_ON_FALSE(fb_num && fb_num <= 2, ESP_ERR_INVALID_ARG, TAG, "invalid frame buffer number");
|
||||
esp_rgb_panel_t *rgb_panel = __containerof(panel, esp_rgb_panel_t, base);
|
||||
ESP_RETURN_ON_FALSE(fb_num && fb_num <= rgb_panel->num_fbs, ESP_ERR_INVALID_ARG, TAG, "invalid frame buffer number");
|
||||
void **fb_itor = fb0;
|
||||
va_list args;
|
||||
va_start(args, fb0);
|
||||
@ -533,7 +554,7 @@ static inline void copy_pixel_24bpp(uint8_t *to, const uint8_t *from)
|
||||
static esp_err_t rgb_panel_draw_bitmap(esp_lcd_panel_t *panel, int x_start, int y_start, int x_end, int y_end, const void *color_data)
|
||||
{
|
||||
esp_rgb_panel_t *rgb_panel = __containerof(panel, esp_rgb_panel_t, base);
|
||||
ESP_RETURN_ON_FALSE(!rgb_panel->flags.no_fb, ESP_ERR_NOT_SUPPORTED, TAG, "no frame buffer installed");
|
||||
ESP_RETURN_ON_FALSE(rgb_panel->num_fbs > 0, ESP_ERR_NOT_SUPPORTED, TAG, "no frame buffer installed");
|
||||
assert((x_start < x_end) && (y_start < y_end) && "start position must be smaller than end position");
|
||||
|
||||
// check if we need to copy the draw buffer (pointed by the color_data) to the driver's frame buffer
|
||||
@ -542,6 +563,8 @@ static esp_err_t rgb_panel_draw_bitmap(esp_lcd_panel_t *panel, int x_start, int
|
||||
rgb_panel->cur_fb_index = 0;
|
||||
} else if (color_data == rgb_panel->fbs[1]) {
|
||||
rgb_panel->cur_fb_index = 1;
|
||||
} else if (color_data == rgb_panel->fbs[2]) {
|
||||
rgb_panel->cur_fb_index = 2;
|
||||
} else {
|
||||
// we do the copy only if the color_data is different from either frame buffer
|
||||
do_copy = true;
|
||||
@ -783,8 +806,9 @@ static esp_err_t rgb_panel_draw_bitmap(esp_lcd_panel_t *panel, int x_start, int
|
||||
if (!rgb_panel->bb_size) {
|
||||
if (rgb_panel->flags.stream_mode) {
|
||||
// the DMA will convey the new frame buffer next time
|
||||
rgb_panel->dma_nodes[rgb_panel->num_dma_nodes - 1].next = rgb_panel->dma_links[rgb_panel->cur_fb_index];
|
||||
rgb_panel->dma_nodes[rgb_panel->num_dma_nodes * 2 - 1].next = rgb_panel->dma_links[rgb_panel->cur_fb_index];
|
||||
for (int i = 0; i < RGB_LCD_PANEL_DMA_LINKS_REPLICA; i++) {
|
||||
rgb_panel->dma_nodes[rgb_panel->num_dma_nodes * (i + 1) - 1].next = rgb_panel->dma_links[rgb_panel->cur_fb_index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -930,7 +954,7 @@ static IRAM_ATTR bool lcd_rgb_panel_fill_bounce_buffer(esp_rgb_panel_t *panel, u
|
||||
{
|
||||
bool need_yield = false;
|
||||
int bytes_per_pixel = panel->fb_bits_per_pixel / 8;
|
||||
if (panel->flags.no_fb) {
|
||||
if (panel->num_fbs == 0) {
|
||||
if (panel->on_bounce_empty) {
|
||||
// We don't have a frame buffer here; we need to call a callback to refill the bounce buffer
|
||||
need_yield = panel->on_bounce_empty(&panel->base, buffer, panel->bounce_pos_px, panel->bb_size, panel->user_ctx);
|
||||
@ -954,7 +978,7 @@ static IRAM_ATTR bool lcd_rgb_panel_fill_bounce_buffer(esp_rgb_panel_t *panel, u
|
||||
if (panel->bounce_pos_px >= panel->fb_size / bytes_per_pixel) {
|
||||
panel->bounce_pos_px = 0;
|
||||
}
|
||||
if (!panel->flags.no_fb) {
|
||||
if (panel->num_fbs > 0) {
|
||||
// Preload the next bit of buffer from psram
|
||||
Cache_Start_DCache_Preload((uint32_t)&panel->fbs[panel->cur_fb_index][panel->bounce_pos_px * bytes_per_pixel],
|
||||
panel->bb_size, 0);
|
||||
@ -979,34 +1003,36 @@ static IRAM_ATTR bool lcd_rgb_panel_eof_handler(gdma_channel_handle_t dma_chan,
|
||||
|
||||
static esp_err_t lcd_rgb_panel_create_trans_link(esp_rgb_panel_t *panel)
|
||||
{
|
||||
panel->dma_links[0] = &panel->dma_nodes[0];
|
||||
panel->dma_links[1] = &panel->dma_nodes[panel->num_dma_nodes];
|
||||
for (int i = 0; i < RGB_LCD_PANEL_DMA_LINKS_REPLICA; i++) {
|
||||
panel->dma_links[i] = &panel->dma_nodes[panel->num_dma_nodes * i];
|
||||
}
|
||||
// chain DMA descriptors
|
||||
for (int i = 0; i < panel->num_dma_nodes * 2; i++) {
|
||||
for (int i = 0; i < panel->num_dma_nodes * RGB_LCD_PANEL_DMA_LINKS_REPLICA; i++) {
|
||||
panel->dma_nodes[i].dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_CPU;
|
||||
panel->dma_nodes[i].next = &panel->dma_nodes[i + 1];
|
||||
}
|
||||
|
||||
if (panel->bb_size) {
|
||||
// loop end back to start
|
||||
panel->dma_nodes[panel->num_dma_nodes * 2 - 1].next = &panel->dma_nodes[0];
|
||||
panel->dma_nodes[panel->num_dma_nodes * RGB_LCD_PANEL_BOUNCE_BUF_NUM - 1].next = &panel->dma_nodes[0];
|
||||
// mount the bounce buffers to the DMA descriptors
|
||||
lcd_com_mount_dma_data(panel->dma_links[0], panel->bounce_buffer[0], panel->bb_size);
|
||||
lcd_com_mount_dma_data(panel->dma_links[1], panel->bounce_buffer[1], panel->bb_size);
|
||||
} else {
|
||||
if (panel->flags.stream_mode) {
|
||||
// circle DMA descriptors chain for each frame buffer
|
||||
panel->dma_nodes[panel->num_dma_nodes - 1].next = &panel->dma_nodes[0];
|
||||
panel->dma_nodes[panel->num_dma_nodes * 2 - 1].next = &panel->dma_nodes[panel->num_dma_nodes];
|
||||
for (int i = 0; i < RGB_LCD_PANEL_DMA_LINKS_REPLICA; i++) {
|
||||
panel->dma_nodes[panel->num_dma_nodes * (i + 1) - 1].next = &panel->dma_nodes[panel->num_dma_nodes * i];
|
||||
}
|
||||
} else {
|
||||
// one-off DMA descriptors chain
|
||||
panel->dma_nodes[panel->num_dma_nodes - 1].next = NULL;
|
||||
panel->dma_nodes[panel->num_dma_nodes * 2 - 1].next = NULL;
|
||||
for (int i = 0; i < RGB_LCD_PANEL_DMA_LINKS_REPLICA; i++) {
|
||||
panel->dma_nodes[panel->num_dma_nodes * (i + 1) - 1].next = NULL;
|
||||
}
|
||||
}
|
||||
// mount the frame buffer to the DMA descriptors
|
||||
lcd_com_mount_dma_data(panel->dma_links[0], panel->fbs[0], panel->fb_size);
|
||||
if (panel->fbs[1]) {
|
||||
lcd_com_mount_dma_data(panel->dma_links[1], panel->fbs[1], panel->fb_size);
|
||||
for (size_t i = 0; i < panel->num_fbs; i++) {
|
||||
lcd_com_mount_dma_data(panel->dma_links[i], panel->fbs[i], panel->fb_size);
|
||||
}
|
||||
}
|
||||
|
@ -52,6 +52,12 @@ static const char *TAG = "example";
|
||||
#define EXAMPLE_LCD_H_RES 800
|
||||
#define EXAMPLE_LCD_V_RES 480
|
||||
|
||||
#if CONFIG_EXAMPLE_DOUBLE_FB
|
||||
#define EXAMPLE_LCD_NUM_FB 2
|
||||
#else
|
||||
#define EXAMPLE_LCD_NUM_FB 1
|
||||
#endif // CONFIG_EXAMPLE_DOUBLE_FB
|
||||
|
||||
#define EXAMPLE_LVGL_TICK_PERIOD_MS 2
|
||||
|
||||
// we use two semaphores to sync the VSYNC event and the LVGL task, to avoid potential tearing effect
|
||||
@ -122,6 +128,7 @@ void app_main(void)
|
||||
esp_lcd_rgb_panel_config_t panel_config = {
|
||||
.data_width = 16, // RGB565 in parallel mode, thus 16bit in width
|
||||
.psram_trans_align = 64,
|
||||
.num_fbs = EXAMPLE_LCD_NUM_FB,
|
||||
#if CONFIG_EXAMPLE_USE_BOUNCE_BUFFER
|
||||
.bounce_buffer_size_px = 10 * EXAMPLE_LCD_H_RES,
|
||||
#endif
|
||||
@ -163,9 +170,6 @@ void app_main(void)
|
||||
.flags.pclk_active_neg = true,
|
||||
},
|
||||
.flags.fb_in_psram = true, // allocate frame buffer in PSRAM
|
||||
#if CONFIG_EXAMPLE_DOUBLE_FB
|
||||
.flags.double_fb = true, // allocate double frame buffer
|
||||
#endif // CONFIG_EXAMPLE_DOUBLE_FB
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_lcd_new_rgb_panel(&panel_config, &panel_handle));
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include "driver/gpio.h"
|
||||
#include "pretty_effect.h"
|
||||
|
||||
// Using SPI2 in the example, as it aslo supports octal modes on some targets
|
||||
// Using SPI2 in the example, as it also supports octal modes on some targets
|
||||
#define LCD_HOST SPI2_HOST
|
||||
// To speed up transfers, every SPI transfer sends a bunch of lines. This define specifies how many.
|
||||
// More means more memory use, but less overhead for setting up / finishing transfers. Make sure 240
|
||||
@ -31,7 +31,7 @@
|
||||
#define EXAMPLE_LCD_PIXEL_CLOCK_HZ (20 * 1000 * 1000)
|
||||
#define EXAMPLE_LCD_BK_LIGHT_ON_LEVEL 0
|
||||
#define EXAMPLE_LCD_BK_LIGHT_OFF_LEVEL !EXAMPLE_LCD_BK_LIGHT_ON_LEVEL
|
||||
#define EXAMPLE_PIN_NUM_DATA0 23 /*!< for 1-line SPI, this also refered as MOSI */
|
||||
#define EXAMPLE_PIN_NUM_DATA0 23 /*!< for 1-line SPI, this also refereed as MOSI */
|
||||
#define EXAMPLE_PIN_NUM_PCLK 19
|
||||
#define EXAMPLE_PIN_NUM_CS 22
|
||||
#define EXAMPLE_PIN_NUM_DC 21
|
||||
|
Loading…
Reference in New Issue
Block a user