# RGB 接口的 LCD

[English]

RGB LCD 面板的分配步骤只需一步，即调用函数 `esp_lcd_new_rgb_panel()`，其中包含通过 `esp_lcd_rgb_panel_config_t` 指定的各种配置。

> - `esp_lcd_rgb_panel_config_t::clk_src` 选择 RGB LCD 控制器的时钟源。可用的时钟源参见 `lcd_clock_source_t`。

> - `esp_lcd_rgb_panel_config_t::data_width` 设置 RGB 接口使用的数据线数量。目前支持 8 根或 16 根。

> - `esp_lcd_rgb_panel_config_t::bits_per_pixel` 设置每像素的位数 (bpp)。该字段与 `esp_lcd_rgb_panel_config_t::data_width` 有所不同。默认情况下，如果将此字段设置为 0，驱动程序会自动调整 bpp 与 `esp_lcd_rgb_panel_config_t::data_width` 等值。但在某些情况下，bpp 与数据线数量必须不同。例如，串行 RGB 接口的 LCD 只需要 `8` 条数据线，但颜色深度可以达到 `RGB888`，此时 `esp_lcd_rgb_panel_config_t::bits_per_pixel` 应设置为 `24`。

> - `esp_lcd_rgb_panel_config_t::hsync_gpio_num`、`esp_lcd_rgb_panel_config_t::vsync_gpio_num`、`esp_lcd_rgb_panel_config_t::de_gpio_num`、`esp_lcd_rgb_panel_config_t::pclk_gpio_num`、`esp_lcd_rgb_panel_config_t::disp_gpio_num` 以及 `esp_lcd_rgb_panel_config_t::data_gpio_nums` 都是 RGB LCD 控制器使用的 GPIO 管脚。未使用到的管脚需设置为 -1。

> - `esp_lcd_rgb_panel_config_t::dma_burst_size` 设置 DMA 突发传输大小，该值必须是 2 的幂次方。

> - `esp_lcd_rgb_panel_config_t::bounce_buffer_size_px` 设置弹性 buffer 的大小。仅在“弹性 buffer”模式下需要设置此字段。详情请参阅 bounce buffer 与 PSRAM frame buffer。

> - `esp_lcd_rgb_panel_config_t::timings` 设置 LCD 面板的特定时序参数。包括 LCD 分辨率和消隐间隔在内的必要参数列表见 `esp_lcd_rgb_timing_t`，请依据 LCD 技术规格书填写参数。

> - `esp_lcd_rgb_panel_config_t::fb_in_psram` 设置是否从 PSRAM 中分配 frame buffer。详情请参阅 PSRAM 中的单 frame buffer。

> - `esp_lcd_rgb_panel_config_t::num_fbs` 设置由驱动程序分配的 frame buffer 的数量。为了向后兼容，`0` 表示分配 `一个` frame buffer。如果不想分配任何 frame buffer，请设置 `esp_lcd_rgb_panel_config_t::no_fb`。

> - `esp_lcd_rgb_panel_config_t::no_fb` 可决定是否分配 frame buffer。设置该字段后将不分配 frame buffer。这也被称为 只应用 bounce buffer 模式。

## RGB LCD frame buffer 操作模式

大多数情况下，RGB LCD 驱动程序应至少维护一个屏幕大小的 frame buffer。根据 frame buffer 数量和位置的不同，驱动程序提供了几种不同的 buffer 模式。

### 内部存储器中的单 frame buffer 模式

