LCD

Introduction

ESP chips can generate various kinds of timings that needed by common LCDs on the market, like SPI LCD, I80 LCD (a.k.a Intel 8080 parallel LCD), RGB/SRGB LCD, I2C LCD, etc. The esp_lcd component is officially to support those LCDs with a group of universal APIs across chips.

Functional Overview

In esp_lcd, an LCD panel is represented by esp_lcd_panel_handle_t, which plays the role of an abstract frame buffer, regardless of the frame memory is allocated inside ESP chip or in external LCD controller. Based on the location of the frame buffer, the LCD panel allocation functions are mainly grouped into the following categories:

  • RGB LCD panel - is simply based on a group of specific synchronous signals indicating where to start and stop a frame.

  • Controller based LCD panel involves multiple steps to get a panel handle, like bus allocation, IO device registration and controller driver install.

After we get the LCD handle, the remaining LCD operations are the same for different LCD interfaces and vendors.

RGB Interfaced LCD

RGB LCD panel is allocated in one step: esp_lcd_new_rgb_panel(), with various configurations specified by esp_lcd_rgb_panel_config_t.

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 don’t 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 16bit 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 want to store the frame buffer there rather than in the limited internal memory, the LCD peripheral will use EDMA to fetch frame data directly from the PSRAM, bypassing the internal cache. You can enable this feature by setting the esp_lcd_rgb_panel_config_t::fb_in_psram to true. The downside of this is that when both the CPU as well as EDMA need access to the PSRAM, the bandwidth will be shared between them, that is, EDMA gets half and the CPUs the other half. If there’re other peripherals using EDMA as well, with a high enough pixel clock this can lead to starvation of the LCD peripheral, leading to display corruption. However, if the pixel clock is low enough for this not to be an issue, this is a solution that uses almost no 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 16bit 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 avoid tearing effect, using two screen sized frame buffers is the easiest approach. In this mode, the frame buffer can only be allocated from PSRAM, because of the limited internal memory. The frame buffer that the CPU write to and the frame buffer that the EDMA read from are guaranteed to be different and independent. The EDMA will only switch between the two frame buffers when the previous write operation is finished and the current frame has been sent to the LCD. The downside of this mode is that, you have to maintain the 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 16bit 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
    .flags.double_fb = true,   // allocate double 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 so-called bounce buffers from the internal memory, and a main frame buffer that is still in PSRAM. This mode is selected by setting the esp_lcd_rgb_panel_config_t::fb_in_psram flag and additionally specifying a non-zero esp_lcd_rgb_panel_config_t::bounce_buffer_size_px value. The bounce buffers only need to be large enough to hold a few lines of display data, which is significantly less than the main frame buffer. The LCD peripheral will use DMA to read data from one of the bounce buffers, and meanwhile an interrupt routine will use the CPU DCache to copy data from the main PSRAM frame buffer into the other bounce buffer. Once the LCD peripheral has finished reading the bounce buffer, the two buffers change place and the CPU can fill the others. The advantage of this mode is that, you can achieve higher pixel clock frequency. As 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 major increase in CPU use and the LCD CAN’T work if the cache is disabled by flash operations, e.g. OTA or NVS write.

