显示屏¶
许多应用需要把信息显示给用户,因此显示屏是很重要的一个显示设备。ESP32 系列芯片为屏幕显示应用提供了丰富的外设支持,包含的接口类型有 I2C
、8080
、SPI
和 RGB
。
一块屏幕通常有两个主要部分:显示基板
和 驱动 IC
。显示基板(也称显示面板)决定了显示的尺寸、分辨率、色彩等参数;驱动 IC (也称屏幕控制器)是匹配显示基板并与基板封装在一起的,它通过一定的接口对外通信并控制显示基板进行显示。
ESP32 系列芯片的屏幕接口¶
大部分屏幕控制器可以支持多种显示接口。如 ILI9486 支持 MCU 接口(即 8080 接口)、SPI 接口、RGB 接口和 MIPI 接口。
ESP32 系列芯片接口支持情况如下:
SoC |
I2C 接口 |
SPI 接口 |
8080 接口 |
RGB 接口 |
ESP32 |
||||
ESP32-S2 |
||||
ESP32-S3 |
||||
ESP32-C3 |
注解
ESP32 系列芯片的 I2C、SPI、8080 和 RGB 接口均可以通过 GPIO 交换矩阵将信号映射到任意管脚。
SPI 接口¶
ESP32 系列芯片的 SPI 接口特点:
SPI 时钟频率最高可达 80MHz
支持 QSPI 模式
8080 接口¶
ESP32 系列芯片的 8080 接口分别由不同的外设实现
SoC |
实现 8080 接口的外设 |
特点 |
ESP32 |
I2S |
8/16 位模式下时钟频率最高可达 20MHz |
ESP32-S2 |
I2S |
8 位模式下时钟频率最高可达 40MHz,16 位模式下 20MHz |
ESP32-S3 |
LCD_CAM |
8 位模式下时钟频率最高可达 40MHz,16 位模式下 20MHz |
RGB 接口¶
ESP32-S3 芯片拥有一个 RGB 接口,支持并行 RGB565 模式和串行 RGB888 模式。RGB 接口与 8080 接口都是并行接口,一个重要区别在于 RGB 接口的屏幕一般不带显存,这就需要每一个刷新周期都对屏幕上的所有像素数据进行更新。由于 ESP32-S3 芯片内部没有足够的 RAM 用于显存,所以需要外接 PSRAM,并将显存置于 PSRAM 上。由于显存要求的带宽较大,所以为达到良好的显示效果 需要使用 8 线 PSRAM ,并且将 PSRAM 时钟频率至少设置为 80MHz。
注解
RGB 接口的驱动在 esp-idf 的 components/esp_lcd
组件中而不在 esp-iot-solution。例程请参考 esp-idf/examples/peripherals/lcd/rgb_panel
屏幕控制器¶
已适配的屏幕控制器型号如下表所示:
控制器型号 |
最大分辨率 |
类型 |
---|---|---|
NT35510 |
480 x 865 |
Color |
ILI9806 |
480 x 865 |
Color |
RM68120 |
480 x 865 |
Color |
ILI9486 |
320 x 480 |
Color |
ILI9488 |
320 x 480 |
Color |
ILI9341 |
240 x 320 |
Color |
ILI9342 |
240 x 320 |
Color |
ST7789 |
240 x 320 |
Color |
ST7796 |
320 x 480 |
Color |
SSD1351 |
128 x 128 |
Color |
SSD1306 |
128 x 64 |
Mono |
SSD1307 |
128 x 39 |
Mono |
SSD1322 |
480 x 128 |
Gray |
SSD1963 |
480 x 864 |
Color |
其中 SSD1963
可将 8080 接口转换到 RGB 接口。
驱动结构¶
为了更加符合一个屏幕控制芯片拥有多个接口的实际情况,将屏幕驱动程序划分为 接口驱动
和 屏幕控制器驱动
两部分。
接口驱动:完成基本的命令和数据的读写
屏幕控制器驱动:通过接口驱动来完成屏幕的显示
在程序设计上,一个屏幕控制器驱动可以通过调用不同的接口驱动以实现切换硬件上不同的接口。
屏幕的分类¶
对屏幕进行分类的讨论将有助于我们对驱动的理解,这里将按照屏幕可显示的色彩来分类,而非 OLED、LCD 等屏幕的面板材料。 一般情况下,屏幕显示的色彩决定了 BPP (Bits Per Pixel),而 BPP 的不同导致程序的处理方式有一些不同,下面将更直观地列举几种 GRAM 映射到像素点的方式:
从以上图中可以看出,映射方式大概可以分为两类:
BBP >= 8,通常是支持 RGB888、RGB666、RGB565 等编码的彩色屏幕。
BPP < 8,通常是单色的屏幕,可能是黑白的,也可能是灰阶的。
BPP < 8 时,一个字节映射到了多个像素,因此无法直接地控制单个像素。这时,驱动不支持 draw_pixel()
函数,且 set_window()
的参数也将受到限制。BPP >= 8 时,则可以轻松地访问单个像素。
注意
对于彩色屏幕,驱动仅支持 RGB565 颜色编码。
接口驱动¶
一个屏幕控制器通常有多种接口,在 ESP32 上通常使用 8080 并口
、SPI
和 I2C
这三种接口与屏幕连接,可以在调用 scr_interface_create()
创建接口驱动时选用其中一种接口。
注解
使用 scr_interface_create()
创建不同类型的接口时需要注意传入与之对应的配置参数类型,例如 8080 接口是 i2s_lcd_config_t
而 SPI 接口是 scr_interface_spi_config_t
。
为了方便在屏幕控制器驱动中统一使用这些接口,display/screen/screen_utility/interface_drv_def.h 中定义了所有接口,可以使用简单的参数调用接口驱动。
注解
大部分屏幕是大端模式,而 ESP32 是小端模式,因此可在使用的接口驱动中根据 swap_data
配置可选择进行大小端转换。请注意: 当使用 SPI 接口时,由于 IDF 的 SPI 驱动内部没有提供该功能,接口驱动将会对传入数据进行转换,这要求传入的数据是可写的,因此数据 必须 存放在 RAM 中。
屏幕控制器驱动¶
该部分将根据不同的屏幕控制器分别实现显示等功能,为了方便地移植到不同 GUI 库,对屏幕的一部分通用函数用 scr_driver_t
进行了抽象。对于一些屏幕的非通用功能,需要自行调用其特定的函数完成。
对于这些通用函数,由于屏幕控制器本身的功能不尽相同,并不是所有的屏幕都全部实现了,例如:对于 BPP < 8 的屏幕不支持 draw_pixel()
函数。调用不支持的函数将返回 ESP_ERR_NOT_SUPPORTED
。
显示方向¶
这里设置的屏幕显示方向是完全由屏幕硬件实现的,这个功能在不同的屏幕控制器上会有差异。一共有 8 种可能的显示方向,显示器可以旋转 0°、90°、180° 或 270°,也可以从顶部或底部查看,默认方向为 0° 和顶部查看。这 8 (4 × 2) 个不同的显示方向也可以表示为 3 个二进制开关的组合:X-mirroring、Y-mirroring 和 X/Y swapping。
下表将列出全部 8 种组合显示的方向。如果显示方向不正常,请查看下表中的配置开关使其正常工作。
0 [SCR_DIR_LRTB] |
SCR_MIRROR_Y [SCR_DIR_LRBT] |
||
SCR_MIRROR_X [SCR_DIR_RLTB] |
SCR_MIRROR_X| SCR_MIRROR_Y [SCR_DIR_RLBT] |
||
SCR_SWAP_XY [SCR_DIR_TBLR] |
SCR_SWAP_XY| SCR_MIRROR_Y [SCR_DIR_BTLR] |
||
SCR_SWAP_XY| SCR_MIRROR_X [SCR_DIR_TBRL] |
SCR_SWAP_XY| SCR_MIRROR_X| SCR_MIRROR_Y [SCR_DIR_BTRL] |
对于不同屏幕控制器,屏幕显示方向的实现并不完全相同,通常分为以下的情况:
对于彩色屏幕,支持 8 个方向的旋转。
对于单色屏幕,如 SSD1306 等屏幕来说,只支持
scr_dir_t
中定义的前 4 个方向,即不支持交换 XY 轴。
注解
显示方向还和使用的屏幕面板有关系,你可能会发现两种异常的情况:
显示方向设置为
SCR_DIR_LRTB
,屏幕却不是按照上表中对应的显示方向。这可能是因为屏幕面板上的走线对 X/Y 方向上进行了镜像,这时应该根据实际情况调整旋转以得到期望的显示方向。旋转了屏幕后,显示内容不见了。这可能是因为屏幕面板的分辨率小于屏幕控制器的分辨率,导致旋转后显示区域没有完全落在屏幕面板上,这时应考虑设置正确的显示区域偏移。
显示区域的偏移¶
在一些小尺寸的屏幕上,通常其可视区域分辨率小于所用屏幕控制器的分辨率。请参考以下示例图:
图中 Controller window
是屏幕控制器的显示窗口,分辨率为 240 × 320,Panel window
是屏幕面板窗口,分辨率为 135 × 240,可视的区域为屏幕面板区域。可以看出显示区域在水平方向上偏移了 52 个像素,在垂直方向上偏移了 40 个像素。
当屏幕逆时针旋转 90° 后,变成水平方向上偏移了 40 个像素,在垂直方向上偏移了 53 个像素,如下所示:
屏幕控制器驱动会帮助你自动根据屏幕的旋转来改变偏移的值,以保持正确的显示区域。你需要做的是在 scr_controller_config_t
中正确配置屏幕在 SCR_DIR_LRTB
方向时的偏移和屏幕面板尺寸。
注解
显示偏移仅支持 BPP >= 8 的屏幕。
当屏幕控制器是可选分辨率的时候,发现偏移不对可能是因为选择的分辨率与实际不符,此时应该修改程序,如: ILI9806 可尝试修改
ili9806.c
中的ILI9806_RESOLUTION_VER
为实际的分辨率。
应用示例¶
注解
以下示例不再维护,LCD 以及 LVGL 示例请参考: i80_controller、 rgb_panel 和 spi_lcd_touch
初始化屏幕¶
scr_driver_t g_lcd; // A screen driver
esp_err_t ret = ESP_OK;
/** Initialize 16bit 8080 interface */
i2s_lcd_config_t i2s_lcd_cfg = {
.data_width = 16,
.pin_data_num = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
},
.pin_num_cs = 45,
.pin_num_wr = 34,
.pin_num_rs = 33,
.clk_freq = 20000000,
.i2s_port = I2S_NUM_0,
.buffer_size = 32000,
.swap_data = false,
};
scr_interface_driver_t *iface_drv;
scr_interface_create(SCREEN_IFACE_8080, &i2s_lcd_cfg, &iface_drv);
/** Find screen driver for ILI9806 */
ret = scr_find_driver(SCREEN_CONTROLLER_ILI9806, &g_lcd);
if (ESP_OK != ret) {
ESP_LOGE(TAG, "screen find failed");
return;
}
/** Configure screen controller */
scr_controller_config_t lcd_cfg = {
.interface_drv = iface_drv,
.pin_num_rst = -1, // The reset pin is not connected
.pin_num_bckl = -1, // The backlight pin is not connected
.rst_active_level = 0,
.bckl_active_level = 1,
.offset_hor = 0,
.offset_ver = 0,
.width = 480,
.height = 854,
.rotate = SCR_DIR_LRBT,
};
/** Initialize ILI9806 screen */
g_lcd.init(&lcd_cfg);
注解
默认情况下只打开了 ILI9341 屏幕的驱动,如果要使用其他的驱动,需要在 menuconfig -> Component config -> LCD Drivers -> Select Screen Controller
中使能对应屏幕驱动。
显示图像¶
/** Draw a red point at position (10, 20) */
lcd.draw_pixel(10, 20, COLOR_RED);
/** Draw a bitmap */
lcd.draw_bitmap(0, 0, width_of_pic, height_of_pic, pic_data);
获取屏幕信息¶
scr_info_t lcd_info;
lcd.get_info(&lcd_info);
ESP_LOGI(TAG, "Screen name:%s | width:%d | height:%d", lcd_info.name, lcd_info.width, lcd_info.height);
API 参考¶
Header File¶
Functions¶
-
esp_err_t
scr_find_driver
(scr_controller_t controller, scr_driver_t *out_screen)¶ Find a screen driver.
- Return
ESP_OK on success
ESP_ERR_INVALID_ARG Arguments is NULL.
ESP_ERR_NOT_FOUND Screen controller was not found.
- Parameters
controller
: Screen controller to initializeout_screen
: Pointer to a screen driver
Structures¶
-
struct
scr_controller_config_t
¶ configuration of screen controller
Public Members
-
scr_interface_driver_t *
interface_drv
¶ Interface driver for screen
-
int8_t
pin_num_rst
¶ Pin to hardreset LCD
-
int8_t
pin_num_bckl
¶ Pin for control backlight
-
uint8_t
rst_active_level
¶ Reset pin active level
-
uint8_t
bckl_active_level
¶ Backlight active level
-
uint16_t
width
¶ Screen width
-
uint16_t
height
¶ Screen height
-
uint16_t
offset_hor
¶ Offset of horizontal
-
uint16_t
offset_ver
¶ Offset of vertical
-
scr_interface_driver_t *
-
struct
scr_info_t
¶ Information of screen.
Public Members
-
uint16_t
width
¶ Current screen width, it may change when apply to rotate
-
uint16_t
height
¶ Current screen height, it may change when apply to rotate
-
scr_color_type_t
color_type
¶ Color type of the screen, See scr_color_type_t struct
-
uint8_t
bpp
¶ Bits per pixel
-
const char *
name
¶ Name of the screen
-
uint16_t
-
struct
scr_driver_t
¶ Define a screen common function.
Public Members
-
esp_err_t (*
init
)(const scr_controller_config_t *lcd_conf)¶ Initialize screen.
- Return
ESP_OK on success
ESP_FAIL Driver not installed
- Parameters
lcd_conf
: Pointer to a structure with lcd config arguments. see struct scr_controller_config_t
-
esp_err_t (*
deinit
)(void)¶ Deinitialize screen.
- Return
ESP_OK on success
ESP_FAIL Deinitialize failed
ESP_ERR_NOT_SUPPORTED unsupported
-
esp_err_t (*
set_direction
)(scr_dir_t dir)¶ Set screen direction of rotation.
- Note
Not all screens support eight directions, it depends on the screen controller.
- Return
ESP_OK on success
ESP_FAIL Failed
- Parameters
dir
: Pointer to a scr_dir_t structure. You can set the direction in two ways, for example, set it to “SCR_DIR_LRBT” or “SCR_MIRROR_Y”, They are the same, depending on which expression you want to use
-
esp_err_t (*
set_window
)(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)¶ Set screen window.
- Note
When the BPP of the screen controller is less than 8, the coordinate value is limited to a multiple of some number
- Return
ESP_OK on success
ESP_FAIL Failed
- Parameters
x0
: Starting point in X directiony0
: Starting point in Y directionx1
: End point in X directiony1
: End point in Y direction
-
esp_err_t (*
write_ram_data
)(uint16_t color)¶ Write a RAM data.
- Return
ESP_OK on success
ESP_FAIL Failed
- Parameters
color
: New color of a pixel
-
esp_err_t (*
draw_pixel
)(uint16_t x, uint16_t y, uint16_t color)¶ Draw one pixel in screen with color.
- Return
ESP_OK on success
ESP_FAIL Failed
- Parameters
x
: X co-ordinate of set orientationy
: Y co-ordinate of set orientationcolor
: New color of the pixel
-
esp_err_t (*
draw_bitmap
)(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t *bitmap)¶ Fill the pixels on LCD screen with bitmap.
- Return
ESP_OK on success
ESP_FAIL Failed
- Parameters
x
: Starting point in X directiony
: Starting point in Y directionw
: width of image in bitmap arrayh
: height of image in bitmap arraybitmap
: pointer to bitmap array
-
esp_err_t (*
get_info
)(scr_info_t *info)¶ Get screen information.
- Return
ESP_OK on success
ESP_FAIL Failed
- Parameters
info
: Pointer to a scr_info_t structure.
-
esp_err_t (*
Macros¶
-
COLOR_BLACK
¶
-
COLOR_NAVY
¶
-
COLOR_DARKGREEN
¶
-
COLOR_DARKCYAN
¶
-
COLOR_MAROON
¶
-
COLOR_PURPLE
¶
-
COLOR_OLIVE
¶
-
COLOR_LIGHTGREY
¶
-
COLOR_DARKGREY
¶
-
COLOR_BLUE
¶
-
COLOR_GREEN
¶
-
COLOR_CYAN
¶
-
COLOR_RED
¶
-
COLOR_MAGENTA
¶
-
COLOR_YELLOW
¶
-
COLOR_WHITE
¶
-
COLOR_ORANGE
¶
-
COLOR_GREENYELLOW
¶
-
COLOR_PINK
¶
-
COLOR_SILVER
¶
-
COLOR_GRAY
¶
-
COLOR_LIME
¶
-
COLOR_TEAL
¶
-
COLOR_FUCHSIA
¶
-
COLOR_ESP_BKGD
¶
Enumerations¶
-
enum
scr_dir_t
¶ Define all screen direction.
Values:
-
SCR_DIR_LRTB
¶ From left to right then from top to bottom, this consider as the original direction of the screen
-
SCR_DIR_LRBT
¶ From left to right then from bottom to top
-
SCR_DIR_RLTB
¶ From right to left then from top to bottom
-
SCR_DIR_RLBT
¶ From right to left then from bottom to top
-
SCR_DIR_TBLR
¶ From top to bottom then from left to right
-
SCR_DIR_BTLR
¶ From bottom to top then from left to right
-
SCR_DIR_TBRL
¶ From top to bottom then from right to left
-
SCR_DIR_BTRL
¶ From bottom to top then from right to left
-
SCR_DIR_MAX
¶
-
SCR_MIRROR_X
= 0x40¶ Mirror X-axis
-
SCR_MIRROR_Y
= 0x20¶ Mirror Y-axis
-
SCR_SWAP_XY
= 0x80¶ Swap XY axis
-
-
enum
scr_color_type_t
¶ The types of colors that can be displayed on the screen.
Values:
-
SCR_COLOR_TYPE_MONO
¶ The screen is monochrome
-
SCR_COLOR_TYPE_GRAY
¶ The screen is gray
-
SCR_COLOR_TYPE_RGB565
¶ The screen is colorful
-
-
enum
scr_controller_t
¶ All supported screen controllers.
Values:
-
SCREEN_CONTROLLER_ILI9341
¶
-
SCREEN_CONTROLLER_ILI9342
¶
-
SCREEN_CONTROLLER_ILI9806
¶
-
SCREEN_CONTROLLER_ILI9486
¶
-
SCREEN_CONTROLLER_ILI9488
¶
-
SCREEN_CONTROLLER_NT35510
¶
-
SCREEN_CONTROLLER_RM68120
¶
-
SCREEN_CONTROLLER_ST7789
¶
-
SCREEN_CONTROLLER_ST7796
¶
-
SCREEN_CONTROLLER_SSD1351
¶
-
SCREEN_CONTROLLER_SSD1963
¶
-
SCREEN_CONTROLLER_SSD1306
¶
-
SCREEN_CONTROLLER_SSD1307
¶
-
SCREEN_CONTROLLER_SSD1322
¶
-
Header File¶
Functions¶
-
esp_err_t
scr_interface_create
(scr_interface_type_t type, void *config, scr_interface_driver_t **out_driver)¶ Create screen interface driver.
- Return
ESP_OK on success
ESP_ERR_INVALID_ARG Arguments is NULL.
ESP_FAIL Initialize failed
ESP_ERR_NO_MEM: Cannot allocate memory.
- Parameters
type
: Type of screen interfaceconfig
: configuration of interface driverout_driver
: Pointer to a screen interface driver
-
esp_err_t
scr_interface_delete
(const scr_interface_driver_t *driver)¶ Delete screen interface driver.
- Return
ESP_OK on success
ESP_ERR_INVALID_ARG Arguments is NULL.
- Parameters
driver
: screen interface driver to delete
Structures¶
-
struct
scr_interface_spi_config_t
¶ SPI interface configuration.
-
struct
scr_interface_i2c_config_t
¶ I2C interface configuration.
Public Members
-
i2c_bus_handle_t
i2c_bus
¶ Handle of i2c bus
-
uint32_t
clk_speed
¶ I2C clock frequency for master mode, (no higher than 1MHz for now)
-
uint16_t
slave_addr
¶ I2C slave address
-
i2c_bus_handle_t
-
struct
scr_interface_driver_t
¶ Define common function for screen interface driver.
Public Members
-
scr_interface_type_t
type
¶ Interface bus type, see scr_interface_type_t struct
-
esp_err_t (*
write_command
)(void *handle, const uint8_t *cmd, uint32_t length)¶ Function to write command
-
esp_err_t (*
write_data
)(void *handle, uint16_t data)¶ Function to write a data
-
esp_err_t (*
write
)(void *handle, const uint8_t *data, uint32_t length)¶ Function to write a block data
-
esp_err_t (*
read
)(void *handle, uint8_t *data, uint32_t length)¶ Function to read a block data
-
esp_err_t (*
bus_acquire
)(void *handle)¶ Function to acquire interface bus
-
esp_err_t (*
bus_release
)(void *handle)¶ Function to release interface bus
-
scr_interface_type_t