该模式为默认模式，操作最简单，且无需指定标志或弹性 buffer 选项。从内部存储器中分配 frame buffer，帧数据通过 DMA 直接读取到 LCD 上，无需 CPU 干预即可起效，但会占用相当一部分内部存储器。

    esp_lcd_panel_handle_t panel_handle = NULL;
    esp_lcd_rgb_panel_config_t panel_config = {
        .data_width = 16, // 并行模式下像素格式为 RGB565，数据宽度为 16 位
        .clk_src = LCD_CLK_SRC_DEFAULT,
        .disp_gpio_num = EXAMPLE_PIN_NUM_DISP_EN,
        .pclk_gpio_num = EXAMPLE_PIN_NUM_PCLK,
        .vsync_gpio_num = EXAMPLE_PIN_NUM_VSYNC,
        .hsync_gpio_num = EXAMPLE_PIN_NUM_HSYNC,
        .de_gpio_num = EXAMPLE_PIN_NUM_DE,
        .data_gpio_nums = {
            EXAMPLE_PIN_NUM_DATA0,
            EXAMPLE_PIN_NUM_DATA1,
            EXAMPLE_PIN_NUM_DATA2,
            // 其他 GPIO
            // 此处 GPIO 的数量应与上文中 "data_width" 的值相同
            ...
        },
        // 参照 LCD 规格书，填写时序参数
        .timings = {
            .pclk_hz = EXAMPLE_LCD_PIXEL_CLOCK_HZ,
            .h_res = EXAMPLE_LCD_H_RES,
            .v_res = EXAMPLE_LCD_V_RES,
            .hsync_back_porch = 40,
            .hsync_front_porch = 20,
            .hsync_pulse_width = 1,
            .vsync_back_porch = 8,
            .vsync_front_porch = 4,
            .vsync_pulse_width = 1,
        },
    };
    ESP_ERROR_CHECK(esp_lcd_new_rgb_panel(&panel_config, &panel_handle));

### PSRAM 中的单 frame buffer

如果不想将 frame buffer 存储在有限的内部存储器中，而是将其存储在 PSRAM 中，则 LCD 外设将绕过内部 cache，使用 EDMA 直接从 PSRAM 中获取帧数据。将 `esp_lcd_rgb_panel_config_t::fb_in_psram` 设置为 `true` 就可以启用此功能。该模式的缺点在于，当 CPU 和 EDMA 同时需要访问 PSRAM 时，二者将 共享 带宽，即 CPU 与 EDMA 各自获取一半的带宽。若此时还有其他外设也在使用 EDMA，并且像素时钟频率很高，则可能导致 LCD 外设的带宽不足，造成显示损坏。但如果像素时钟频率较低，就不会出现这种问题，且只需极少的 CPU 干预。

PSRAM 与主 flash（用来存储固件二进制文件）共享同一个 SPI 总线，但二者不能同时使用总线。若主 flash 还用来存储其他文件（例如，SPIFFS），则将共享底层 SPI 总线的带宽，造成显示损坏。此时可调用 `esp_lcd_rgb_panel_set_pclk()` 降低像素时钟频率。

    esp_lcd_panel_handle_t panel_handle = NULL;
    esp_lcd_rgb_panel_config_t panel_config = {
        .data_width = 16, // 并行模式下像素格式为 RGB565，数据宽度为 16 位
        .clk_src = LCD_CLK_SRC_DEFAULT,
        .disp_gpio_num = EXAMPLE_PIN_NUM_DISP_EN,
        .pclk_gpio_num = EXAMPLE_PIN_NUM_PCLK,
        .vsync_gpio_num = EXAMPLE_PIN_NUM_VSYNC,
        .hsync_gpio_num = EXAMPLE_PIN_NUM_HSYNC,
        .de_gpio_num = EXAMPLE_PIN_NUM_DE,
        .data_gpio_nums = {
            EXAMPLE_PIN_NUM_DATA0,
            EXAMPLE_PIN_NUM_DATA1,
            EXAMPLE_PIN_NUM_DATA2,
            // 其他 GPIO
            // 此处 GPIO 的数量应与上文中 "data_width" 的值相同
            ...
        },
        // 参照 LCD 规格书，填写时序参数
        .timings = {
            .pclk_hz = EXAMPLE_LCD_PIXEL_CLOCK_HZ,
            .h_res = EXAMPLE_LCD_H_RES,
            .v_res = EXAMPLE_LCD_V_RES,
            .hsync_back_porch = 40,
            .hsync_front_porch = 20,
            .hsync_pulse_width = 1,
            .vsync_back_porch = 8,
            .vsync_front_porch = 4,
            .vsync_pulse_width = 1,
        },
        .flags.fb_in_psram = true, // 从 PSRAM 中分配 frame buffer
    };
    ESP_ERROR_CHECK(esp_lcd_new_rgb_panel(&panel_config, &panel_handle));

### PSRAM 中的双 frame buffer

