9#if defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3)
11#include "esp_idf_version.h"
13#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 1, 0)
22#include "freertos/FreeRTOS.h"
23#include "freertos/task.h"
24#include "freertos/semphr.h"
28#include "esp_lcd_panel_interface.h"
29#include "esp_lcd_panel_ops.h"
30#include "esp_rom_gpio.h"
31#include "soc/soc_caps.h"
33#include "hal/dma_types.h"
34#include "hal/gpio_hal.h"
35#include "esp_private/gdma.h"
36#include "driver/gpio.h"
37#include "driver/periph_ctrl.h"
41#if SOC_LCDCAM_SUPPORTED
43#include "soc/lcd_periph.h"
44#include "hal/lcd_hal.h"
45#include "hal/lcd_ll.h"
47#if CONFIG_LCD_RGB_ISR_IRAM_SAFE
48#define LCD_RGB_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_INTRDISABLED)
50#define LCD_RGB_INTR_ALLOC_FLAGS ESP_INTR_FLAG_INTRDISABLED
53static const char *TAG =
"lcd_panel.rgb";
55typedef struct esp_rgb_panel_t esp_rgb_panel_t;
58extern int Cache_WriteBack_Addr(uint32_t addr, uint32_t size);
60static esp_err_t rgb_panel_del(esp_lcd_panel_t *panel);
61static esp_err_t rgb_panel_reset(esp_lcd_panel_t *panel);
62static esp_err_t rgb_panel_init(esp_lcd_panel_t *panel);
63static 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);
64static esp_err_t rgb_panel_invert_color(esp_lcd_panel_t *panel,
bool invert_color_data);
65static esp_err_t rgb_panel_mirror(esp_lcd_panel_t *panel,
bool mirror_x,
bool mirror_y);
66static esp_err_t rgb_panel_swap_xy(esp_lcd_panel_t *panel,
bool swap_axes);
67static esp_err_t rgb_panel_set_gap(esp_lcd_panel_t *panel,
int x_gap,
int y_gap);
68static esp_err_t rgb_panel_disp_off(esp_lcd_panel_t *panel,
bool off);
69static esp_err_t lcd_rgb_panel_select_clock_src(esp_rgb_panel_t *panel, lcd_clock_source_t clk_src);
70static esp_err_t lcd_rgb_panel_create_trans_link(esp_rgb_panel_t *panel);
71static esp_err_t lcd_rgb_panel_configure_gpio(esp_rgb_panel_t *panel,
const esp_lcd_rgb_panel_config_t *panel_config);
72static void lcd_rgb_panel_start_transmission(esp_rgb_panel_t *rgb_panel);
73static void lcd_default_isr_handler(
void *args);
75struct esp_rgb_panel_t {
78 lcd_hal_context_t hal;
80 size_t sram_trans_align;
81 size_t psram_trans_align;
84 esp_pm_lock_handle_t pm_lock;
88 int data_gpio_nums[SOC_LCD_RGB_DATA_WIDTH];
90 esp_lcd_rgb_timing_t timings;
91 gdma_channel_handle_t dma_chan;
92 esp_lcd_rgb_panel_frame_trans_done_cb_t on_frame_trans_done;
98 unsigned int disp_en_level: 1;
99 unsigned int stream_mode: 1;
100 unsigned int fb_in_psram: 1;
102 dma_descriptor_t dma_nodes[];
105esp_err_t esp_lcd_new_rgb_panel(
const esp_lcd_rgb_panel_config_t *rgb_panel_config, esp_lcd_panel_handle_t *ret_panel)
107 esp_err_t ret = ESP_OK;
108 esp_rgb_panel_t *rgb_panel = NULL;
109 ESP_GOTO_ON_FALSE(rgb_panel_config && ret_panel, ESP_ERR_INVALID_ARG, err, TAG,
"invalid parameter");
110 ESP_GOTO_ON_FALSE(rgb_panel_config->data_width == 16, ESP_ERR_NOT_SUPPORTED, err, TAG,
111 "unsupported data width %d", rgb_panel_config->data_width);
113#if CONFIG_LCD_RGB_ISR_IRAM_SAFE
114 if (rgb_panel_config->on_frame_trans_done) {
115 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");
117 if (rgb_panel_config->user_ctx) {
118 ESP_RETURN_ON_FALSE(esp_ptr_internal(rgb_panel_config->user_ctx), ESP_ERR_INVALID_ARG, TAG,
"user context not in internal RAM");
123 size_t fb_size = rgb_panel_config->timings.h_res * rgb_panel_config->timings.v_res * rgb_panel_config->data_width / 8;
124 size_t num_dma_nodes = fb_size / DMA_DESCRIPTOR_BUFFER_MAX_SIZE;
125 if (fb_size > num_dma_nodes * DMA_DESCRIPTOR_BUFFER_MAX_SIZE) {
129 rgb_panel = heap_caps_calloc(1,
sizeof(esp_rgb_panel_t) + num_dma_nodes *
sizeof(dma_descriptor_t), MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
130 ESP_GOTO_ON_FALSE(rgb_panel, ESP_ERR_NO_MEM, err, TAG,
"no mem for rgb panel");
131 rgb_panel->num_dma_nodes = num_dma_nodes;
132 rgb_panel->panel_id = -1;
134 int panel_id = lcd_com_register_device(LCD_COM_DEVICE_TYPE_RGB, rgb_panel);
135 ESP_GOTO_ON_FALSE(panel_id >= 0, ESP_ERR_NOT_FOUND, err, TAG,
"no free rgb panel slot");
136 rgb_panel->panel_id = panel_id;
138 periph_module_enable(lcd_periph_signals.panels[panel_id].module);
139 periph_module_reset(lcd_periph_signals.panels[panel_id].module);
141 bool alloc_from_psram =
false;
143 if (rgb_panel_config->flags.fb_in_psram) {
144#if CONFIG_SPIRAM_USE_MALLOC || CONFIG_SPIRAM_USE_CAPS_ALLOC
145 if (esp_spiram_is_initialized()) {
146 alloc_from_psram =
true;
150 size_t psram_trans_align = rgb_panel_config->psram_trans_align ? rgb_panel_config->psram_trans_align : 64;
151 size_t sram_trans_align = rgb_panel_config->sram_trans_align ? rgb_panel_config->sram_trans_align : 4;
152 if (alloc_from_psram) {
154 rgb_panel->fb = heap_caps_aligned_calloc(psram_trans_align, 1, fb_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
156 rgb_panel->fb = heap_caps_aligned_calloc(sram_trans_align, 1, fb_size, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA);
158 ESP_GOTO_ON_FALSE(rgb_panel->fb, ESP_ERR_NO_MEM, err, TAG,
"no mem for frame buffer");
159 rgb_panel->psram_trans_align = psram_trans_align;
160 rgb_panel->sram_trans_align = sram_trans_align;
161 rgb_panel->fb_size = fb_size;
162 rgb_panel->flags.fb_in_psram = alloc_from_psram;
164 lcd_hal_init(&rgb_panel->hal, panel_id);
166 lcd_ll_enable_clock(rgb_panel->hal.dev,
true);
168 ret = lcd_rgb_panel_select_clock_src(rgb_panel, rgb_panel_config->clk_src);
169 ESP_GOTO_ON_ERROR(ret, err, TAG,
"set source clock failed");
172 if (!(rgb_panel_config->timings.flags.pclk_active_neg || rgb_panel_config->timings.flags.pclk_idle_high)) {
173 rgb_panel->lcd_clk_flags |= LCD_HAL_PCLK_FLAG_ALLOW_EQUAL_SYSCLK;
176 int isr_flags = LCD_RGB_INTR_ALLOC_FLAGS | ESP_INTR_FLAG_SHARED;
177 ret = esp_intr_alloc_intrstatus(lcd_periph_signals.panels[panel_id].irq_id, isr_flags,
178 (uint32_t)lcd_ll_get_interrupt_status_reg(rgb_panel->hal.dev),
179 LCD_LL_EVENT_VSYNC_END, lcd_default_isr_handler, rgb_panel, &rgb_panel->intr);
180 ESP_GOTO_ON_ERROR(ret, err, TAG,
"install interrupt failed");
181 lcd_ll_enable_interrupt(rgb_panel->hal.dev, LCD_LL_EVENT_VSYNC_END,
false);
182 lcd_ll_clear_interrupt_status(rgb_panel->hal.dev, UINT32_MAX);
184 rgb_panel->flags.stream_mode = !rgb_panel_config->flags.relax_on_idle;
185 ret = lcd_rgb_panel_create_trans_link(rgb_panel);
186 ESP_GOTO_ON_ERROR(ret, err, TAG,
"install DMA failed");
188 ret = lcd_rgb_panel_configure_gpio(rgb_panel, rgb_panel_config);
189 ESP_GOTO_ON_ERROR(ret, err, TAG,
"configure GPIO failed");
191 memcpy(rgb_panel->data_gpio_nums, rgb_panel_config->data_gpio_nums, SOC_LCD_RGB_DATA_WIDTH);
192 rgb_panel->timings = rgb_panel_config->timings;
193 rgb_panel->data_width = rgb_panel_config->data_width;
194 rgb_panel->disp_gpio_num = rgb_panel_config->disp_gpio_num;
195 rgb_panel->flags.disp_en_level = !rgb_panel_config->flags.disp_active_low;
196 rgb_panel->on_frame_trans_done = rgb_panel_config->on_frame_trans_done;
197 rgb_panel->user_ctx = rgb_panel_config->user_ctx;
199 rgb_panel->base.del = rgb_panel_del;
200 rgb_panel->base.reset = rgb_panel_reset;
201 rgb_panel->base.init = rgb_panel_init;
202 rgb_panel->base.draw_bitmap = rgb_panel_draw_bitmap;
203 rgb_panel->base.disp_off = rgb_panel_disp_off;
204 rgb_panel->base.invert_color = rgb_panel_invert_color;
205 rgb_panel->base.mirror = rgb_panel_mirror;
206 rgb_panel->base.swap_xy = rgb_panel_swap_xy;
207 rgb_panel->base.set_gap = rgb_panel_set_gap;
209 *ret_panel = &(rgb_panel->base);
210 ESP_LOGD(TAG,
"new rgb panel(%d) @%p, fb @%p, size=%zu", rgb_panel->panel_id, rgb_panel, rgb_panel->fb, rgb_panel->fb_size);
215 if (rgb_panel->panel_id >= 0) {
216 periph_module_disable(lcd_periph_signals.panels[rgb_panel->panel_id].module);
217 lcd_com_remove_device(LCD_COM_DEVICE_TYPE_RGB, rgb_panel->panel_id);
222 if (rgb_panel->dma_chan) {
223 gdma_disconnect(rgb_panel->dma_chan);
224 gdma_del_channel(rgb_panel->dma_chan);
226 if (rgb_panel->intr) {
227 esp_intr_free(rgb_panel->intr);
229 if (rgb_panel->pm_lock) {
230 esp_pm_lock_release(rgb_panel->pm_lock);
231 esp_pm_lock_delete(rgb_panel->pm_lock);
238static esp_err_t rgb_panel_del(esp_lcd_panel_t *panel)
240 esp_rgb_panel_t *rgb_panel = __containerof(panel, esp_rgb_panel_t, base);
241 int panel_id = rgb_panel->panel_id;
242 gdma_disconnect(rgb_panel->dma_chan);
243 gdma_del_channel(rgb_panel->dma_chan);
244 esp_intr_free(rgb_panel->intr);
245 lcd_ll_enable_clock(rgb_panel->hal.dev,
false);
246 periph_module_disable(lcd_periph_signals.panels[panel_id].module);
247 lcd_com_remove_device(LCD_COM_DEVICE_TYPE_RGB, rgb_panel->panel_id);
249 if (rgb_panel->pm_lock) {
250 esp_pm_lock_release(rgb_panel->pm_lock);
251 esp_pm_lock_delete(rgb_panel->pm_lock);
254 ESP_LOGD(TAG,
"del rgb panel(%d)", panel_id);
258static esp_err_t rgb_panel_reset(esp_lcd_panel_t *panel)
260 esp_rgb_panel_t *rgb_panel = __containerof(panel, esp_rgb_panel_t, base);
261 lcd_ll_fifo_reset(rgb_panel->hal.dev);
262 lcd_ll_reset(rgb_panel->hal.dev);
266static esp_err_t rgb_panel_init(esp_lcd_panel_t *panel)
268 esp_err_t ret = ESP_OK;
269 esp_rgb_panel_t *rgb_panel = __containerof(panel, esp_rgb_panel_t, base);
271 rgb_panel->timings.pclk_hz = lcd_hal_cal_pclk_freq(&rgb_panel->hal, rgb_panel->src_clk_hz, rgb_panel->timings.pclk_hz, rgb_panel->lcd_clk_flags);
273 lcd_ll_set_clock_idle_level(rgb_panel->hal.dev, rgb_panel->timings.flags.pclk_idle_high);
274 lcd_ll_set_pixel_clock_edge(rgb_panel->hal.dev, rgb_panel->timings.flags.pclk_active_neg);
276 lcd_ll_enable_rgb_mode(rgb_panel->hal.dev,
true);
277 lcd_ll_set_data_width(rgb_panel->hal.dev, rgb_panel->data_width);
278 lcd_ll_set_phase_cycles(rgb_panel->hal.dev, 0, 0, 1);
280 lcd_ll_enable_output_always_on(rgb_panel->hal.dev,
true);
282 lcd_ll_set_idle_level(rgb_panel->hal.dev, !rgb_panel->timings.flags.hsync_idle_low,
283 !rgb_panel->timings.flags.vsync_idle_low, rgb_panel->timings.flags.de_idle_high);
285 lcd_ll_set_blank_cycles(rgb_panel->hal.dev, 1, 1);
286 lcd_ll_set_horizontal_timing(rgb_panel->hal.dev, rgb_panel->timings.hsync_pulse_width,
287 rgb_panel->timings.hsync_back_porch, rgb_panel->timings.h_res,
288 rgb_panel->timings.hsync_front_porch);
289 lcd_ll_set_vertical_timing(rgb_panel->hal.dev, rgb_panel->timings.vsync_pulse_width,
290 rgb_panel->timings.vsync_back_porch, rgb_panel->timings.v_res,
291 rgb_panel->timings.vsync_front_porch);
293 lcd_ll_enable_output_hsync_in_porch_region(rgb_panel->hal.dev,
true);
295 lcd_ll_set_hsync_position(rgb_panel->hal.dev, 0);
297 lcd_ll_enable_auto_next_frame(rgb_panel->hal.dev,
false);
299 lcd_ll_enable_interrupt(rgb_panel->hal.dev, LCD_LL_EVENT_VSYNC_END,
true);
301 esp_intr_enable(rgb_panel->intr);
303 if (rgb_panel->flags.stream_mode) {
304 lcd_rgb_panel_start_transmission(rgb_panel);
306 ESP_LOGD(TAG,
"rgb panel(%d) start, pclk=%uHz", rgb_panel->panel_id, rgb_panel->timings.pclk_hz);
310static 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)
312 esp_rgb_panel_t *rgb_panel = __containerof(panel, esp_rgb_panel_t, base);
313 assert((x_start < x_end) && (y_start < y_end) &&
"start position must be smaller than end position");
315 x_start += rgb_panel->x_gap;
316 y_start += rgb_panel->y_gap;
317 x_end += rgb_panel->x_gap;
318 y_end += rgb_panel->y_gap;
320 x_start = MIN(x_start, rgb_panel->timings.h_res);
321 x_end = MIN(x_end, rgb_panel->timings.h_res);
322 y_start = MIN(y_start, rgb_panel->timings.v_res);
323 y_end = MIN(y_end, rgb_panel->timings.v_res);
326 int bytes_per_pixel = rgb_panel->data_width / 8;
327 int pixels_per_line = rgb_panel->timings.h_res;
328 uint32_t bytes_per_line = bytes_per_pixel * pixels_per_line;
329 const uint8_t *from = (
const uint8_t *)color_data;
331 uint32_t copy_bytes_per_line = (x_end - x_start) * bytes_per_pixel;
332 uint8_t *to = rgb_panel->fb + (y_start * pixels_per_line + x_start) * bytes_per_pixel;
333 for (
int y = y_start; y < y_end; y++) {
334 memcpy(to, from, copy_bytes_per_line);
335 to += bytes_per_line;
336 from += copy_bytes_per_line;
339 if (rgb_panel->flags.fb_in_psram) {
341 uint32_t bytes_to_flush = (y_end - y_start) * bytes_per_line;
342 Cache_WriteBack_Addr((uint32_t)(rgb_panel->fb + y_start * bytes_per_line), bytes_to_flush);
346 if (!rgb_panel->flags.stream_mode) {
347 lcd_rgb_panel_start_transmission(rgb_panel);
353static esp_err_t rgb_panel_invert_color(esp_lcd_panel_t *panel,
bool invert_color_data)
355 esp_rgb_panel_t *rgb_panel = __containerof(panel, esp_rgb_panel_t, base);
356 int panel_id = rgb_panel->panel_id;
358 for (
int i = 0; i < rgb_panel->data_width; i++) {
359 esp_rom_gpio_connect_out_signal(rgb_panel->data_gpio_nums[i], lcd_periph_signals.panels[panel_id].data_sigs[i],
360 invert_color_data,
false);
365static esp_err_t rgb_panel_mirror(esp_lcd_panel_t *panel,
bool mirror_x,
bool mirror_y)
367 return ESP_ERR_NOT_SUPPORTED;
370static esp_err_t rgb_panel_swap_xy(esp_lcd_panel_t *panel,
bool swap_axes)
372 return ESP_ERR_NOT_SUPPORTED;
375static esp_err_t rgb_panel_set_gap(esp_lcd_panel_t *panel,
int x_gap,
int y_gap)
377 esp_rgb_panel_t *rgb_panel = __containerof(panel, esp_rgb_panel_t, base);
378 rgb_panel->x_gap = x_gap;
379 rgb_panel->y_gap = y_gap;
383static esp_err_t rgb_panel_disp_off(esp_lcd_panel_t *panel,
bool off)
385 esp_rgb_panel_t *rgb_panel = __containerof(panel, esp_rgb_panel_t, base);
386 if (rgb_panel->disp_gpio_num < 0) {
387 return ESP_ERR_NOT_SUPPORTED;
390 gpio_set_level(rgb_panel->disp_gpio_num, !rgb_panel->flags.disp_en_level);
392 gpio_set_level(rgb_panel->disp_gpio_num, rgb_panel->flags.disp_en_level);
397static esp_err_t lcd_rgb_panel_configure_gpio(esp_rgb_panel_t *panel,
const esp_lcd_rgb_panel_config_t *panel_config)
399 int panel_id = panel->panel_id;
401 bool valid_gpio = (panel_config->pclk_gpio_num >= 0);
402 if (panel_config->de_gpio_num < 0) {
404 valid_gpio = valid_gpio && (panel_config->hsync_gpio_num >= 0) && (panel_config->vsync_gpio_num >= 0);
406 for (
size_t i = 0; i < panel_config->data_width; i++) {
407 valid_gpio = valid_gpio && (panel_config->data_gpio_nums[i] >= 0);
410 return ESP_ERR_INVALID_ARG;
413 for (
size_t i = 0; i < panel_config->data_width; i++) {
414 gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[panel_config->data_gpio_nums[i]], PIN_FUNC_GPIO);
415 gpio_set_direction(panel_config->data_gpio_nums[i], GPIO_MODE_OUTPUT);
416 esp_rom_gpio_connect_out_signal(panel_config->data_gpio_nums[i],
417 lcd_periph_signals.panels[panel_id].data_sigs[i],
false,
false);
419 if (panel_config->hsync_gpio_num >= 0) {
420 gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[panel_config->hsync_gpio_num], PIN_FUNC_GPIO);
421 gpio_set_direction(panel_config->hsync_gpio_num, GPIO_MODE_OUTPUT);
422 esp_rom_gpio_connect_out_signal(panel_config->hsync_gpio_num,
423 lcd_periph_signals.panels[panel_id].hsync_sig,
false,
false);
425 if (panel_config->vsync_gpio_num >= 0) {
426 gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[panel_config->vsync_gpio_num], PIN_FUNC_GPIO);
427 gpio_set_direction(panel_config->vsync_gpio_num, GPIO_MODE_OUTPUT);
428 esp_rom_gpio_connect_out_signal(panel_config->vsync_gpio_num,
429 lcd_periph_signals.panels[panel_id].vsync_sig,
false,
false);
431 gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[panel_config->pclk_gpio_num], PIN_FUNC_GPIO);
432 gpio_set_direction(panel_config->pclk_gpio_num, GPIO_MODE_OUTPUT);
433 esp_rom_gpio_connect_out_signal(panel_config->pclk_gpio_num,
434 lcd_periph_signals.panels[panel_id].pclk_sig,
false,
false);
436 if (panel_config->de_gpio_num >= 0) {
437 gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[panel_config->de_gpio_num], PIN_FUNC_GPIO);
438 gpio_set_direction(panel_config->de_gpio_num, GPIO_MODE_OUTPUT);
439 esp_rom_gpio_connect_out_signal(panel_config->de_gpio_num,
440 lcd_periph_signals.panels[panel_id].de_sig,
false,
false);
443 if (panel_config->disp_gpio_num >= 0) {
444 gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[panel_config->disp_gpio_num], PIN_FUNC_GPIO);
445 gpio_set_direction(panel_config->disp_gpio_num, GPIO_MODE_OUTPUT);
446 esp_rom_gpio_connect_out_signal(panel_config->disp_gpio_num, SIG_GPIO_OUT_IDX,
false,
false);
451static esp_err_t lcd_rgb_panel_select_clock_src(esp_rgb_panel_t *panel, lcd_clock_source_t clk_src)
453 esp_err_t ret = ESP_OK;
455 case LCD_CLK_SRC_PLL240M:
456 panel->src_clk_hz = 240000000;
458 case LCD_CLK_SRC_PLL160M:
459 panel->src_clk_hz = 160000000;
461 case LCD_CLK_SRC_XTAL:
462 panel->src_clk_hz = rtc_clk_xtal_freq_get() * 1000000;
465 ESP_RETURN_ON_FALSE(
false, ESP_ERR_NOT_SUPPORTED, TAG,
"unsupported clock source: %d", clk_src);
468 lcd_ll_select_clk_src(panel->hal.dev, clk_src);
470 if (clk_src == LCD_CLK_SRC_PLL240M || clk_src == LCD_CLK_SRC_PLL160M) {
472 ret = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0,
"rgb_panel", &panel->pm_lock);
473 ESP_RETURN_ON_ERROR(ret, TAG,
"create ESP_PM_APB_FREQ_MAX lock failed");
475 esp_pm_lock_acquire(panel->pm_lock);
476 ESP_LOGD(TAG,
"installed ESP_PM_APB_FREQ_MAX lock and hold the lock during the whole panel lifecycle");
482static esp_err_t lcd_rgb_panel_create_trans_link(esp_rgb_panel_t *panel)
484 esp_err_t ret = ESP_OK;
486 for (
int i = 0; i < panel->num_dma_nodes; i++) {
487 panel->dma_nodes[i].dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_CPU;
488 panel->dma_nodes[i].next = &panel->dma_nodes[i + 1];
491 panel->dma_nodes[panel->num_dma_nodes - 1].next = NULL;
495 gdma_channel_alloc_config_t dma_chan_config = {
496 .direction = GDMA_CHANNEL_DIRECTION_TX,
498 ret = gdma_new_channel(&dma_chan_config, &panel->dma_chan);
499 ESP_GOTO_ON_ERROR(ret, err, TAG,
"alloc DMA channel failed");
500 gdma_connect(panel->dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_LCD, 0));
501 gdma_transfer_ability_t ability = {
502 .psram_trans_align = panel->psram_trans_align,
503 .sram_trans_align = panel->sram_trans_align,
505 gdma_set_transfer_ability(panel->dma_chan, &ability);
507 gdma_start(panel->dma_chan, (intptr_t)panel->dma_nodes);
513static void lcd_rgb_panel_start_transmission(esp_rgb_panel_t *rgb_panel)
516 gdma_reset(rgb_panel->dma_chan);
517 lcd_ll_stop(rgb_panel->hal.dev);
518 lcd_ll_fifo_reset(rgb_panel->hal.dev);
519 gdma_start(rgb_panel->dma_chan, (intptr_t)rgb_panel->dma_nodes);
524 lcd_ll_start(rgb_panel->hal.dev);
527IRAM_ATTR
static void lcd_default_isr_handler(
void *args)
529 esp_rgb_panel_t *rgb_panel = (esp_rgb_panel_t *)args;
530 bool need_yield =
false;
532 uint32_t intr_status = lcd_ll_get_interrupt_status(rgb_panel->hal.dev);
533 lcd_ll_clear_interrupt_status(rgb_panel->hal.dev, intr_status);
534 if (intr_status & LCD_LL_EVENT_VSYNC_END) {
536 if (rgb_panel->on_frame_trans_done) {
537 if (rgb_panel->on_frame_trans_done(&rgb_panel->base, NULL, rgb_panel->user_ctx)) {
542 if (rgb_panel->flags.stream_mode) {
543 lcd_rgb_panel_start_transmission(rgb_panel);
547 portYIELD_FROM_ISR();
551esp_err_t esp_lcd_rgb_panel_get_frame_buffer(esp_lcd_panel_handle_t panel, uint32_t fb_num,
void **fb0, ...)
553 ESP_RETURN_ON_FALSE(panel, ESP_ERR_INVALID_ARG, TAG,
"invalid argument");
554 esp_rgb_panel_t *rgb_panel = __containerof(panel, esp_rgb_panel_t, base);
556 void **fb_itor = fb0;
559 for (
int i = 0; i < fb_num; i++) {
561 *fb_itor = rgb_panel->fb;
563 fb_itor = va_arg(args,
void **);
void lcd_com_mount_dma_data(dma_descriptor_t *desc_head, const void *buffer, size_t len)
Mount data to DMA descriptors.