文章目录
- 1 前言
- 2 准备
- 3 移植LVGL
- 3.1 工程准备
- 3.2 修改 CMakeLists.txt文件编译 LVGL
- 3.3 编译LVGL
- 4 编译 ST7789 LCD驱动
- 5 发现问题
1 前言
本教程开始学习
LVGL
的,开始之前要把环境配置好,首先就需要移植lvgl
,使用的是esp32
环境,使用的 LCD驱动IC是 ST7789,没有使用到触摸屏。
2 准备
组件下载地址
https://components.espressif.com/
-
准备一个空的工程
-
下载
esp_lvgl_port
https://components.espressif.com/components/espressif/esp_lvgl_port
-
下载
LVGL8.3.6
https://components.espressif.com/components/lvgl/lvgl/versions/8.3.6~1?language=en
下载位置
这里说明一下:为什么使用手动下载,很多教程都是使用的是
idf_component.yml
这个文件进行配置,但是在下载esp_lvgl_port
的时候,会自动下载LVGL 8
的最新版,或者LVGL 9
的最新版,而且弄好以后,还需要重新吧远程的文件重新移动到本地文件,不然后面修改组件的代码,会编译报错。笔者想使用的是LVGL 8.3.6
,所以选择手动下载配置,
3 移植LVGL
3.1 工程准备
components
文件夹
在 main
文件夹 同级别 的目录下,新建一个 components
的文件夹,把刚刚下载好的两个文件移动到 components
目录下,并修改一个简单的文件夹名字,
3.2 修改 CMakeLists.txt文件编译 LVGL
esp_lvgl_Port
依赖于 LVGL,修改 esp_lvgl_Port -> CMakeLists.txt
文件
`lvgl_lvgl`改成 `lvgl`
把 `lvgl_lvgl`改成 "lvgl的文件夹名字"
3.3 编译LVGL
- 编译成功
4 编译 ST7789 LCD驱动
在下载 esp_lvgl_Port
的时候,就会自动下载了 ST7789
的驱动,如果不是 ST7789的驱动,那么需要自己去下载相关的驱动,下载地址也是
https://components.espressif.com/
搜索自己的 LCD驱动 IC 名称进行下载,放在 components 目录下即可。
main.c
编写驱动代码
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_err.h"
#include "esp_log.h"
#include "esp_check.h"
#include "driver/i2c.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"
/* LCD size */
#define EXAMPLE_LCD_H_RES (320)
#define EXAMPLE_LCD_V_RES (240)
/* LCD settings */
#define EXAMPLE_LCD_SPI_NUM (SPI3_HOST)
#define EXAMPLE_LCD_PIXEL_CLK_HZ (40 * 1000 * 1000)
#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 (50)
#define EXAMPLE_LCD_BL_ON_LEVEL (1)
/* LCD pins */
#define EXAMPLE_LCD_GPIO_SCLK (GPIO_NUM_7)
#define EXAMPLE_LCD_GPIO_MOSI (GPIO_NUM_6)
#define EXAMPLE_LCD_GPIO_RST (GPIO_NUM_48)
#define EXAMPLE_LCD_GPIO_DC (GPIO_NUM_4)
#define EXAMPLE_LCD_GPIO_CS (GPIO_NUM_5)
#define EXAMPLE_LCD_GPIO_BL (GPIO_NUM_45)
static const char *TAG = "EXAMPLE";
/* 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 app_lcd_init(void)
{
esp_err_t ret = ESP_OK;
/* LCD backlight */
gpio_config_t bk_gpio_config = {
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = 1ULL << EXAMPLE_LCD_GPIO_BL
};
ESP_ERROR_CHECK(gpio_config(&bk_gpio_config));
/* LCD initialization */
ESP_LOGD(TAG, "Initialize SPI bus");
const spi_bus_config_t buscfg = {
.sclk_io_num = EXAMPLE_LCD_GPIO_SCLK,
.mosi_io_num = EXAMPLE_LCD_GPIO_MOSI,
.miso_io_num = GPIO_NUM_NC,
.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");
ESP_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_PIXEL_CLK_HZ,
.lcd_cmd_bits = EXAMPLE_LCD_CMD_BITS,
.lcd_param_bits = EXAMPLE_LCD_PARAM_BITS,
.spi_mode = 0,
.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");
ESP_LOGD(TAG, "Install LCD driver");
const esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = EXAMPLE_LCD_GPIO_RST,
.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 = 4096, /* 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 * sizeof(uint16_t),
.double_buffer = EXAMPLE_LCD_DRAW_BUFF_DOUBLE,
.hres = EXAMPLE_LCD_H_RES,
.vres = EXAMPLE_LCD_V_RES,
.monochrome = false,
/* Rotation values must be same as used in esp_lcd for initial settings of the screen */
.rotation = {
.swap_xy = false,
.mirror_x = true,
.mirror_y = true,
},
.flags = {
.buff_dma = true,
.swap_bytes = true,
}
};
lvgl_disp = lvgl_port_add_disp(&disp_cfg);
return ESP_OK;
}
static void _app_button_cb(lv_event_t *e)
{
lv_disp_rotation_t rotation = lv_disp_get_rotation(lvgl_disp);
rotation++;
if (rotation > LV_DISPLAY_ROTATION_270) {
rotation = LV_DISPLAY_ROTATION_0;
}
/* LCD HW rotation */
lv_disp_set_rotation(lvgl_disp, rotation);
}
static void app_main_display(void)
{
lv_obj_t *scr = lv_scr_act();
/* Task lock */
lvgl_port_lock(0);
/* Your LVGL objects code here .... */
/* 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 == 8
lv_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" #");
#else
lv_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);
#endif
lv_obj_align(label, LV_ALIGN_CENTER, 0, -30);
/* Button */
lv_obj_t *btn = lv_btn_create(scr);
label = lv_label_create(btn);
lv_label_set_text_static(label, "Rotate screen");
lv_obj_align(btn, LV_ALIGN_BOTTOM_MID, 0, -30);
lv_obj_add_event_cb(btn, _app_button_cb, LV_EVENT_CLICKED, NULL);
/* Task unlock */
lvgl_port_unlock();
}
void app_main(void)
{
/* LCD HW initialization */
ESP_ERROR_CHECK(app_lcd_init());
/* LVGL initialization */
ESP_ERROR_CHECK(app_lvgl_init());
/* Show LVGL objects */
app_main_display();
}
5 发现问题
-
发现是花屏,需要进入开启
Swap the 2 bytes of RGB565 color. Useful if the display has an 8-bit interface (e.g. SPI).
-
发现 颜色是反的, app_lcd_init 添加代码
esp_lcd_panel_invert_color(lcd_panel, true);
-
发现显示屏错位了,Y坐标 起点是 -80 并不是0,app_lcd_init 添加代码
esp_lcd_panel_set_gap(lcd_panel, 0, 80);
文章是自己总结而记录,有些知识点没说明白的,请各位看官多多提意见,多多交流,欢迎大家留言
如果技术交流可以加以下群,方便沟通
QQ群:370278903
点击链接加入群聊【蜡笔小芯的嵌入式交流群】