# RGB Interfaced LCD

[中文]

RGB LCD panel is created by `esp_lcd_new_rgb_panel()`, with various configurations specified in `esp_lcd_rgb_panel_config_t`.

> - `esp_lcd_rgb_panel_config_t::clk_src` selects the clock source of the RGB LCD controller. The available clock sources are listed in `lcd_clock_source_t`.

> - `esp_lcd_rgb_panel_config_t::data_width` sets number of data lines consumed by the RGB interface. It can be 8/16/24.

> - `esp_lcd_rgb_panel_config_t::bits_per_pixel` specifies the number of bits per pixel. This differs from `esp_lcd_rgb_panel_config_t::data_width`. By default, if this field is set to 0, the driver will automatically match the bpp to the value set in `esp_lcd_rgb_panel_config_t::data_width`. However, in some scenarios, these values need to be different. For instance, a serial RGB interfaced LCD might only require `8` data lines, but the color depth could be `RGB888`, meaning `esp_lcd_rgb_panel_config_t::bits_per_pixel` should be set to `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` and `esp_lcd_rgb_panel_config_t::data_gpio_nums` are GPIO pins consumed by the RGB LCD controller. If any of them are not used, please set them to `-1`.

> - `esp_lcd_rgb_panel_config_t::dma_burst_size` specifies the size of the DMA transfer burst. Ensure this value is a power of 2.

> - `esp_lcd_rgb_panel_config_t::bounce_buffer_size_px` specifies the size of the bounce buffer. This is required only for the "bounce buffer" mode. For more details, see Bounce Buffer with Single PSRAM Frame Buffer.

> - `esp_lcd_rgb_panel_config_t::timings` specifies the timing parameters unique to the LCD panel. These parameters, detailed in `esp_lcd_rgb_timing_t`, include the LCD resolution and blanking porches. Ensure they are set according to your LCD's datasheet.

> - `esp_lcd_rgb_panel_config_t::fb_in_psram` determines if the frame buffer should be allocated from PSRAM. For further details, see Single Frame Buffer in PSRAM.

> - `esp_lcd_rgb_panel_config_t::num_fbs` specifies how many frame buffers the driver should allocate. For backward compatibility, setting this to `0` will allocate a single frame buffer. If you don't want to allocate any frame buffer, use `esp_lcd_rgb_panel_config_t::no_fb` instead.

> - `esp_lcd_rgb_panel_config_t::no_fb` determines whether frame buffer will be allocated. When it is set, no frame buffer will be allocated. This is also called the Bounce Buffer Only mode.

## GPIO Matrix and IOMUX Pins

On ESP32-S31, the RGB LCD driver can use IOMUX automatically when all required signals are mapped to dedicated pins:

- If `data_gpio_nums`, `hsync_gpio_num`, `vsync_gpio_num`, `pclk_gpio_num`, and `de_gpio_num` all match their dedicated IOMUX pins, the driver bypasses the GPIO matrix automatically.

- If any one of these signals does not match the dedicated IOMUX pin, the driver falls back to GPIO matrix routing automatically.

For higher pixel clock configurations, using IOMUX pins is recommended for better timing robustness.

Dedicated RGB IOMUX pins on ESP32-S31 are listed below:

- When `data_width = 8`, `DATA[0:7]` is used

- When `data_width = 16`, `DATA[0:15]` is used

- When `data_width = 24`, `DATA[0:23]` is used

Signal | GPIO
--- | ---
DATA[0:7] | 8, 9, 10, 11, 12, 13, 14, 15
DATA[8:15] | 16, 17, 18, 19, 33, 34, 35, 36
DATA[16:23] | 37, 38, 39, 2, 3, 4, 5, 7
HSYNC | 44
VSYNC | 45
PCLK | 40
DE | 43

## RGB LCD Frame Buffer Operation Modes

Most of the time, the RGB LCD driver should maintain at least one screen sized frame buffer. According to the number and location of the frame buffer, the driver provides several different buffer modes.

### Single Frame Buffer in Internal Memory

This is the default and simplest and you do not have to specify flags or bounce buffer options. A frame buffer is allocated from the internal memory. The frame data is read out by DMA to the LCD verbatim. It needs no CPU intervention to function, but it has the downside that it uses up a fair bit of the limited amount of internal memory.

    esp_lcd_panel_handle_t panel_handle = NULL;
    esp_lcd_rgb_panel_config_t panel_config = {
        .data_width = 16, // RGB565 in parallel mode, thus 16 bits in width
        .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,
            // other GPIOs
            // The number of GPIOs here should be the same to the value of "data_width" above
            ...
        },
        // The timing parameters should refer to your LCD spec
        .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));