为避免 LCD 显示撕裂的问题，可以使用两个屏幕大小的 frame buffer。在这种模式下，由于内部存储器空间有限，因而只能从 PSRAM 中分配 frame buffer。CPU 写入的 frame buffer 和 EDMA 读取的 frame buffer 是完全不同且相互独立的两个区域。只有当写入操作完成、且当前帧已发送到 LCD 时，EDMA 才会在两个 frame buffer 之间切换。该模式的缺点在于，必须确保两个 frame buffer 之间同步。

    esp_lcd_panel_handle_t panel_handle = NULL;
    esp_lcd_rgb_panel_config_t panel_config = {
        .data_width = 16, // 并行模式下像素格式为 RGB565，数据宽度为 16 位
        .num_fbs = 2,     // 分配双 frame buffer
        .clk_src = LCD_CLK_SRC_DEFAULT,
        .disp_gpio_num = EXAMPLE_PIN_NUM_DISP_EN,
        .pclk_gpio_num = EXAMPLE_PIN_NUM_PCLK,
        .vsync_gpio_num = EXAMPLE_PIN_NUM_VSYNC,
        .hsync_gpio_num = EXAMPLE_PIN_NUM_HSYNC,
        .de_gpio_num = EXAMPLE_PIN_NUM_DE,
        .data_gpio_nums = {
            EXAMPLE_PIN_NUM_DATA0,
            EXAMPLE_PIN_NUM_DATA1,
            EXAMPLE_PIN_NUM_DATA2,
            // 其他 GPIO
            // 此处 GPIO 的数量应与上文中 "data_width" 的值相同
            ...
        },
        // 参照 LCD 规格书，填写时序参数
        .timings = {
            .pclk_hz = EXAMPLE_LCD_PIXEL_CLOCK_HZ,
            .h_res = EXAMPLE_LCD_H_RES,
            .v_res = EXAMPLE_LCD_V_RES,
            .hsync_back_porch = 40,
            .hsync_front_porch = 20,
            .hsync_pulse_width = 1,
            .vsync_back_porch = 8,
            .vsync_front_porch = 4,
            .vsync_pulse_width = 1,
        },
        .flags.fb_in_psram = true, // 从 PSRAM 中分配 frame buffer
    };
    ESP_ERROR_CHECK(esp_lcd_new_rgb_panel(&panel_config, &panel_handle));

### 用户自定义 frame buffer

用户可以提供自己分配的 frame buffer，而不是让驱动程序分配。该模式下，用户需要自己管理 frame buffer 的生命周期。

    esp_lcd_panel_handle_t panel_handle = NULL;
    esp_lcd_rgb_panel_config_t panel_config = {
        .data_width = 16, // 并行模式下像素格式为 RGB565，数据宽度为 16 位
        .clk_src = LCD_CLK_SRC_DEFAULT,
        .disp_gpio_num = EXAMPLE_PIN_NUM_DISP_EN,
        .pclk_gpio_num = EXAMPLE_PIN_NUM_PCLK,
        .vsync_gpio_num = EXAMPLE_PIN_NUM_VSYNC,
        .hsync_gpio_num = EXAMPLE_PIN_NUM_HSYNC,
        .de_gpio_num = EXAMPLE_PIN_NUM_DE,
        .data_gpio_nums = {
            EXAMPLE_PIN_NUM_DATA0,
            EXAMPLE_PIN_NUM_DATA1,
            EXAMPLE_PIN_NUM_DATA2,
            // 其他 GPIO
            // 此处 GPIO 的数量应与上文中 "data_width" 的值相同
            ...
        },
        // 参照 LCD 规格书，填写时序参数
        .timings = {
            .pclk_hz = EXAMPLE_LCD_PIXEL_CLOCK_HZ,
            .h_res = EXAMPLE_LCD_H_RES,
            .v_res = EXAMPLE_LCD_V_RES,
            .hsync_back_porch = 40,
            .hsync_front_porch = 20,
            .hsync_pulse_width = 1,
            .vsync_back_porch = 8,
            .vsync_front_porch = 4,
            .vsync_pulse_width = 1,
        },
        .user_fbs[0] = user_frame_buffer, // 使用用户自定义 frame buffer
    };
    ESP_ERROR_CHECK(esp_lcd_new_rgb_panel(&panel_config, &panel_handle));

### bounce buffer 与 PSRAM frame buffer

