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 and the hardware connection interface, the LCD panel drivers are mainly grouped into the following categories:

  • Controller based LCD driver involves multiple steps to get a panel handle, like bus allocation, IO device registration and controller driver install. The frame buffer is located in the controller’s internal GRAM (Graphical RAM). ESP-IDF provides only a limited number of LCD controller drivers out of the box (e.g. ST7789, SSD1306), More Controller Based LCD Drivers are maintained in the Espressif Component Registry <https://components.espressif.com/>_.

  • SPI Interfaced LCD describes the steps to install the SPI LCD IO driver and then get the panel handle.

  • I2C Interfaced LCD describes the steps to install the I2C LCD IO driver and then get the panel handle.

  • LCD Panel IO Operations - provides a set of APIs to operate the LCD panel, like turning on/off the display, setting the orientation, etc. These operations are common for either controller-based LCD panel driver or RGB LCD panel driver.

SPI Interfaced LCD

  1. Create an SPI bus. Please refer to SPI Master API doc for more details.

    spi_bus_config_t buscfg = {
        .sclk_io_num = EXAMPLE_PIN_NUM_SCLK,
        .mosi_io_num = EXAMPLE_PIN_NUM_MOSI,
        .miso_io_num = EXAMPLE_PIN_NUM_MISO,
        .quadwp_io_num = -1, // Quad SPI LCD driver is not yet supported
        .quadhd_io_num = -1, // Quad SPI LCD driver is not yet supported
        .max_transfer_sz = EXAMPLE_LCD_H_RES * 80 * sizeof(uint16_t), // transfer 80 lines of pixels (assume pixel is RGB565) at most in one SPI transaction
    };
    ESP_ERROR_CHECK(spi_bus_initialize(LCD_HOST, &buscfg, SPI_DMA_CH_AUTO)); // Enable the DMA feature
    
  2. Allocate an LCD IO device handle from the SPI bus. In this step, you need to provide the following information:

    esp_lcd_panel_io_handle_t io_handle = NULL;
    esp_lcd_panel_io_spi_config_t io_config = {
        .dc_gpio_num = EXAMPLE_PIN_NUM_LCD_DC,
        .cs_gpio_num = EXAMPLE_PIN_NUM_LCD_CS,
        .pclk_hz = EXAMPLE_LCD_PIXEL_CLOCK_HZ,
        .lcd_cmd_bits = EXAMPLE_LCD_CMD_BITS,
        .lcd_param_bits = EXAMPLE_LCD_PARAM_BITS,
        .spi_mode = 0,
        .trans_queue_depth = 10,
    };
    // Attach the LCD to the SPI bus
    ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_HOST, &io_config, &io_handle));
    
  3. Install the LCD controller driver. The LCD controller driver is responsible for sending the commands and parameters to the LCD controller chip. In this step, you need to specify the SPI IO device handle that allocated in the last step, and some panel specific configurations:

    esp_lcd_panel_handle_t panel_handle = NULL;
    esp_lcd_panel_dev_config_t panel_config = {
        .reset_gpio_num = EXAMPLE_PIN_NUM_RST,
        .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_BGR,
        .bits_per_pixel = 16,
    };
    // Create LCD panel handle for ST7789, with the SPI IO device handle
    ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle));
    