### Single Frame Buffer in PSRAM

If you have PSRAM and prefer to store the frame buffer there instead of using the limited internal memory, the LCD peripheral can utilize EDMA to fetch frame data directly from PSRAM, bypassing the internal cache. This can be enabled by setting `esp_lcd_rgb_panel_config_t::fb_in_psram` to `true`. The trade-off is that when both the CPU and EDMA need access to PSRAM, the bandwidth is shared between them, meaning EDMA and the CPU each get half. If other peripherals are also using EDMA, a high pixel clock might cause LCD peripheral starvation, leading to display corruption. However, with a sufficiently low pixel clock, this approach minimizes CPU intervention.

    esp_lcd_panel_handle_t panel_handle = NULL;
    esp_lcd_rgb_panel_config_t panel_config = {
        .data_width = 16, // RGB565 in parallel mode, thus 16 bits in width
        .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,
            // other GPIOs
            // The number of GPIOs here should be the same to the value of "data_width" above
            ...
        },
        // The timing parameters should refer to your LCD spec
        .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, // allocate frame buffer from PSRAM
    };
    ESP_ERROR_CHECK(esp_lcd_new_rgb_panel(&panel_config, &panel_handle));

### Double Frame Buffer in PSRAM

To prevent tearing effects, the simplest method is to use two screen-sized frame buffers. Given the limited internal memory, these buffers must be allocated from PSRAM. This ensures that the frame buffer being written to by the CPU and the one being read by the EDMA are always distinct and independent. The EDMA will only switch between the two buffers once the current write operation is complete and the frame has been fully transmitted to the LCD. The main drawback of this approach is the need to maintain synchronization between the two frame buffers.

    esp_lcd_panel_handle_t panel_handle = NULL;
    esp_lcd_rgb_panel_config_t panel_config = {
        .data_width = 16, // RGB565 in parallel mode, thus 16 bits in width
        .num_fbs = 2,     // allocate double 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,
            // other GPIOs
            // The number of GPIOs here should be the same to the value of "data_width" above
            ...
        },
        // The timing parameters should refer to your LCD spec
        .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, // allocate frame buffer from PSRAM
    };
    ESP_ERROR_CHECK(esp_lcd_new_rgb_panel(&panel_config, &panel_handle));

### User Custom Frame Buffer

User can provide their own frame buffer instead of letting the driver allocate it. In this mode, user needs to manage the lifecycle of the frame buffer by themselves.

    esp_lcd_panel_handle_t panel_handle = NULL;
    esp_lcd_rgb_panel_config_t panel_config = {
        .data_width = 16, // RGB565 in parallel mode, thus 16 bits in width
        .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,
            // other GPIOs
            // The number of GPIOs here should be the same to the value of "data_width" above
            ...
        },
        // The timing parameters should refer to your LCD spec
        .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, // use user custom frame buffer
    };
    ESP_ERROR_CHECK(esp_lcd_new_rgb_panel(&panel_config, &panel_handle));

### Bounce Buffer with Single PSRAM Frame Buffer

This mode allocates two "bounce buffers" from internal memory and a main frame buffer in PSRAM. To enable this mode, set the `esp_lcd_rgb_panel_config_t::fb_in_psram` flag and specify a non-zero value for `esp_lcd_rgb_panel_config_t::bounce_buffer_size_px`. The bounce buffers only need to hold a few lines of display data, which is much smaller than the main frame buffer. The LCD peripheral uses DMA to read data from one bounce buffer while an interrupt routine uses the CPU DCache to copy data from the main PSRAM frame buffer into the other bounce buffer. Once the LCD peripheral finishes reading from the bounce buffer, the buffers swap roles, allowing the CPU to fill the other one. The advantage of this mode is achieving a higher pixel clock frequency. Since the bounce buffers are larger than the FIFOs in the EDMA path, this method is also more robust against short bandwidth spikes. The downside is a significant increase in CPU usage, and the LCD CANNOT function if the external memory cache is disabled, such as during OTA or NVS writes to the main flash.

Note