在该模式下，从内部存储器中分配出两个 `bounce buffer` 和一个位于 PSRAM 中的主 frame buffer。若想选择此模式，可设置 `esp_lcd_rgb_panel_config_t::fb_in_psram` 标志并额外指定 `esp_lcd_rgb_panel_config_t::bounce_buffer_size_px` 值（非零）。bounce buffer 只要能容纳几行显示数据即可，存储量远远低于主 frame buffer。LCD 可通过 DMA 从其中一个 bounce buffer 里读取数据，与此同时中断例程通过 CPU DCache 将数据从主 PSRAM frame buffer 复制到另一个 bounce buffer 中。一旦 LCD 完成对 bounce buffer 的数据读取，两个 buffer 将交换位置，CPU 可以填充另一个 bounce buffer。这种模式的优点在于，可以实现更高的像素时钟频率。bounce buffer 的存储量比 EDMA 路径中的 FIFO 大，即便短时间内带宽需求激增，该模式下 bounce buffer 也能有效应对。而缺点在于，CPU 使用量大幅增加，并且如果禁用外部存储器的 cache（例如，禁止通过 OTA 或 NVS 写入主 flash），LCD 将 无法 工作。

备注

强烈建议在此模式下启用 Kconfig 选项：CONFIG_SPIRAM_XIP_FROM_PSRAM，开启“PSRAM XIP（就地执行）”功能，使 CPU 能从 PSRAM 里而不是主 flash 中提取指令和只读数据。此外，即使想通过 SPI 1 写入主 flash，外部存储器 cache 也不会被禁用，应用程序便能正常显示 OTA 进度条。

备注

由于 PSRAM 带宽不足，此模式还可能存在另一个问题。例如，从 PSRAM 中分配绘图 buffer，且 buffer 中的数据被复制到 CPU 核 1 上的内部 frame buffer 中，此时在 CPU 核 0 上，DMA EOF ISR 也在进行内存复制。这种情况下，两个内核都通过 cache 访问 PSRAM 并共享 PSRAM 的带宽，DMA EOF ISR 复制内存的时间大大增加。驱动程序无法及时切换 bounce buffer，造成 LCD 屏幕移位。尽管驱动程序可以检测到这种情况并在 LCD 的 VSYNC 中断处理程序中执行重新启动，但仍会出现屏幕闪烁现象。

    esp_lcd_panel_handle_t panel_handle = NULL;
    esp_lcd_rgb_panel_config_t panel_config = {
        .data_width = 16, // 并行模式下像素格式为 RGB565，数据宽度为 16 位
        .clk_src = LCD_CLK_SRC_DEFAULT,
        .bounce_buffer_size_px = 10 * EXAMPLE_LCD_H_RES, // 从内部存储器中分配 bounce buffer，足够存储 10 行数据
        .disp_gpio_num = EXAMPLE_PIN_NUM_DISP_EN,
        .pclk_gpio_num = EXAMPLE_PIN_NUM_PCLK,
        .vsync_gpio_num = EXAMPLE_PIN_NUM_VSYNC,
        .hsync_gpio_num = EXAMPLE_PIN_NUM_HSYNC,
        .de_gpio_num = EXAMPLE_PIN_NUM_DE,
        .data_gpio_nums = {
            EXAMPLE_PIN_NUM_DATA0,
            EXAMPLE_PIN_NUM_DATA1,
            EXAMPLE_PIN_NUM_DATA2,
            // 其他 GPIO
            // 此处 GPIO 的数量应与上文中 "data_width" 的值相同
            ...
        },
        // 参照 LCD 规格书，填写时序参数
        .timings = {
            .pclk_hz = EXAMPLE_LCD_PIXEL_CLOCK_HZ,
            .h_res = EXAMPLE_LCD_H_RES,
            .v_res = EXAMPLE_LCD_V_RES,
            .hsync_back_porch = 40,
            .hsync_front_porch = 20,
            .hsync_pulse_width = 1,
            .vsync_back_porch = 8,
            .vsync_front_porch = 4,
            .vsync_pulse_width = 1,
        },
        .flags.fb_in_psram = true, // 从 PSRAM 中分配 frame buffer
    };
    ESP_ERROR_CHECK(esp_lcd_new_rgb_panel(&panel_config, &panel_handle));

### 只应用 bounce buffer