I2C Interfaced LCD

  1. Create I2C bus. Please refer to I2C API doc for more details.

    i2c_config_t i2c_conf = {
        .mode = I2C_MODE_MASTER, // I2C LCD is a master node
        .sda_io_num = EXAMPLE_PIN_NUM_SDA,
        .scl_io_num = EXAMPLE_PIN_NUM_SCL,
        .sda_pullup_en = GPIO_PULLUP_ENABLE,
        .scl_pullup_en = GPIO_PULLUP_ENABLE,
        .master.clk_speed = EXAMPLE_LCD_PIXEL_CLOCK_HZ,
    };
    ESP_ERROR_CHECK(i2c_param_config(I2C_HOST, &i2c_conf));
    ESP_ERROR_CHECK(i2c_driver_install(I2C_HOST, I2C_MODE_MASTER, 0, 0, 0));
    
  2. Allocate an LCD IO device handle from the I2C bus. In this step, you need to provide the following information:

    esp_lcd_panel_io_handle_t io_handle = NULL;
    esp_lcd_panel_io_i2c_config_t io_config = {
        .dev_addr = EXAMPLE_I2C_HW_ADDR,
        .control_phase_bytes = 1, // refer to LCD spec
        .dc_bit_offset = 6,       // refer to LCD spec
        .lcd_cmd_bits = EXAMPLE_LCD_CMD_BITS,
        .lcd_param_bits = EXAMPLE_LCD_CMD_BITS,
    };
    ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)I2C_HOST, &io_config, &io_handle));
    
  3. Install the LCD controller driver. The LCD controller driver is responsible for sending the commands and parameters to the LCD controller chip. In this step, you need to specify the I2C IO device handle that allocated in the last step, and some panel specific configurations:

    esp_lcd_panel_handle_t panel_handle = NULL;
    esp_lcd_panel_dev_config_t panel_config = {
        .bits_per_pixel = 1,
        .reset_gpio_num = EXAMPLE_PIN_NUM_RST,
    };
    ESP_ERROR_CHECK(esp_lcd_new_panel_ssd1306(io_handle, &panel_config, &panel_handle));
    

More Controller Based LCD Drivers

More LCD panel drivers and touch drivers are available in IDF Component Registry. The list of available and planned drivers with links is in this table.

LCD Panel IO Operations

Application Example

LCD examples are located under: peripherals/lcd:

API Reference

Header File

Macros

LCD_RGB_ENDIAN_RGB
LCD_RGB_ENDIAN_BGR

Type Definitions

typedef lcd_rgb_element_order_t lcd_color_rgb_endian_t

for backward compatible

Enumerations

enum lcd_rgb_element_order_t

RGB color endian.

Values:

enumerator LCD_RGB_ELEMENT_ORDER_RGB

RGB element order: RGB

enumerator LCD_RGB_ELEMENT_ORDER_BGR

RGB element order: BGR

enum lcd_rgb_data_endian_t

RGB data endian.

Values:

enumerator LCD_RGB_DATA_ENDIAN_BIG

RGB data endian: MSB first

enumerator LCD_RGB_DATA_ENDIAN_LITTLE

RGB data endian: LSB first

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

  • 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_panel_io_register_event_callbacks(esp_lcd_panel_io_handle_t io, const esp_lcd_panel_io_callbacks_t *cbs, void *user_ctx)

Register LCD panel IO callbacks.

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

  • cbs[in] structure with all LCD panel IO callbacks

  • user_ctx[in] User private data, passed directly to callback’s user_ctx

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

Structures

struct esp_lcd_panel_io_event_data_t

Type of LCD panel IO event data.

struct esp_lcd_panel_io_callbacks_t

Type of LCD panel IO callbacks.

Public Members

esp_lcd_panel_io_color_trans_done_cb_t on_color_trans_done

Callback invoked when color data transfer has finished

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_high_on_cmd

If enabled, DC level = 1 indicates command transfer

unsigned int dc_low_on_data

If enabled, DC level = 0 indicates color data transfer

unsigned int dc_low_on_param

If enabled, DC level = 0 indicates parameter transfer

unsigned int octal_mode

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

unsigned int quad_mode

transmit with quad mode (4 data lines), this mode is useful when transmitting LCD parameters (Only use one line for command)

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

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

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

Deprecated:

Set RGB color space, please use rgb_ele_order instead

lcd_rgb_element_order_t rgb_endian

Deprecated:

Set RGB data endian, please use rgb_ele_order instead

lcd_rgb_element_order_t rgb_ele_order

Set RGB element order, RGB or BGR

lcd_rgb_data_endian_t data_endian

Set the data endian for color data larger than 1 byte

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