ESP32开发路程LVGL篇(一)——移植完整过程,花屏问题解决,ST7735显示方向
使用 ESP32 驱动 ST7735 128*160屏幕,使用 lvgl 和 lvgl_esp32_drivers,参考 lv_port_esp32 创建工程,完整说明移植过程,同时解决ST7735显示方向受限问题,并给出常见的花屏问题解决方案
LVGL官方文档:文档链接
本文使用屏幕:ST7735(1.8寸,分辨率128*160)
本文使用框架:ESP-IDF(VSCODE)
移植
准备工作
下载 lvgl (注意是v7版本,v8暂不适配):
https://github.com/lvgl/lvgl/tree/release/v7
下载 lvgl_esp32_drivers(master 分支):
https://github.com/lvgl/lvgl_esp32_drivers/tree/master
开始移植
-
创建新项目
新手可以参考 这一篇文章 里面的 常用操作 -> 自己创建工程 -
创建 components
新建 components 文件夹,并将准备工作中下载的 lvgl 和 lvgl_esp32_drivers 移入该文件夹中,创建结果应与下图相符合
- 添加 SPI_HOST_MAX 定义
在 lvgl_esp32_drivers 里的 lvgl_helpers.h 里面的合适位置添加 SPI_HOST_MAX 定义
#define SPI_HOST_MAX 3
- 在 menuconfig 里面进行相关配置
!!!这一环节很重要,一步没注意就会导致屏幕显示异常- LVGL configuration
在此处修改屏幕分辨率(128*160为例),勾选 Swap 这一选项
- LVGL TFT Display controller
Display orientation 可以更改屏幕显示方向,controller model 选择ST7735S,勾选 Use custom SPI clock frequency 我的设置为10MHz
- Display Pin Assignments
这里的引脚设置可以自定义,以下仅作参考,Backlight Control 可有可无,不用时选择 Not Used
- LVGL configuration
- 修改驱动代码
在 lvgl_esp32_drivers -> lvgl_tft 里的 st7735s.h 文件里 修改以下定义,COLSTART 和 ROWSTART 的值需要根据所用的屏幕分辨率进行调整,本文所用的128*160,应将两者设置为0
#define COLSTART 0
#define ROWSTART 0
编译运行
- 添加 main.c 代码
给出一段测试代码(lv_port_esp32 工程中删减的 main.c 代码),运行效果为白底黑字显示“Hello world”,关于代码的讲解放在下一篇去介绍。
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_freertos_hooks.h"
#include "freertos/semphr.h"
#include "esp_system.h"
#include "driver/gpio.h"
/* Littlevgl specific */
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
#include "lvgl_helpers.h"
/*********************
* DEFINES
*********************/
#define TAG "demo"
#define LV_TICK_PERIOD_MS 1
/**********************
* STATIC PROTOTYPES
**********************/
static void lv_tick_task(void *arg);
static void guiTask(void *pvParameter);
static void create_demo_application(void);
/**********************
* APPLICATION MAIN
**********************/
void app_main() {
/* If you want to use a task to create the graphic, you NEED to create a Pinned task
* Otherwise there can be problem such as memory corruption and so on.
* NOTE: When not using Wi-Fi nor Bluetooth you can pin the guiTask to core 0 */
xTaskCreatePinnedToCore(guiTask, "gui", 4096*2, NULL, 0, NULL, 1);
}
/* Creates a semaphore to handle concurrent call to lvgl stuff
* If you wish to call *any* lvgl function from other threads/tasks
* you should lock on the very same semaphore! */
SemaphoreHandle_t xGuiSemaphore;
static void guiTask(void *pvParameter) {
(void) pvParameter;
xGuiSemaphore = xSemaphoreCreateMutex();
lv_init();
/* Initialize SPI or I2C bus used by the drivers */
lvgl_driver_init();
lv_color_t* buf1 = heap_caps_malloc(DISP_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA);
assert(buf1 != NULL);
/* Use double buffered when not working with monochrome displays */
lv_color_t* buf2 = heap_caps_malloc(DISP_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA);
assert(buf2 != NULL);
static lv_disp_buf_t disp_buf;
uint32_t size_in_px = DISP_BUF_SIZE;
/* Initialize the working buffer depending on the selected display.
* NOTE: buf2 == NULL when using monochrome displays. */
lv_disp_buf_init(&disp_buf, buf1, buf2, size_in_px);
lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.flush_cb = disp_driver_flush;
#if defined CONFIG_DISPLAY_ORIENTATION_PORTRAIT || defined CONFIG_DISPLAY_ORIENTATION_PORTRAIT_INVERTED
disp_drv.rotated = 1;
#endif
disp_drv.buffer = &disp_buf;
lv_disp_drv_register(&disp_drv);
/* Create and start a periodic timer interrupt to call lv_tick_inc */
const esp_timer_create_args_t periodic_timer_args = {
.callback = &lv_tick_task,
.name = "periodic_gui"
};
esp_timer_handle_t periodic_timer;
ESP_ERROR_CHECK(esp_timer_create(&periodic_timer_args, &periodic_timer));
ESP_ERROR_CHECK(esp_timer_start_periodic(periodic_timer, LV_TICK_PERIOD_MS * 1000));
/* Create the demo application */
create_demo_application();
while (1) {
/* Delay 1 tick (assumes FreeRTOS tick is 10ms */
vTaskDelay(pdMS_TO_TICKS(10));
/* Try to take the semaphore, call lvgl related function on success */
if (pdTRUE == xSemaphoreTake(xGuiSemaphore, portMAX_DELAY)) {
lv_task_handler();
xSemaphoreGive(xGuiSemaphore);
}
}
/* A task should NEVER return */
free(buf1);
#ifndef CONFIG_LV_TFT_DISPLAY_MONOCHROME
free(buf2);
#endif
vTaskDelete(NULL);
}
static void create_demo_application(void)
{
/* When using a monochrome display we only show "Hello World" centered on the
* screen */
/* use a pretty small demo for monochrome displays */
/* Get the current screen */
lv_obj_t * scr = lv_disp_get_scr_act(NULL);
/*Create a Label on the currently active screen*/
lv_obj_t * label1 = lv_label_create(scr, NULL);
/*Modify the Label's text*/
lv_label_set_text(label1, "Hello\nworld");
/* Align the Label to the center
* NULL means align on parent (which is the screen now)
* 0, 0 at the end means an x, y offset after alignment*/
lv_obj_align(label1, NULL, LV_ALIGN_CENTER, 0, 0);
}
static void lv_tick_task(void *arg) {
(void) arg;
lv_tick_inc(LV_TICK_PERIOD_MS);
}
- 编译运行
ESP32 与 TFT 的引脚连接参考如下,编译成功的话,将代码烧录到 ESP32 中
ESP32 | TFT | 本文使用引脚 |
---|---|---|
MOSI | SDA | 23 |
CLK | SCL | 18 |
CS | CS | 19 |
DC | DC | 21 |
RST | RST | 22 |
- 结果展示
花屏问题
- 检查分辨率设置
- 在 lvgl_helpers.h 中通过修改 LV_HOR_RES_MAX 和 LV_VER_RES_MAX 的值来设置显示器的像素宽度和高度可能是没有作用的,应该在 menuconfig -> LVGL configuration 里面设置
- 同时要注意 horizontal 和 vertical 的值不要写颠倒了,可以尝试调换两个值的所处位置
- 调整 SPI 频率
- 可以在 menuconfig -> LVGL TFT Display controller 里面调整 SPI 频率,我设置的频率是10MHz
ST7735显示方向
目前使用的驱动,可以支持的 ST7735 显示方向只有 Portrait (竖屏)和 Landscape (横屏)。
要想将显示方向调整为 Portrait inverted 和 Landscape inverted 的话,需要修改 lvgl_esp32_drivers -> lvgl_tft 里的 st7735s.c 文件
找到文件里的 st7735s_set_orientation 函数,并将其替换成如下所示
static void st7735s_set_orientation(uint8_t orientation)
{
const char *orientation_str[] = {
"PORTRAIT", "PORTRAIT_INVERTED", "LANDSCAPE", "LANDSCAPE_INVERTED"
};
ESP_LOGD(TAG, "Display orientation: %s", orientation_str[orientation]);
/*
Portrait: 0xC8 = ST77XX_MADCTL_MX | ST77XX_MADCTL_MY | ST77XX_MADCTL_BGR
Portrait inverted: 0x08
Landscape: 0xA8 = ST77XX_MADCTL_MY | ST77XX_MADCTL_MV | ST77XX_MADCTL_BGR
Landscape inverted: 0x78
*/
uint8_t data[] = {0xC8, 0x08, 0xA8, 0x78};
ESP_LOGD(TAG, "0x36 command value: 0x%02X", data[orientation]);
st7735s_send_cmd(ST7735_MADCTL);
st7735s_send_data((void *) &data[orientation], 1);
}
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)