该模式与 bounce buffer 与 PSRAM frame buffer 模式类似，但 LCD 驱动程序不会初始化 PSRAM frame buffer。相反，该模式依赖用户提供的回调函数来填充 bounce buffer。LCD 驱动程序无需指定写入像素的来源，因此回调函数可以执行一些操作：例如，将较小的每像素 8 位 PSRAM frame buffer 即时转换为 16 位 LCD 数据，甚至还可以转换为无 frame buffer 图形。若想选择此模式，可以设置 `esp_lcd_rgb_panel_config_t::no_fb` 标志并提供 `esp_lcd_rgb_panel_config_t::bounce_buffer_size_px` 值。然后通过调用 `esp_lcd_rgb_panel_register_event_callbacks()` 注册回调函数 `esp_lcd_rgb_panel_event_callbacks_t::on_bounce_empty`。

备注

虽说在设计良好的嵌入式应用程序中, DMA 传递数据的速度不应该赶不上 LCD 读取数据的速度。但理论上，此种情况还是有可能出现的。在 ESP32-S3 的硬件中，这种情况会导致 LCD 在 DMA 等待数据时单纯输出 dummy 字节。若以流式传输运行 DMA，则 DMA 会将读取到的数据传输到某个 LCD 地址，同时 LCD 也会将数据输出到某个 LCD 地址，但上述两个地址可能会不同步，导致图像 永久 偏移。 为防止类似情况发生，可以启用 CONFIG_LCD_RGB_RESTART_IN_VSYNC 选项，以便驱动程序在 VBlank 中断时自动重启 DMA；或者也可以调用 `esp_lcd_rgb_panel_restart()`，手动重启 DMA。请注意，调用 `esp_lcd_rgb_panel_restart()` 不会立即重启 DMA，DMA 只会在下一个 VSYNC 事件中重启。

## API 参考

### Header File

- components/esp_lcd/rgb/include/esp_lcd_panel_rgb.h

- This header file can be included with:

  >     #include "esp_lcd_panel_rgb.h"

- This header file is a part of the API provided by the `esp_lcd` component. To declare that your component depends on `esp_lcd`, add the following to your CMakeLists.txt:

  >     REQUIRES esp_lcd

  > or

  >     PRIV_REQUIRES esp_lcd

### Functions

esp_err_t esp_lcd_new_rgb_panel(const esp_lcd_rgb_panel_config_t *rgb_panel_config, esp_lcd_panel_handle_t *ret_panel)

  Create RGB LCD panel.

  参数:

    - rgb_panel_config -- [in] RGB panel configuration

    - ret_panel -- [out] Returned LCD panel handle

  返回:

    - ESP_ERR_INVALID_ARG: Create RGB LCD panel failed because of invalid argument

    - ESP_ERR_NO_MEM: Create RGB LCD panel failed because of out of memory

    - ESP_ERR_NOT_FOUND: Create RGB LCD panel failed because some mandatory hardware resources are not found

    - ESP_OK: Create RGB LCD panel successfully

esp_err_t esp_lcd_rgb_panel_register_event_callbacks(esp_lcd_panel_handle_t panel, const esp_lcd_rgb_panel_event_callbacks_t *callbacks, void *user_ctx)

  Register LCD RGB panel event callbacks.

  参数:

    - panel -- [in] LCD panel handle, returned from `esp_lcd_new_rgb_panel`

    - callbacks -- [in] Group of callback functions

    - user_ctx -- [in] User data, which will be passed to the callback functions directly

  返回:

    - ESP_OK: Set event callbacks successfully

    - ESP_ERR_INVALID_ARG: Set event callbacks failed because of invalid argument

    - ESP_FAIL: Set event callbacks failed because of other error

esp_err_t esp_lcd_rgb_panel_set_pclk(esp_lcd_panel_handle_t panel, uint32_t freq_hz)

  Set frequency of PCLK for RGB LCD panel.

  备注

  The PCLK frequency is set in the `esp_lcd_rgb_timing_t` and gets configured during LCD panel initialization. Usually you don't need to call this function to set the PCLK again, but in some cases, you might want to change the PCLK frequency. e.g. slow down the PCLK frequency to reduce power consumption or to reduce the memory throughput during OTA.

  备注

  This function doesn't cause the hardware to update the PCLK immediately but to record the new frequency and set a flag internally. Only in the next VSYNC event handler, will the driver attempt to update the PCLK frequency.

  参数:

    - panel -- [in] LCD panel handle, returned from `esp_lcd_new_rgb_panel`

    - freq_hz -- [in] Frequency of pixel clock, in Hz

  返回:

    - ESP_ERR_INVALID_ARG: Set PCLK frequency failed because of invalid argument

    - ESP_OK: Set PCLK frequency successfully