For optimal performance in this mode, it is highly recommended to enable the "PSRAM XIP (Execute In Place)" feature by turning on the Kconfig option: CONFIG_SPIRAM_XIP_FROM_PSRAM. This allows the CPU to fetch instructions and read-only data directly from PSRAM instead of the main flash. Additionally, the external memory cache remains active even when writing to the main flash via SPI 1, making it feasible to display an OTA progress bar during your application updates.

Note

This mode also faces issues due to limited PSRAM bandwidth. For instance, if your draw buffers are in PSRAM and their contents are copied to the internal frame buffer by CPU Core 1, while CPU Core 0 is performing another memory copy in the DMA EOF ISR, both CPUs will be accessing PSRAM via cache, sharing its bandwidth. This significantly increases the memory copy time in the DMA EOF ISR, causing the driver to fail in switching the bounce buffer promptly, resulting in a screen shift. Although the driver can detect this condition and restart in the LCD's VSYNC interrupt handler, you may still notice flickering on the screen.

    esp_lcd_panel_handle_t panel_handle = NULL;
    esp_lcd_rgb_panel_config_t panel_config = {
        .data_width = 16, // RGB565 in parallel mode, thus 16 bits in width
        .clk_src = LCD_CLK_SRC_DEFAULT,
        .bounce_buffer_size_px = 10 * EXAMPLE_LCD_H_RES, // allocate 10 lines data as bounce buffer from internal memory
        .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,
            // other GPIOs
            // The number of GPIOs here should be the same to the value of "data_width" above
            ...
        },
        // The timing parameters should refer to your LCD spec
        .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, // allocate frame buffer from PSRAM
    };
    ESP_ERROR_CHECK(esp_lcd_new_rgb_panel(&panel_config, &panel_handle));

### Bounce Buffer Only

This mode is similar to Bounce Buffer with Single PSRAM Frame Buffer, but there is no PSRAM frame buffer initialized by the LCD driver. Instead, the user supplies a callback function that is responsible for filling the bounce buffers. As this driver does not care where the written pixels come from, this allows for the callback doing e.g., on-the-fly conversion from a smaller, 8-bit-per-pixel PSRAM frame buffer to a 16-bit LCD, or even procedurally generated frame-buffer-less graphics. This option is selected by setting the `esp_lcd_rgb_panel_config_t::no_fb` flag and supplying a `esp_lcd_rgb_panel_config_t::bounce_buffer_size_px` value. And then register the `esp_lcd_rgb_panel_event_callbacks_t::on_bounce_empty` callback by calling `esp_lcd_rgb_panel_register_event_callbacks()`.

Note

In a well-designed embedded application, situations where the DMA cannot deliver data as fast as the LCD consumes it should be avoided. However, such scenarios can theoretically occur. In the ESP32-S31 hardware, this results in the LCD outputting dummy bytes while the DMA waits for data. If the DMA were to run in a continuous stream, it could cause a desynchronization between the LCD address from which the DMA reads data and the address from which the LCD peripheral outputs data, leading to a permanently shifted image. To prevent this, you can either enable the CONFIG_LCD_RGB_RESTART_IN_VSYNC option, allowing the driver to automatically restart the DMA during the VBlank interrupt, or call `esp_lcd_rgb_panel_restart()` to manually restart the DMA. Note that `esp_lcd_rgb_panel_restart()` does not restart the DMA immediately; instead, the DMA will be restarted at the next VSYNC event.

## API Reference

### 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.

  Parameters:

    - rgb_panel_config -- [in] RGB panel configuration

    - ret_panel -- [out] Returned LCD panel handle

  Returns:

    - 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.

  Parameters:

    - 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

  Returns:

    - 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.

  Note

  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.

  Note

  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.

  Parameters:

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

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

  Returns:

    - 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.

  Note

  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.

  Note

  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.

  Note

  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.

  Parameters:

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

  Returns:

    - 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.

  Parameters:

    - 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

  Returns:

    - 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.

  Note

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

  Parameters:

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

  Returns:

    - 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.

  Note

  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.

  Parameters:

    - 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

  Returns:

    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.

  Parameters:

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

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

  Returns:

    - 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.

  Note

  The callbacks are all running under ISR environment

  Note

  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

    A whole frame buffer was just sent to the LCD DMA

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 is sent to the LCD DMA. 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

Was this page helpful?

- Thank you! We received your feedback.
- If you have any comments, fill in Espressif Documentation Feedback Form.

- We value your feedback.
- Let us know how we can improve this page by filling in Espressif Documentation Feedback Form.