ESP32S3 使用LVGL驱动LCD屏(ST7789主控)
目录
1 分析原理图
2 驱动、点亮LCD(ST7789)
2.1 在工程中添加目录、文件
2.2 添加esp_lvgl_port组件
2.3 对工程进行必要的配置
2.4 编写必要代码
3 烧录、验证
1 分析原理图
通过这部分原理图,可以知道,主控用的是8MB Flash的ESP32S3-WROOM模组,LCD驱动芯片为ST7789,驱动接口为SPI接口。IO9控制的是LCD的亮度、IO10为ST7789的SPI片选、IO12为ST7789的SPI时钟、IO11和IO13则为ST7789的SPI数据输入输出,其他的还有一些复位信号、背光信号。
2 驱动、点亮LCD(ST7789)
IDF项目添加LVGL组件 创建的工程的基础上,进一步实现LCD屏幕的驱动点亮。
2.1 在工程中添加目录、文件
修改main路径下的CMakeLists.txt文件,将lvgl_options路径下的文件添加进构建系统。
2.2 添加esp_lvgl_port组件
idf.py clean
idf.py add-dependency "espressif/esp_lvgl_port^2.4.3"
idf.py set-target esp32s3
2.3 对工程进行必要的配置
根据模组的实际ram情况配置ram。
根据LCD情况和实际内存资源情况,调整LVGL相关配置。
2.4 编写必要代码
spi_bus_config_t buscfg = {.sclk_io_num = EXAMPLE_LCD_GPIO_SCLK,.mosi_io_num = EXAMPLE_LCD_GPIO_MOSI,.miso_io_num = EXAMPLE_LCD_GPIO_MISO,.quadwp_io_num = GPIO_NUM_NC,.quadhd_io_num = GPIO_NUM_NC,.max_transfer_sz = EXAMPLE_LCD_H_RES * EXAMPLE_LCD_DRAW_BUFF_HEIGHT * sizeof(uint16_t),};ESP_RETURN_ON_ERROR(spi_bus_initialize(EXAMPLE_LCD_SPI_NUM, &buscfg, SPI_DMA_CH_AUTO), TAG, "SPI init failed");
在完成了SPI 总线的初始化后,就可以开始初始化LCD设备了,LCD设备的初始化需要先创建一个esp_lcd_panel_io_spi_config_t类型的对象完成实际SPI的配置,再通过esp_lcd_new_panel_io_spi()接口完成lcd_io对象的创建,再通过lcd_io对象完成lcd_panel的创建。
const esp_lcd_panel_io_spi_config_t io_config = {.dc_gpio_num = EXAMPLE_LCD_GPIO_DC,.cs_gpio_num = EXAMPLE_LCD_GPIO_CS,.pclk_hz = EXAMPLE_LCD_CLOCK_SPEED_HZ,.lcd_cmd_bits = EXAMPLE_LCD_CMD_BITS,.lcd_param_bits = EXAMPLE_LCD_PARAM_BITS,.spi_mode = EXAMPLE_LCD_SPI_MODE,.trans_queue_depth = 10,};
ESP_GOTO_ON_ERROR(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)EXAMPLE_LCD_SPI_NUM, &io_config, &lcd_io), err, TAG, "New panel IO failed");const esp_lcd_panel_dev_config_t panel_config = {//.reset_gpio_num = EXAMPLE_LCD_GPIO_RST,.reset_gpio_num = GPIO_NUM_NC,.color_space = EXAMPLE_LCD_COLOR_SPACE,.bits_per_pixel = EXAMPLE_LCD_BITS_PER_PIXEL,
};
ESP_GOTO_ON_ERROR(esp_lcd_new_panel_st7789(lcd_io, &panel_config, &lcd_panel), err, TAG, "New panel failed");
在完成了SPI和LCD设备的初始化后,就可以初始化lvgl组件了。主要就是调用lvgl_port_init()和lvgl_port_add_disp()。
完整的lvgl_options.h
#ifndef _MY_LVGL_OPTIONS_H_
#define _MY_LVGL_OPTIONS_H_#ifdef __cplusplus
extern "C" {
#endifvoid lvgl_options_test(void);#ifdef __cplusplus
} /* extern "C" */
#endif#endif
完整的lvgl_options.c
#include "esp_err.h"
#include "esp_log.h"
#include "esp_check.h"#include "driver/gpio.h"
#include "driver/spi_master.h"#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"#include "esp_lvgl_port.h"#include "lvgl_options.h"// ST7789 参数
#define SPI_TFT_ST7789_CLOCK_SPEED_HZ (60*1000*1000)
#define SPI_TFT_ST7789_SPI_MODE (2)/* LCD size */
#define EXAMPLE_LCD_H_RES (240)
#define EXAMPLE_LCD_V_RES (320)/* LCD settings */
#define EXAMPLE_LCD_SPI_NUM (SPI3_HOST)
#define EXAMPLE_LCD_CMD_BITS (8)
#define EXAMPLE_LCD_PARAM_BITS (8)
#define EXAMPLE_LCD_COLOR_SPACE (ESP_LCD_COLOR_SPACE_BGR)
#define EXAMPLE_LCD_BITS_PER_PIXEL (16)
#define EXAMPLE_LCD_DRAW_BUFF_DOUBLE (1)
#define EXAMPLE_LCD_DRAW_BUFF_HEIGHT (320)
#define EXAMPLE_LCD_BL_ON_LEVEL (1)#define EXAMPLE_LCD_SPI_MODE SPI_TFT_ST7789_SPI_MODE
#define EXAMPLE_LCD_CLOCK_SPEED_HZ SPI_TFT_ST7789_CLOCK_SPEED_HZ
#define EXAMPLE_LCD_GPIO_SCLK (GPIO_NUM_12)
#define EXAMPLE_LCD_GPIO_MOSI (GPIO_NUM_11)
#define EXAMPLE_LCD_GPIO_MISO (GPIO_NUM_13)
//#define EXAMPLE_LCD_GPIO_RST (GPIO_NUM_48)
#define EXAMPLE_LCD_GPIO_DC (GPIO_NUM_9)
#define EXAMPLE_LCD_GPIO_CS (GPIO_NUM_10)
//#define EXAMPLE_LCD_GPIO_BL (GPIO_NUM_45)static const char *TAG = "lvgl_options";// LVGL image declare
LV_IMG_DECLARE(esp_logo)/* LCD IO and panel */
static esp_lcd_panel_io_handle_t lcd_io = NULL;
static esp_lcd_panel_handle_t lcd_panel = NULL;/* LVGL display and touch */
static lv_display_t *lvgl_disp = NULL;static esp_err_t spi_bus_init(void)
{esp_err_t ret = ESP_OK;spi_bus_config_t buscfg = {.sclk_io_num = EXAMPLE_LCD_GPIO_SCLK,.mosi_io_num = EXAMPLE_LCD_GPIO_MOSI,.miso_io_num = EXAMPLE_LCD_GPIO_MISO,.quadwp_io_num = GPIO_NUM_NC,.quadhd_io_num = GPIO_NUM_NC,.max_transfer_sz = EXAMPLE_LCD_H_RES * EXAMPLE_LCD_DRAW_BUFF_HEIGHT * sizeof(uint16_t),};// 初始化SPI 总线ESP_LOGD(TAG, "Initialize SPI bus");ESP_RETURN_ON_ERROR(spi_bus_initialize(EXAMPLE_LCD_SPI_NUM, &buscfg, SPI_DMA_CH_AUTO), TAG, "SPI init failed");return ret;
}static esp_err_t app_lcd_init(void)
{esp_err_t ret = ESP_OK;ESP_LOGD(TAG, "Install LCD driver");// 初始化 LCD SPIESP_LOGD(TAG, "Install panel IO");const esp_lcd_panel_io_spi_config_t io_config = {.dc_gpio_num = EXAMPLE_LCD_GPIO_DC,.cs_gpio_num = EXAMPLE_LCD_GPIO_CS,.pclk_hz = EXAMPLE_LCD_CLOCK_SPEED_HZ,.lcd_cmd_bits = EXAMPLE_LCD_CMD_BITS,.lcd_param_bits = EXAMPLE_LCD_PARAM_BITS,.spi_mode = EXAMPLE_LCD_SPI_MODE,.trans_queue_depth = 10,};ESP_GOTO_ON_ERROR(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)EXAMPLE_LCD_SPI_NUM, &io_config, &lcd_io), err, TAG, "New panel IO failed");const esp_lcd_panel_dev_config_t panel_config = {//.reset_gpio_num = EXAMPLE_LCD_GPIO_RST,.reset_gpio_num = GPIO_NUM_NC,.color_space = EXAMPLE_LCD_COLOR_SPACE,.bits_per_pixel = EXAMPLE_LCD_BITS_PER_PIXEL,};ESP_GOTO_ON_ERROR(esp_lcd_new_panel_st7789(lcd_io, &panel_config, &lcd_panel), err, TAG, "New panel failed");esp_lcd_panel_reset(lcd_panel);esp_lcd_panel_init(lcd_panel);//esp_lcd_panel_mirror(lcd_panel, true, true);esp_lcd_panel_disp_on_off(lcd_panel, true);/* LCD backlight on ESP_ERROR_CHECK(gpio_set_level(EXAMPLE_LCD_GPIO_BL, EXAMPLE_LCD_BL_ON_LEVEL));*/return ret;err:if (lcd_panel) {esp_lcd_panel_del(lcd_panel);}if (lcd_io) {esp_lcd_panel_io_del(lcd_io);}spi_bus_free(EXAMPLE_LCD_SPI_NUM);return ret;
}static esp_err_t app_lvgl_init(void)
{/* Initialize LVGL */const lvgl_port_cfg_t lvgl_cfg = {.task_priority = 4, /* LVGL task priority */.task_stack = 6144, /* LVGL task stack size */.task_affinity = -1, /* LVGL task pinned to core (-1 is no affinity) */.task_max_sleep_ms = 500, /* Maximum sleep in LVGL task */.timer_period_ms = 5 /* LVGL timer tick period in ms */};ESP_RETURN_ON_ERROR(lvgl_port_init(&lvgl_cfg), TAG, "LVGL port initialization failed");/* Add LCD screen */ESP_LOGD(TAG, "Add LCD screen");const lvgl_port_display_cfg_t disp_cfg = {.io_handle = lcd_io,.panel_handle = lcd_panel,.buffer_size = EXAMPLE_LCD_H_RES * EXAMPLE_LCD_DRAW_BUFF_HEIGHT,.trans_size = EXAMPLE_LCD_H_RES * (EXAMPLE_LCD_DRAW_BUFF_HEIGHT / 2),.double_buffer = EXAMPLE_LCD_DRAW_BUFF_DOUBLE,.hres = EXAMPLE_LCD_H_RES,.vres = EXAMPLE_LCD_V_RES,.monochrome = false,
#if LVGL_VERSION_MAJOR >= 9.color_format = LV_COLOR_FORMAT_RGB565,
#endif.rotation = {.swap_xy = false,.mirror_x = false,.mirror_y = true,},.flags = {//.buff_dma = true,.buff_spiram = true,
#if LVGL_VERSION_MAJOR >= 9//.swap_bytes = true,
#endif }};lvgl_disp = lvgl_port_add_disp(&disp_cfg);return ESP_OK;
}static void app_main_display(void)
{lv_obj_t *scr = lv_scr_act();/* Task lock */lvgl_port_lock(0);/* Label */lv_obj_t *label = lv_label_create(scr);lv_obj_set_width(label, EXAMPLE_LCD_H_RES);lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0);
#if LVGL_VERSION_MAJOR == 8lv_label_set_recolor(label, true);lv_label_set_text(label, "#FF0000 "LV_SYMBOL_BELL" Hello world Espressif and LVGL "LV_SYMBOL_BELL"#\n#FF9400 "LV_SYMBOL_WARNING" For simplier initialization, use BSP "LV_SYMBOL_WARNING" #");
#elselv_label_set_text(label, LV_SYMBOL_BELL" Hello world Espressif and LVGL "LV_SYMBOL_BELL"\n "LV_SYMBOL_WARNING" For simplier initialization, use BSP "LV_SYMBOL_WARNING);
#endiflv_obj_align(label, LV_ALIGN_CENTER, 0, 20);/* Task unlock */lvgl_port_unlock();
}void lvgl_options_test(void)
{ESP_LOGD(TAG, "lvgl_options_test");/* SPI BUS initialization*/ESP_ERROR_CHECK(spi_bus_init());/* LCD HW initialization */ESP_ERROR_CHECK(app_lcd_init());/* LVGL initialization */ESP_ERROR_CHECK(app_lvgl_init());/* Show LVGL objects */app_main_display();return;
}