esp_err_t esp_lcd_rgb_panel_restart(esp_lcd_panel_handle_t panel)

  Restart the LCD transmission.

  备注

  This function can be useful when the LCD controller is out of sync with the DMA because of insufficient bandwidth. To save the screen from a permanent shift, you can call this function to restart the LCD DMA.

  备注

  This function doesn't restart the DMA immediately but to set a flag internally. Only in the next VSYNC event handler, will the driver attempt to do the restart job.

  备注

  If CONFIG_LCD_RGB_RESTART_IN_VSYNC is enabled, you don't need to call this function manually, because the restart job will be done automatically in the VSYNC event handler.

  参数:

    panel -- [in] panel LCD panel handle, returned from `esp_lcd_new_rgb_panel`

  返回:

    - ESP_ERR_INVALID_ARG: Restart the LCD failed because of invalid argument

    - ESP_ERR_INVALID_STATE: Restart the LCD failed because the LCD diver is working in refresh-on-demand mode

    - ESP_OK: Restart the LCD successfully

esp_err_t esp_lcd_rgb_panel_get_frame_buffer(esp_lcd_panel_handle_t panel, uint32_t fb_num, void **fb0, ...)

  Get the address of the frame buffer(s) that allocated by the driver.

  参数:

    - panel -- [in] LCD panel handle, returned from `esp_lcd_new_rgb_panel`

    - fb_num -- [in] Number of frame buffer(s) to get. This value must be the same as the number of the following parameters.

    - fb0 -- [out] Returned address of the frame buffer 0

    - ... -- [out] List of other frame buffer addresses

  返回:

    - ESP_ERR_INVALID_ARG: Get frame buffer address failed because of invalid argument

    - ESP_OK: Get frame buffer address successfully

esp_err_t esp_lcd_rgb_panel_refresh(esp_lcd_panel_handle_t panel)

  Manually trigger once transmission of the frame buffer to the LCD panel.

  备注

  This function should only be called when the RGB panel is working under the `refresh_on_demand` mode.

  参数:

    panel -- [in] LCD panel handle, returned from `esp_lcd_new_rgb_panel`

  返回:

    - ESP_ERR_INVALID_ARG: Start a refresh failed because of invalid argument

    - ESP_ERR_INVALID_STATE: Start a refresh failed because the LCD panel is not created with the `refresh_on_demand` flag enabled.

    - ESP_OK: Start a refresh successfully

void *esp_lcd_rgb_alloc_draw_buffer(esp_lcd_panel_handle_t panel, size_t size, uint32_t caps)

  Allocate a draw buffer for RGB LCD panel.

  备注

  This function differs from the normal 'heap_caps_*' functions in that it can also automatically handle the alignment required by DMA burst, cache line size, etc.

  参数:

    - panel -- [in] LCD panel handle, returned from `esp_lcd_new_rgb_panel`

    - size -- [in] Size of memory to be allocated

    - caps -- [in] Bitwise OR of MALLOC_CAP_* flags indicating the type of memory desired for the allocation

  返回:

    Pointer to a new buffer of size 'size' with capabilities 'caps', or NULL if allocation failed

esp_err_t esp_lcd_rgb_panel_set_yuv_conversion(esp_lcd_panel_handle_t panel, const esp_lcd_color_conv_yuv_config_t *config)

  Configure how to convert the color format between RGB and YUV.

  参数:

    - panel -- [in] LCD panel handle, returned from `esp_lcd_new_rgb_panel`

    - config -- [in] Configuration of RGB-YUV conversion profile

  返回:

    - ESP_ERR_INVALID_ARG: Configure RGB-YUV conversion failed because of invalid argument

    - ESP_ERR_NOT_SUPPORTED: Configure RGB-YUV conversion failed because the conversion mode is not supported by the hardware

    - ESP_OK: Configure RGB-YUV conversion successfully

### Structures

