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.
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.
I80 Interfaced LCD describes the steps to install the I80 LCD IO driver and then get the panel handle.
RGB Interfaced LCD - is based on a group of specific synchronous signals indicating where to start and stop a frame. The frame buffer is allocated on the ESP side. The driver install steps are much simplified because we do not need to install any IO interface driver in this case.
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
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
Allocate an LCD IO device handle from the SPI bus. In this step, you need to provide the following information:
esp_lcd_panel_io_spi_config_t::dc_gpio_num
: Sets the gpio number for the DC signal line (some LCD calls thisRS
line). The LCD driver uses this GPIO to switch between sending command and sending data.esp_lcd_panel_io_spi_config_t::cs_gpio_num
: Sets the gpio number for the CS signal line. The LCD driver uses this GPIO to select the LCD chip. If the SPI bus only has one device attached (i.e., this LCD), you can set the gpio number to-1
to occupy the bus exclusively.esp_lcd_panel_io_spi_config_t::pclk_hz
sets the frequency of the pixel clock, in Hz. The value should not exceed the range recommended in the LCD spec.esp_lcd_panel_io_spi_config_t::spi_mode
sets the SPI mode. The LCD driver uses this mode to communicate with the LCD. For the meaning of the SPI mode, please refer to the SPI Master API doc.esp_lcd_panel_io_spi_config_t::lcd_cmd_bits
andesp_lcd_panel_io_spi_config_t::lcd_param_bits
set the bit width of the command and parameter that recognized by the LCD controller chip. This is chip specific, you should refer to your LCD spec in advance.esp_lcd_panel_io_spi_config_t::trans_queue_depth
sets the depth of the SPI transaction queue. A bigger value means more transactions can be queued up, but it also consumes more memory.
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));
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_dev_config_t::reset_gpio_num
sets the LCD's hardware reset GPIO number. If the LCD does not have a hardware reset pin, set this to-1
.esp_lcd_panel_dev_config_t::rgb_ele_order
sets the R-G-B element order of each color data.esp_lcd_panel_dev_config_t::bits_per_pixel
sets the bit width of the pixel color data. The LCD driver uses this value to calculate the number of bytes to send to the LCD controller chip.esp_lcd_panel_dev_config_t::data_endian
specifies the data endian to be transmitted to the screen. No need to specify for color data within 1 byte, like RGB232. For drivers that do not support specifying data endian, this field would be ignored.
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
Create I2C bus. Please refer to I2C API doc for more details.
i2c_master_bus_handle_t i2c_bus = NULL; i2c_master_bus_config_t bus_config = { .clk_source = I2C_CLK_SRC_DEFAULT, .glitch_ignore_cnt = 7, .i2c_port = I2C_BUS_PORT, .sda_io_num = EXAMPLE_PIN_NUM_SDA, .scl_io_num = EXAMPLE_PIN_NUM_SCL, .flags.enable_internal_pullup = true, }; ESP_ERROR_CHECK(i2c_new_master_bus(&bus_config, &i2c_bus));
Allocate an LCD IO device handle from the I2C bus. In this step, you need to provide the following information:
esp_lcd_panel_io_i2c_config_t::dev_addr
sets the I2C device address of the LCD controller chip. The LCD driver uses this address to communicate with the LCD controller chip.esp_lcd_panel_io_i2c_config_t::scl_speed_hz
sets the I2C clock frequency in Hz. The value should not exceed the range recommended in the LCD spec.esp_lcd_panel_io_i2c_config_t::lcd_cmd_bits
andesp_lcd_panel_io_i2c_config_t::lcd_param_bits
set the bit width of the command and parameter that recognized by the LCD controller chip. This is chip specific, you should refer to your LCD spec in advance.
esp_lcd_panel_io_handle_t io_handle = NULL; esp_lcd_panel_io_i2c_config_t io_config = { .dev_addr = EXAMPLE_I2C_HW_ADDR, .scl_speed_hz = EXAMPLE_LCD_PIXEL_CLOCK_HZ, .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(i2c_bus, &io_config, &io_handle));
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_dev_config_t::reset_gpio_num
sets the LCD's hardware reset GPIO number. If the LCD does not have a hardware reset pin, set this to-1
.esp_lcd_panel_dev_config_t::bits_per_pixel
sets the bit width of the pixel color data. The LCD driver uses this value to calculate the number of bytes to send to the LCD controller chip.
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));
I80 Interfaced LCD
Create I80 bus by
esp_lcd_new_i80_bus()
. You need to set up the following parameters for an Intel 8080 parallel bus:esp_lcd_i80_bus_config_t::clk_src
sets the clock source of the I80 bus. Note, the default clock source may be different between ESP targets.esp_lcd_i80_bus_config_t::wr_gpio_num
sets the GPIO number of the pixel clock (also referred asWR
in some LCD spec)esp_lcd_i80_bus_config_t::dc_gpio_num
sets the GPIO number of the data/command select pin (also referred asRS
in some LCD spec)esp_lcd_i80_bus_config_t::bus_width
sets the bit width of the data bus (only support8
or16
)esp_lcd_i80_bus_config_t::data_gpio_nums
is the array of the GPIO number of the data bus. The number of GPIOs should be equal to theesp_lcd_i80_bus_config_t::bus_width
value.esp_lcd_i80_bus_config_t::max_transfer_bytes
sets the maximum number of bytes that can be transferred in one transaction.
esp_lcd_i80_bus_handle_t i80_bus = NULL; esp_lcd_i80_bus_config_t bus_config = { .clk_src = LCD_CLK_SRC_DEFAULT, .dc_gpio_num = EXAMPLE_PIN_NUM_DC, .wr_gpio_num = EXAMPLE_PIN_NUM_PCLK, .data_gpio_nums = { EXAMPLE_PIN_NUM_DATA0, EXAMPLE_PIN_NUM_DATA1, EXAMPLE_PIN_NUM_DATA2, EXAMPLE_PIN_NUM_DATA3, EXAMPLE_PIN_NUM_DATA4, EXAMPLE_PIN_NUM_DATA5, EXAMPLE_PIN_NUM_DATA6, EXAMPLE_PIN_NUM_DATA7, }, .bus_width = 8, .max_transfer_bytes = EXAMPLE_LCD_H_RES * 100 * sizeof(uint16_t), // transfer 100 lines of pixels (assume pixel is RGB565) at most in one transaction .psram_trans_align = EXAMPLE_PSRAM_DATA_ALIGNMENT, .sram_trans_align = 4, }; ESP_ERROR_CHECK(esp_lcd_new_i80_bus(&bus_config, &i80_bus));
Allocate an LCD IO device handle from the I80 bus. In this step, you need to provide the following information:
esp_lcd_panel_io_i80_config_t::cs_gpio_num
sets the GPIO number of the chip select pin.esp_lcd_panel_io_i80_config_t::pclk_hz
sets the pixel clock frequency in Hz. Higher pixel clock frequency results in higher refresh rate, but may cause flickering if the DMA bandwidth is not sufficient or the LCD controller chip does not support high pixel clock frequency.esp_lcd_panel_io_i80_config_t::lcd_cmd_bits
andesp_lcd_panel_io_i80_config_t::lcd_param_bits
set the bit width of the command and parameter that recognized by the LCD controller chip. This is chip specific, you should refer to your LCD spec in advance.esp_lcd_panel_io_i80_config_t::trans_queue_depth
sets the maximum number of transactions that can be queued in the LCD IO device. A bigger value means more transactions can be queued up, but it also consumes more memory.
esp_lcd_panel_io_handle_t io_handle = NULL; esp_lcd_panel_io_i80_config_t io_config = { .cs_gpio_num = EXAMPLE_PIN_NUM_CS, .pclk_hz = EXAMPLE_LCD_PIXEL_CLOCK_HZ, .trans_queue_depth = 10, .dc_levels = { .dc_idle_level = 0, .dc_cmd_level = 0, .dc_dummy_level = 0, .dc_data_level = 1, }, .lcd_cmd_bits = EXAMPLE_LCD_CMD_BITS, .lcd_param_bits = EXAMPLE_LCD_PARAM_BITS, }; ESP_ERROR_CHECK(esp_lcd_new_panel_io_i80(i80_bus, &io_config, &io_handle));
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 I80 IO device handle that allocated in the last step, and some panel specific configurations:
esp_lcd_panel_dev_config_t::bits_per_pixel
sets the bit width of the pixel color data. The LCD driver uses this value to calculate the number of bytes to send to the LCD controller chip.esp_lcd_panel_dev_config_t::reset_gpio_num
sets the GPIO number of the reset pin. If the LCD controller chip does not have a reset pin, you can set this value to-1
.esp_lcd_panel_dev_config_t::rgb_ele_order
sets the color order the pixel color data.
esp_lcd_panel_dev_config_t panel_config = { .reset_gpio_num = EXAMPLE_PIN_NUM_RST, .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB, .bits_per_pixel = 16, }; ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle));
More Controller Based LCD Drivers
More LCD panel drivers and touch drivers are available in ESP-IDF Component Registry. The list of available and planned drivers with links is in this table.
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
.
esp_lcd_rgb_panel_config_t::clk_src
selects the clock source for the RGB LCD controller. The available clock sources are listed inlcd_clock_source_t
.esp_lcd_rgb_panel_config_t::data_width
set number of data lines used by the RGB interface. Currently, the supported value can be 8 or 16.esp_lcd_rgb_panel_config_t::bits_per_pixel
set the number of bits per pixel. This is different fromesp_lcd_rgb_panel_config_t::data_width
. By default, if you set this field to 0, the driver will automatically adjust the bpp to theesp_lcd_rgb_panel_config_t::data_width
. But in some cases, these two value must be different. For example, a Serial RGB interface LCD only needs8
data lines, but the color width can reach toRGB888
, i.e., theesp_lcd_rgb_panel_config_t::bits_per_pixel
should be set to24
.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
andesp_lcd_rgb_panel_config_t::data_gpio_nums
are the GPIO pins used by the RGB LCD controller. If some of them are not used, please set it to -1.esp_lcd_rgb_panel_config_t::sram_trans_align
andesp_lcd_rgb_panel_config_t::psram_trans_align
set the alignment of the allocated frame buffer. Internally, the DMA transfer ability will adjust against these alignment values. A higher alignment value can lead to a bigger DMA burst size. Please note, the alignment value must be a power of 2.esp_lcd_rgb_panel_config_t::bounce_buffer_size_px
set the size of bounce buffer. This is only necessary for a so-called "bounce buffer" mode. Please refer to Bounce Buffer with Single PSRAM Frame Buffer for more information.esp_lcd_rgb_panel_config_t::timings
sets the LCD panel specific timing parameters. All required parameters are listed in theesp_lcd_rgb_timing_t
, including the LCD resolution and blanking porches. Please fill them according to the datasheet of your LCD.esp_lcd_rgb_panel_config_t::fb_in_psram
sets whether to allocate the frame buffer from PSRAM or not. Please refer to Single Frame Buffer in PSRAM for more information.esp_lcd_rgb_panel_config_t::num_fbs
sets the number of frame buffers allocated by the driver. For backward compatibility,0
means to allocateone
frame buffer. Please useesp_lcd_rgb_panel_config_t::no_fb
if you do not want to allocate any frame buffer.esp_lcd_rgb_panel_config_t::no_fb
if sets, no frame buffer will be allocated. This is also called the Bounce Buffer Only mode.
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 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 get the other half. If there are 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.
The PSRAM shares the same SPI bus with the main Flash (the one stores your firmware binary). At one time, there only be one consumer of the SPI bus. When you also use the main flash to serve your file system (e.g., SPIFFS), the bandwidth of the underlying SPI bus will also be shared, leading to display corruption. You can use esp_lcd_rgb_panel_set_pclk()
to update the pixel clock frequency to a lower value.
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
.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));
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 uses DMA to read data from one of the bounce buffers, and meanwhile 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 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 NOT work if we disable the cache of the external memory, via e.g., OTA or NVS write to the main flash.
Note
It is highly recommended to turn on the "PSRAM XIP (Execute In Place)" feature in this mode by enabling the Kconfig options: CONFIG_SPIRAM_FETCH_INSTRUCTIONS and CONFIG_SPIRAM_RODATA, which allows the CPU to fetch instructions and readonly data from the PSRAM instead of the main flash. What is more, the external memory cache will not be disabled even if you attempt to write to the main flash through SPI1. This makes it possible to display an OTA progress bar for your application.
Note
This mode still has another problem which is also caused by insufficient PSRAM bandwidth. e.g., when your draw buffers are allocated from PSRAM, and their contents are copied into the internal frame buffer on CPU core 1. On CPU core 0, there is another memory copy happening in the DMA EOF ISR. In this situation, both CPUs are accessing the PSRAM by cache and sharing the bandwidth of the PSRAM. This increases the memory copy time that spent in the DMA EOF ISR significantly. The driver can not switch the bounce buffer in time, thus leading to a shift on the LCD screen. Although the driver can detect such a condition and perform a restart in the LCD's VSYNC interrupt handler, you still can see a 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 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 are 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 either enable the CONFIG_LCD_RGB_RESTART_IN_VSYNC option, so the driver can restart the DMA in the VBlank interrupt automatically or call esp_lcd_rgb_panel_restart()
to restart the DMA manually. Note esp_lcd_rgb_panel_restart()
does not restart the DMA immediately, the DMA is still restarted in the next VSYNC event.
LCD Panel IO Operations
esp_lcd_panel_reset()
can reset the LCD panel.esp_lcd_panel_init()
performs a basic initialization of the panel. To perform more manufacture specific initialization, please go to Steps to Add Manufacture Specific Initialization.Through combined use of
esp_lcd_panel_swap_xy()
andesp_lcd_panel_mirror()
, you can rotate the LCD screen.esp_lcd_panel_disp_on_off()
can turn on or off the LCD screen by cutting down the output path from the frame buffer to the LCD screen.esp_lcd_panel_disp_sleep()
can reduce the power consumption of the LCD screen by entering the sleep mode. The internal frame buffer is still retained.esp_lcd_panel_draw_bitmap()
is the most significant function, which does the magic to draw the user provided color buffer to the LCD screen, where the draw window is also configurable.
Steps to Add Manufacture Specific Initialization
The LCD controller drivers (e.g., st7789) in esp-idf only provide basic initialization in the esp_lcd_panel_init()
, leaving the vast majority of settings to the default values. Some LCD modules needs to set a bunch of manufacture specific configurations before it can display normally. These configurations usually include gamma, power voltage and so on. If you want to add manufacture specific initialization, please follow the steps below:
esp_lcd_panel_reset(panel_handle);
esp_lcd_panel_init(panel_handle);
// set extra configurations e.g., gamma control
// with the underlying IO handle
// please consult your manufacture for special commands and corresponding values
esp_lcd_panel_io_tx_param(io_handle, GAMMA_CMD, (uint8_t[]) {
GAMMA_ARRAY
}, N);
// turn on the display
esp_lcd_panel_disp_on_off(panel_handle, true);
Application Example
LCD examples are located under: peripherals/lcd:
Universal SPI LCD example with SPI touch - peripherals/lcd/spi_lcd_touch
Jpeg decoding and LCD display - peripherals/lcd/tjpgd
i80 controller based LCD and LVGL animation UI - peripherals/lcd/i80_controller
RGB panel example with scatter chart UI - peripherals/lcd/rgb_panel
I2C interfaced OLED display scrolling text - peripherals/lcd/i2c_oled
API Reference
Header File
This header file can be included with:
#include "hal/lcd_types.h"
Macros
-
LCD_RGB_ENDIAN_RGB
-
LCD_RGB_ENDIAN_BGR
Type Definitions
-
typedef soc_periph_lcd_clk_src_t lcd_clock_source_t
LCD clock source.
-
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
-
enumerator LCD_RGB_ELEMENT_ORDER_RGB
-
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
-
enumerator LCD_RGB_DATA_ENDIAN_BIG
-
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
-
enumerator LCD_COLOR_SPACE_RGB
-
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
-
enumerator LCD_COLOR_RANGE_LIMIT
Header File
This header file can be included with:
#include "esp_lcd_types.h"
This header file is a part of the API provided by the
esp_lcd
component. To declare that your component depends onesp_lcd
, add the following to your CMakeLists.txt:REQUIRES esp_lcd
or
PRIV_REQUIRES esp_lcd
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
This header file can be included with:
#include "esp_lcd_panel_io.h"
This header file is a part of the API provided by the
esp_lcd
component. To declare that your component depends onesp_lcd
, add the following to your CMakeLists.txt:REQUIRES esp_lcd
or
PRIV_REQUIRES esp_lcd
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 callbackon_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_v1(uint32_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 in legacy implementation.
Note
Please don't call this function in your project directly. Please call
esp_lcd_new_panel_to_i2c
instead.- Parameters
bus -- [in] I2C bus handle, (in uint32_t)
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_panel_io_i2c_v2(i2c_master_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 in new implementation.
Note
Please don't call this function in your project directly. Please call
esp_lcd_new_panel_to_i2c
instead.- Parameters
bus -- [in] I2C bus handle, (in i2c_master_dev_handle_t)
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_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
-
esp_lcd_panel_io_color_trans_done_cb_t on_color_trans_done
-
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
-
int cs_gpio_num
-
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
-
uint32_t scl_speed_hz
I2C LCD SCL frequency (hz)
-
uint32_t dev_addr
-
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
-
int dc_gpio_num
-
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
-
int cs_gpio_num
Macros
-
esp_lcd_new_panel_io_i2c(bus, io_config, ret_io)
Create LCD panel IO handle.
- 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
Type Definitions
-
typedef void *esp_lcd_spi_bus_handle_t
Type of LCD SPI bus handle
-
typedef uint32_t 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
This header file can be included with:
#include "esp_lcd_panel_ops.h"
This header file is a part of the API provided by the
esp_lcd
component. To declare that your component depends onesp_lcd
, add the following to your CMakeLists.txt:REQUIRES esp_lcd
or
PRIV_REQUIRES esp_lcd
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 byesp_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
-
esp_err_t esp_lcd_panel_disp_sleep(esp_lcd_panel_handle_t panel, bool sleep)
Enter or exit sleep mode.
- Parameters
panel -- [in] LCD panel handle, which is created by other factory API like
esp_lcd_new_panel_st7789()
sleep -- [in] True to enter sleep mode, False to wake up
- Returns
ESP_OK on success
ESP_ERR_NOT_SUPPORTED if this function is not supported by the panel
Header File
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 onesp_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
-
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
-
uint32_t pclk_hz
-
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.
-
esp_lcd_rgb_panel_bounce_buf_finish_cb_t on_bounce_frame_finish
Bounce buffer finish callback.
-
esp_lcd_rgb_panel_vsync_cb_t on_vsync
-
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 fromdata_width
-
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
-
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, set to -1 if it's not used
-
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, 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::[anonymous] flags
LCD RGB panel configuration flags
-
lcd_clock_source_t clk_src
-
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
-
lcd_color_space_t color_space
-
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
-
lcd_yuv_conv_std_t std
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
-
typedef bool (*esp_lcd_rgb_panel_bounce_buf_finish_cb_t)(esp_lcd_panel_handle_t panel, const esp_lcd_rgb_panel_event_data_t *edata, void *user_ctx)
Prototype for the function to be called when the bounce buffer finish copying the entire frame.
- 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
Header File
This header file can be included with:
#include "esp_lcd_panel_vendor.h"
This header file is a part of the API provided by the
esp_lcd
component. To declare that your component depends onesp_lcd
, add the following to your CMakeLists.txt:REQUIRES esp_lcd
or
PRIV_REQUIRES esp_lcd
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
-
int reset_gpio_num