esp_lcd_panel_handle_t panel_handle = NULL;
esp_lcd_rgb_panel_config_t panel_config = {
    .data_width = 16, // RGB565 in parallel mode, thus 16bit 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));

Note that this mode also allows for a esp_lcd_rgb_panel_config_t::bb_invalidate_cache flag to be set. Enabling this frees up the cache lines after they’re used to read out the frame buffer data from PSRAM, but it may lead to slight corruption if the other core writes data to the frame buffer at the exact time the cache lines are freed up. (Technically, a write to the frame buffer can be ignored if it falls between the cache writeback and the cache invalidate calls.)

Bounce Buffer Only

This mode is similar to the 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 an 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

It should never happen in a well-designed embedded application, but it can in theory be possible that the DMA cannot deliver data as fast as the LCD consumes it. In the ESP32-S3 hardware, this leads to the LCD simply outputting dummy bytes while DMA waits for data. If we were to run DMA in a stream fashion, this would mean a de-sync between the LCD address the DMA reads the data for and the LCD address the LCD peripheral thinks it outputs data for, leading to a permanently shifted image. In order to stop this from happening, you can enable the CONFIG_LCD_RGB_RESTART_IN_VSYNC option, so the driver will restart the DMA in the VBlank interrupt; this way we always know where it starts.

Application Example

LCD examples are located under: peripherals/lcd:

Other LCD drivers

Drivers for some LCD and touch controllers are available in IDF Component Registry. The list of available and planned drivers with links is in this table.

API Reference

Header File

Type Definitions

typedef soc_periph_lcd_clk_src_t lcd_clock_source_t

LCD clock source.

Enumerations

enum lcd_color_rgb_endian_t

RGB color endian.

Values:

enumerator LCD_RGB_ENDIAN_RGB

RGB data endian: RGB

enumerator LCD_RGB_ENDIAN_BGR

RGB data endian: BGR

enum lcd_color_space_t

LCD color space.

Values:

enumerator LCD_COLOR_SPACE_RGB

Color space: RGB

enumerator LCD_COLOR_SPACE_YUV

Color space: YUV

enum lcd_color_range_t

LCD color range.

Values:

enumerator LCD_COLOR_RANGE_LIMIT

Limited color range

enumerator LCD_COLOR_RANGE_FULL

Full color range

enum lcd_yuv_sample_t

YUV sampling method.

Values:

enumerator LCD_YUV_SAMPLE_422

YUV 4:2:2 sampling

enumerator LCD_YUV_SAMPLE_420

YUV 4:2:0 sampling

enumerator LCD_YUV_SAMPLE_411

YUV 4:1:1 sampling

enum lcd_yuv_conv_std_t

The standard used for conversion between RGB and YUV.

Values:

enumerator LCD_YUV_CONV_STD_BT601

YUV<->RGB conversion standard: BT.601

enumerator LCD_YUV_CONV_STD_BT709

YUV<->RGB conversion standard: BT.709

Header File

Type Definitions

typedef struct esp_lcd_panel_io_t *esp_lcd_panel_io_handle_t

Type of LCD panel IO handle

typedef struct esp_lcd_panel_t *esp_lcd_panel_handle_t

Type of LCD panel handle

Header File

Functions

esp_err_t esp_lcd_panel_io_rx_param(esp_lcd_panel_io_handle_t io, int lcd_cmd, void *param, size_t param_size)

Transmit LCD command and receive corresponding parameters.

Note

Commands sent by this function are short, so they are sent using polling transactions. The function does not return before the command transfer is completed. If any queued transactions sent by esp_lcd_panel_io_tx_color() are still pending when this function is called, this function will wait until they are finished and the queue is empty before sending the command(s).

Parameters
  • io[in] LCD panel IO handle, which is created by other factory API like esp_lcd_new_panel_io_spi()

  • lcd_cmd[in] The specific LCD command, set to -1 if no command needed

  • param[out] Buffer for the command data

  • param_size[in] Size of param buffer

Returns

  • ESP_ERR_INVALID_ARG if parameter is invalid

  • ESP_ERR_NOT_SUPPORTED if read is not supported by transport

  • ESP_OK on success

esp_err_t esp_lcd_panel_io_tx_param(esp_lcd_panel_io_handle_t io, int lcd_cmd, const void *param, size_t param_size)

Transmit LCD command and corresponding parameters.

Note

Commands sent by this function are short, so they are sent using polling transactions. The function does not return before the command transfer is completed. If any queued transactions sent by esp_lcd_panel_io_tx_color() are still pending when this function is called, this function will wait until they are finished and the queue is empty before sending the command(s).

Parameters
  • io[in] LCD panel IO handle, which is created by other factory API like esp_lcd_new_panel_io_spi()

  • lcd_cmd[in] The specific LCD command (set to -1 if no command needed - only in SPI and I2C)

  • param[in] Buffer that holds the command specific parameters, set to NULL if no parameter is needed for the command

  • param_size[in] Size of param in memory, in bytes, set to zero if no parameter is needed for the command

Returns

  • ESP_ERR_INVALID_ARG if parameter is invalid

  • ESP_OK on success

esp_err_t esp_lcd_panel_io_tx_color(esp_lcd_panel_io_handle_t io, int lcd_cmd, const void *color, size_t color_size)

Transmit LCD RGB data.

Note

This function will package the command and RGB data into a transaction, and push into a queue. The real transmission is performed in the background (DMA+interrupt). The caller should take care of the lifecycle of the color buffer. Recycling of color buffer should be done in the callback on_color_trans_done().

Parameters
  • io[in] LCD panel IO handle, which is created by factory API like esp_lcd_new_panel_io_spi()

  • lcd_cmd[in] The specific LCD command, set to -1 if no command needed

  • color[in] Buffer that holds the RGB color data

  • color_size[in] Size of color in memory, in bytes

Returns

  • ESP_ERR_INVALID_ARG if parameter is invalid

  • ESP_OK on success

esp_err_t esp_lcd_panel_io_del(esp_lcd_panel_io_handle_t io)

Destroy LCD panel IO handle (deinitialize panel and free all corresponding resource)

Parameters

io[in] LCD panel IO handle, which is created by factory API like esp_lcd_new_panel_io_spi()

Returns

  • ESP_ERR_INVALID_ARG if parameter is invalid

  • ESP_OK on success

esp_err_t esp_lcd_new_panel_io_spi(esp_lcd_spi_bus_handle_t bus, const esp_lcd_panel_io_spi_config_t *io_config, esp_lcd_panel_io_handle_t *ret_io)

Create LCD panel IO handle, for SPI interface.

Parameters
  • bus[in] SPI bus handle

  • io_config[in] IO configuration, for SPI interface

  • ret_io[out] Returned IO handle

Returns

  • ESP_ERR_INVALID_ARG if parameter is invalid

  • ESP_ERR_NO_MEM if out of memory

  • ESP_OK on success

esp_err_t esp_lcd_new_panel_io_i2c(esp_lcd_i2c_bus_handle_t bus, const esp_lcd_panel_io_i2c_config_t *io_config, esp_lcd_panel_io_handle_t *ret_io)

Create LCD panel IO handle, for I2C interface.

Parameters
  • bus[in] I2C bus handle

  • io_config[in] IO configuration, for I2C interface

  • ret_io[out] Returned IO handle

Returns

  • ESP_ERR_INVALID_ARG if parameter is invalid

  • ESP_ERR_NO_MEM if out of memory

  • ESP_OK on success

esp_err_t esp_lcd_new_i80_bus(const esp_lcd_i80_bus_config_t *bus_config, esp_lcd_i80_bus_handle_t *ret_bus)

Create Intel 8080 bus handle.

Parameters
  • bus_config[in] Bus configuration

  • ret_bus[out] Returned bus handle

Returns

  • ESP_ERR_INVALID_ARG if parameter is invalid

  • ESP_ERR_NO_MEM if out of memory

  • ESP_ERR_NOT_FOUND if no free bus is available

  • ESP_OK on success

esp_err_t esp_lcd_del_i80_bus(esp_lcd_i80_bus_handle_t bus)

Destroy Intel 8080 bus handle.

Parameters

bus[in] Intel 8080 bus handle, created by esp_lcd_new_i80_bus()

Returns

  • ESP_ERR_INVALID_ARG if parameter is invalid

  • ESP_ERR_INVALID_STATE if there still be some device attached to the bus

  • ESP_OK on success

esp_err_t esp_lcd_new_panel_io_i80(esp_lcd_i80_bus_handle_t bus, const esp_lcd_panel_io_i80_config_t *io_config, esp_lcd_panel_io_handle_t *ret_io)

Create LCD panel IO, for Intel 8080 interface.

Parameters
  • bus[in] Intel 8080 bus handle, created by esp_lcd_new_i80_bus()

  • io_config[in] IO configuration, for i80 interface

  • ret_io[out] Returned panel IO handle

Returns

  • ESP_ERR_INVALID_ARG if parameter is invalid

  • ESP_ERR_NOT_SUPPORTED if some configuration can’t be satisfied, e.g. pixel clock out of the range

  • ESP_ERR_NO_MEM if out of memory

  • ESP_OK on success

Structures

struct esp_lcd_panel_io_event_data_t

Type of LCD panel IO event data.

struct esp_lcd_panel_io_spi_config_t

Panel IO configuration structure, for SPI interface.

Public Members

int cs_gpio_num

GPIO used for CS line

int dc_gpio_num

GPIO used to select the D/C line, set this to -1 if the D/C line is not used

int spi_mode

Traditional SPI mode (0~3)

unsigned int pclk_hz

Frequency of pixel clock

size_t trans_queue_depth

Size of internal transaction queue

esp_lcd_panel_io_color_trans_done_cb_t on_color_trans_done

Callback invoked when color data transfer has finished

void *user_ctx

User private data, passed directly to on_color_trans_done’s user_ctx

int lcd_cmd_bits

Bit-width of LCD command

int lcd_param_bits

Bit-width of LCD parameter

unsigned int dc_low_on_data

If this flag is enabled, DC line = 0 means transfer data, DC line = 1 means transfer command; vice versa

unsigned int octal_mode

transmit with octal mode (8 data lines), this mode is used to simulate Intel 8080 timing

unsigned int sio_mode

Read and write through a single data line (MOSI)

unsigned int lsb_first

transmit LSB bit first

unsigned int cs_high_active

CS line is high active

struct esp_lcd_panel_io_spi_config_t::[anonymous] flags

Extra flags to fine-tune the SPI device

struct esp_lcd_panel_io_i2c_config_t

Panel IO configuration structure, for I2C interface.

Public Members

uint32_t dev_addr

I2C device address

esp_lcd_panel_io_color_trans_done_cb_t on_color_trans_done

Callback invoked when color data transfer has finished

void *user_ctx

User private data, passed directly to on_color_trans_done’s user_ctx

size_t control_phase_bytes

I2C LCD panel will encode control information (e.g. D/C selection) into control phase, in several bytes

unsigned int dc_bit_offset

Offset of the D/C selection bit in control phase

int lcd_cmd_bits

Bit-width of LCD command

int lcd_param_bits

Bit-width of LCD parameter

unsigned int dc_low_on_data

If this flag is enabled, DC line = 0 means transfer data, DC line = 1 means transfer command; vice versa

unsigned int disable_control_phase

If this flag is enabled, the control phase isn’t used

struct esp_lcd_panel_io_i2c_config_t::[anonymous] flags

Extra flags to fine-tune the I2C device

struct esp_lcd_i80_bus_config_t

LCD Intel 8080 bus configuration structure.

Public Members

int dc_gpio_num

GPIO used for D/C line

int wr_gpio_num

GPIO used for WR line

lcd_clock_source_t clk_src

Clock source for the I80 LCD peripheral

int data_gpio_nums[(16)]

GPIOs used for data lines

size_t bus_width

Number of data lines, 8 or 16

size_t max_transfer_bytes

Maximum transfer size, this determines the length of internal DMA link

size_t psram_trans_align

DMA transfer alignment for data allocated from PSRAM

size_t sram_trans_align

DMA transfer alignment for data allocated from SRAM

struct esp_lcd_panel_io_i80_config_t

Panel IO configuration structure, for intel 8080 interface.

Public Members

int cs_gpio_num

GPIO used for CS line, set to -1 will declaim exclusively use of I80 bus

uint32_t pclk_hz

Frequency of pixel clock

size_t trans_queue_depth

Transaction queue size, larger queue, higher throughput

esp_lcd_panel_io_color_trans_done_cb_t on_color_trans_done

Callback invoked when color data was transferred done

void *user_ctx

User private data, passed directly to on_color_trans_done’s user_ctx

int lcd_cmd_bits

Bit-width of LCD command

int lcd_param_bits

Bit-width of LCD parameter

unsigned int dc_idle_level

Level of DC line in IDLE phase

unsigned int dc_cmd_level

Level of DC line in CMD phase

unsigned int dc_dummy_level

Level of DC line in DUMMY phase

unsigned int dc_data_level

Level of DC line in DATA phase

struct esp_lcd_panel_io_i80_config_t::[anonymous] dc_levels

Each i80 device might have its own D/C control logic

unsigned int cs_active_high

If set, a high level of CS line will select the device, otherwise, CS line is low level active

unsigned int reverse_color_bits

Reverse the data bits, D[N:0] -> D[0:N]

unsigned int swap_color_bytes

Swap adjacent two color bytes

unsigned int pclk_active_neg

The display will write data lines when there’s a falling edge on WR signal (a.k.a the PCLK)

unsigned int pclk_idle_low

The WR signal (a.k.a the PCLK) stays at low level in IDLE phase

struct esp_lcd_panel_io_i80_config_t::[anonymous] flags

Panel IO config flags

Type Definitions

typedef void *esp_lcd_spi_bus_handle_t

Type of LCD SPI bus handle

typedef void *esp_lcd_i2c_bus_handle_t

Type of LCD I2C bus handle

typedef struct esp_lcd_i80_bus_t *esp_lcd_i80_bus_handle_t

Type of LCD intel 8080 bus handle

typedef bool (*esp_lcd_panel_io_color_trans_done_cb_t)(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx)

Declare the prototype of the function that will be invoked when panel IO finishes transferring color data.

Param panel_io

[in] LCD panel IO handle, which is created by factory API like esp_lcd_new_panel_io_spi()

Param edata

[in] Panel IO event data, fed by driver

Param user_ctx

[in] User data, passed from esp_lcd_panel_io_xxx_config_t

Return

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

Header File

Functions

esp_err_t esp_lcd_panel_reset(esp_lcd_panel_handle_t panel)

Reset LCD panel.

Note

Panel reset must be called before attempting to initialize the panel using esp_lcd_panel_init().

Parameters

panel[in] LCD panel handle, which is created by other factory API like esp_lcd_new_panel_st7789()

Returns

  • ESP_OK on success

esp_err_t esp_lcd_panel_init(esp_lcd_panel_handle_t panel)

Initialize LCD panel.

Note

Before calling this function, make sure the LCD panel has finished the reset stage by esp_lcd_panel_reset().

Parameters

panel[in] LCD panel handle, which is created by other factory API like esp_lcd_new_panel_st7789()

Returns

  • ESP_OK on success

esp_err_t esp_lcd_panel_del(esp_lcd_panel_handle_t panel)

Deinitialize the LCD panel.

Parameters

panel[in] LCD panel handle, which is created by other factory API like esp_lcd_new_panel_st7789()

Returns

  • ESP_OK on success

esp_err_t esp_lcd_panel_draw_bitmap(esp_lcd_panel_handle_t panel, int x_start, int y_start, int x_end, int y_end, const void *color_data)

Draw bitmap on LCD panel.

Parameters
  • panel[in] LCD panel handle, which is created by other factory API like esp_lcd_new_panel_st7789()

  • x_start[in] Start index on x-axis (x_start included)

  • y_start[in] Start index on y-axis (y_start included)

  • x_end[in] End index on x-axis (x_end not included)

  • y_end[in] End index on y-axis (y_end not included)

  • color_data[in] RGB color data that will be dumped to the specific window range

Returns

  • ESP_OK on success

esp_err_t esp_lcd_panel_mirror(esp_lcd_panel_handle_t panel, bool mirror_x, bool mirror_y)

Mirror the LCD panel on specific axis.

Note

Combined with esp_lcd_panel_swap_xy(), one can realize screen rotation

Parameters
  • panel[in] LCD panel handle, which is created by other factory API like esp_lcd_new_panel_st7789()

  • mirror_x[in] Whether the panel will be mirrored about the x axis

  • mirror_y[in] Whether the panel will be mirrored about the y axis

Returns

  • ESP_OK on success

  • ESP_ERR_NOT_SUPPORTED if this function is not supported by the panel

esp_err_t esp_lcd_panel_swap_xy(esp_lcd_panel_handle_t panel, bool swap_axes)

Swap/Exchange x and y axis.

Note

Combined with esp_lcd_panel_mirror(), one can realize screen rotation

Parameters
  • panel[in] LCD panel handle, which is created by other factory API like esp_lcd_new_panel_st7789()

  • swap_axes[in] Whether to swap the x and y axis

Returns

  • ESP_OK on success

  • ESP_ERR_NOT_SUPPORTED if this function is not supported by the panel

esp_err_t esp_lcd_panel_set_gap(esp_lcd_panel_handle_t panel, int x_gap, int y_gap)

Set extra gap in x and y axis.

The gap is the space (in pixels) between the left/top sides of the LCD panel and the first row/column respectively of the actual contents displayed.

Note

Setting a gap is useful when positioning or centering a frame that is smaller than the LCD.

Parameters
  • panel[in] LCD panel handle, which is created by other factory API like esp_lcd_new_panel_st7789()

  • x_gap[in] Extra gap on x axis, in pixels

  • y_gap[in] Extra gap on y axis, in pixels

Returns

  • ESP_OK on success

esp_err_t esp_lcd_panel_invert_color(esp_lcd_panel_handle_t panel, bool invert_color_data)

Invert the color (bit-wise invert the color data line)

Parameters
  • panel[in] LCD panel handle, which is created by other factory API like esp_lcd_new_panel_st7789()

  • invert_color_data[in] Whether to invert the color data

Returns

  • ESP_OK on success

esp_err_t esp_lcd_panel_disp_on_off(esp_lcd_panel_handle_t panel, bool on_off)

Turn on or off the display.

Parameters
  • panel[in] LCD panel handle, which is created by other factory API like esp_lcd_new_panel_st7789()

  • on_off[in] True to turns on display, False to turns off display

Returns

  • ESP_OK on success

  • ESP_ERR_NOT_SUPPORTED if this function is not supported by the panel

esp_err_t esp_lcd_panel_disp_off(esp_lcd_panel_handle_t panel, bool off)

Turn off the display.

Parameters
  • panel[in] LCD panel handle, which is created by other factory API like esp_lcd_new_panel_st7789()

  • off[in] Whether to turn off the screen

Returns

  • ESP_OK on success

  • ESP_ERR_NOT_SUPPORTED if this function is not supported by the panel

Header File

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

esp_err_t esp_lcd_rgb_panel_set_yuv_conversion(esp_lcd_panel_handle_t panel, const esp_lcd_yuv_conv_config_t *config)

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

Note

Pass in config as NULL will disable the RGB-YUV converter.

Note

The hardware converter can only parse a “packed” storage format, while “planar” and “semi-planar” format is not supported.

Parameters
  • panel[in] LCD panel handle, returned from esp_lcd_new_rgb_panel

  • config[in] Configuration of RGB-YUV conversion

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|      |         |/ / / / / / / / / / / / / / / / / / / /|    |
*             |Heigh |      |         |/ / / / / / 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::[anonymous] 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_vsync_cb_t on_vsync

VSYNC event callback

esp_lcd_rgb_panel_bounce_buf_fill_cb_t on_bounce_empty

Bounce buffer empty callback.

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

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

size_t psram_trans_align

Alignment of buffers (frame buffer) that allocated in PSRAM

int hsync_gpio_num

GPIO used for HSYNC signal

int vsync_gpio_num

GPIO used for VSYNC signal

int de_gpio_num

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

int pclk_gpio_num

GPIO used for PCLK signal

int disp_gpio_num

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

int data_gpio_nums[(16)]

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

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

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::[anonymous] flags

LCD RGB panel configuration flags

struct esp_lcd_color_conv_profile_t

LCD color conversion profile.

Public Members

lcd_color_space_t color_space

Color space of the image

lcd_color_range_t color_range

Color range of the image

lcd_yuv_sample_t yuv_sample

YUV sample format of the image

struct esp_lcd_yuv_conv_config_t

Configuration of YUG-RGB conversion.

Public Members

lcd_yuv_conv_std_t std

YUV conversion standard: BT601, BT709

esp_lcd_color_conv_profile_t src

Color conversion profile of the input image

esp_lcd_color_conv_profile_t dst

Color conversion profile of the output image

Type Definitions

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

RGB LCD VSYNC event callback prototype.

Param panel

[in] LCD panel handle, returned from esp_lcd_new_rgb_panel()

Param edata

[in] Panel event data, fed 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 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

Header File

Functions

esp_err_t esp_lcd_new_panel_st7789(const esp_lcd_panel_io_handle_t io, const esp_lcd_panel_dev_config_t *panel_dev_config, esp_lcd_panel_handle_t *ret_panel)

Create LCD panel for model ST7789.

Parameters
  • io[in] LCD panel IO handle

  • panel_dev_config[in] general panel device configuration

  • ret_panel[out] Returned LCD panel handle

Returns

  • ESP_ERR_INVALID_ARG if parameter is invalid

  • ESP_ERR_NO_MEM if out of memory

  • ESP_OK on success

esp_err_t esp_lcd_new_panel_nt35510(const esp_lcd_panel_io_handle_t io, const esp_lcd_panel_dev_config_t *panel_dev_config, esp_lcd_panel_handle_t *ret_panel)

Create LCD panel for model NT35510.

Parameters
  • io[in] LCD panel IO handle

  • panel_dev_config[in] general panel device configuration

  • ret_panel[out] Returned LCD panel handle

Returns

  • ESP_ERR_INVALID_ARG if parameter is invalid

  • ESP_ERR_NO_MEM if out of memory

  • ESP_OK on success

esp_err_t esp_lcd_new_panel_ssd1306(const esp_lcd_panel_io_handle_t io, const esp_lcd_panel_dev_config_t *panel_dev_config, esp_lcd_panel_handle_t *ret_panel)

Create LCD panel for model SSD1306.

Parameters
  • io[in] LCD panel IO handle

  • panel_dev_config[in] general panel device configuration

  • ret_panel[out] Returned LCD panel handle

Returns

  • ESP_ERR_INVALID_ARG if parameter is invalid

  • ESP_ERR_NO_MEM if out of memory

  • ESP_OK on success

Structures

struct esp_lcd_panel_dev_config_t

Configuration structure for panel device.

Public Members

int reset_gpio_num

GPIO used to reset the LCD panel, set to -1 if it’s not used

lcd_color_rgb_endian_t color_space

Deprecated:

Set RGB color space, please use rgb_endian instead

lcd_color_rgb_endian_t rgb_endian

Set RGB data endian: RGB or BGR

unsigned int bits_per_pixel

Color depth, in bpp

unsigned int reset_active_high

Setting this if the panel reset is high level active

struct esp_lcd_panel_dev_config_t::[anonymous] flags

LCD panel config flags

void *vendor_config

vendor specific configuration, optional, left as NULL if not used