struct esp_lcd_rgb_timing_t

  LCD RGB timing structure.

      *                                                 Total Width
      *                             <--------------------------------------------------->
      *                       HSYNC width HBP             Active Width                HFP
      *                             <---><--><--------------------------------------><--->
      *                         ____    ____|_______________________________________|____|
      *                             |___|   |                                       |    |
      *                                     |                                       |    |
      *                         __|         |                                       |    |
      *            /|\    /|\  |            |                                       |    |
      *             | VSYNC|   |            |                                       |    |
      *             |Width\|/  |__          |                                       |    |
      *             |     /|\     |         |                                       |    |
      *             |  VBP |      |         |                                       |    |
      *             |     \|/_____|_________|_______________________________________|    |
      *             |     /|\     |         | / / / / / / / / / / / / / / / / / / / |    |
      *             |      |      |         |/ / / / / / / / / / / / / / / / / / / /|    |
      *    Total    |      |      |         |/ / / / / / / / / / / / / / / / / / / /|    |
      *    Height   |      |      |         |/ / / / / / / / / / / / / / / / / / / /|    |
      *             |Active|      |         |/ / / / / / / / / / / / / / / / / / / /|    |
      *             |Height|      |         |/ / / / / / Active Display Area / / / /|    |
      *             |      |      |         |/ / / / / / / / / / / / / / / / / / / /|    |
      *             |      |      |         |/ / / / / / / / / / / / / / / / / / / /|    |
      *             |      |      |         |/ / / / / / / / / / / / / / / / / / / /|    |
      *             |      |      |         |/ / / / / / / / / / / / / / / / / / / /|    |
      *             |      |      |         |/ / / / / / / / / / / / / / / / / / / /|    |
      *             |     \|/_____|_________|_______________________________________|    |
      *             |     /|\     |                                                      |
      *             |  VFP |      |                                                      |
      *            \|/    \|/_____|______________________________________________________|
      *

  Public Members

  uint32_t pclk_hz

    Frequency of pixel clock

  uint32_t h_res

    Horizontal resolution, i.e. the number of pixels in a line

  uint32_t v_res

    Vertical resolution, i.e. the number of lines in the frame

  uint32_t hsync_pulse_width

    Horizontal sync width, unit: PCLK period

  uint32_t hsync_back_porch

    Horizontal back porch, number of PCLK between hsync and start of line active data

  uint32_t hsync_front_porch

    Horizontal front porch, number of PCLK between the end of active data and the next hsync

  uint32_t vsync_pulse_width

    Vertical sync width, unit: number of lines

  uint32_t vsync_back_porch

    Vertical back porch, number of invalid lines between vsync and start of frame

  uint32_t vsync_front_porch

    Vertical front porch, number of invalid lines between the end of frame and the next vsync

  uint32_t hsync_idle_low

    The hsync signal is low in IDLE state

  uint32_t vsync_idle_low

    The vsync signal is low in IDLE state

  uint32_t de_idle_high

    The de signal is high in IDLE state

  uint32_t pclk_active_neg

    Whether the display data is clocked out on the falling edge of PCLK

  uint32_t pclk_idle_high

    The PCLK stays at high level in IDLE phase

  struct esp_lcd_rgb_timing_t flags

    LCD RGB timing flags

struct esp_lcd_rgb_panel_event_data_t

  Type of RGB LCD panel event data.

struct esp_lcd_rgb_panel_event_callbacks_t

  Group of supported RGB LCD panel callbacks.

  备注

  The callbacks are all running under ISR environment

  备注

  When CONFIG_LCD_RGB_ISR_IRAM_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM.

  Public Members

  esp_lcd_rgb_panel_draw_buf_complete_cb_t on_color_trans_done

    Invoked when user's color buffer copied to the internal frame buffer. This is an indicator that the draw buffer can be recycled safely. But doesn't mean the draw buffer finishes the refreshing to the screen.

  esp_lcd_rgb_panel_vsync_cb_t on_vsync

    VSYNC event callback

  esp_lcd_rgb_panel_bounce_buf_fill_cb_t on_bounce_empty

    Bounce buffer empty callback.

  esp_lcd_rgb_panel_frame_buf_complete_cb_t on_frame_buf_complete

    Invoked when the frame buffer can be reused safely

struct esp_lcd_rgb_panel_config_t

  LCD RGB panel configuration structure.

  Public Members

  lcd_clock_source_t clk_src

    Clock source for the RGB LCD peripheral

  esp_lcd_rgb_timing_t timings

    RGB timing parameters, including the screen resolution

  size_t data_width

    Number of data lines

  lcd_color_format_t in_color_format

    Format of the input data (color space and pixel format), which is the format stored in the frame buffer

  lcd_color_format_t out_color_format

    Format of the output data (color space and pixel format), which is the format that the panel device can accept

  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

  void *user_fbs[ESP_RGB_LCD_PANEL_MAX_FB_NUM]

    Array of user-provided frame buffers. If not NULL, the driver will use these buffers instead of allocating its own

  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 dma_burst_size

    DMA burst size, in bytes

  gpio_num_t hsync_gpio_num

    GPIO used for HSYNC signal

  gpio_num_t vsync_gpio_num

    GPIO used for VSYNC signal

  gpio_num_t de_gpio_num

    GPIO used for DE signal, set to -1 if it's not used

  gpio_num_t pclk_gpio_num

    GPIO used for PCLK signal, set to -1 if it's not used

  gpio_num_t disp_gpio_num

    GPIO used for display control signal, set to -1 if it's not used

  gpio_num_t data_gpio_nums[ESP_LCD_RGB_BUS_WIDTH_MAX]

    GPIOs used for data lines

  uint32_t disp_active_low

    If this flag is enabled, a low level of display control signal can turn the screen on; vice versa

  uint32_t refresh_on_demand

    If this flag is enabled, the host only refresh the frame buffer in `esp_lcd_panel_draw_bitmap` and `esp_lcd_rgb_panel_refresh`.

  uint32_t fb_in_psram

    If this flag is enabled, the frame buffer will be allocated from PSRAM, preferentially

  uint32_t double_fb

    If this flag is enabled, the driver will allocate two screen sized frame buffer, same as num_fbs=2

  uint32_t no_fb

    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

    If this flag is enabled, in bounce back mode we'll do a cache invalidate on the read data, freeing the cache. Can be dangerous if data is written from other core(s).

  struct esp_lcd_rgb_panel_config_t flags

    LCD RGB panel configuration flags

### Macros

ESP_LCD_RGB_BUS_WIDTH_MAX

ESP_RGB_LCD_PANEL_MAX_FB_NUM

### Type Definitions

typedef bool (*esp_lcd_rgb_panel_general_cb_t)(esp_lcd_panel_handle_t panel, const esp_lcd_rgb_panel_event_data_t *edata, void *user_ctx)

  A general function callback prototype for RGB panel driver.

  Param panel:

    [in] LCD panel handle, which is created by factory API like `esp_lcd_new_rgb_panel`

  Param edata:

    [in] RGB panel event data, provided by driver

  Param user_ctx:

    [in] User data, passed from `esp_lcd_rgb_panel_register_event_callbacks()`

  Return:

    Whether a high priority task has been waken up by this function

typedef esp_lcd_rgb_panel_general_cb_t esp_lcd_rgb_panel_draw_buf_complete_cb_t

  Declare the prototype of the function that will be invoked when the user draw buffer is complete. The draw buffer can be recycled after this event.

typedef esp_lcd_rgb_panel_general_cb_t esp_lcd_rgb_panel_frame_buf_complete_cb_t

  Declare the prototype of the function that will be invoked when a whole frame buffer can be reused safely. The LCD hardware may still need some blank time to finish the refresh.

typedef esp_lcd_rgb_panel_general_cb_t esp_lcd_rgb_panel_vsync_cb_t

  Declare the prototype of the function that will be invoked when the LCD controller sends the VSYNC signal. It means, the LCD hardware should be ready, and after some blank time, the next frame will be flushed to the LCD controller.

typedef bool (*esp_lcd_rgb_panel_bounce_buf_fill_cb_t)(esp_lcd_panel_handle_t panel, void *bounce_buf, int pos_px, int len_bytes, void *user_ctx)

  Prototype for function to re-fill a bounce buffer, rather than copying from the frame buffer.

  Param panel:

    [in] LCD panel handle, returned from `esp_lcd_new_rgb_panel`

  Param bounce_buf:

    [in] Bounce buffer to write data into

  Param pos_px:

    [in] How many pixels already were sent to the display in this frame, in other words, at what pixel the routine should start putting data into bounce_buf

  Param len_bytes:

    [in] Length, in bytes, of the bounce buffer. Routine should fill this length fully.

  Param user_ctx:

    [in] Opaque pointer that was passed from `esp_lcd_rgb_panel_register_event_callbacks()`

  Return:

    Whether a high priority task has been waken up by this function

此文档对您有帮助吗？

- 反馈已收到，谢谢！
- 如果您有其他意见，欢迎填写乐鑫文档反馈表。

- 我们重视您的反馈。
- 您可以填写乐鑫文档反馈表告诉我们如何改进该文档。