ESP32 ESP-IDF LVGL8.3.3移植

陈拓 2022/11/27-2022/12/10

1. 概述

在《ESP32 ESP-IDF TFT-LCD(ST7735 128x160) LVGL演示》

ESP32 ESP-IDF TFT-LCD(ST7735 128x160) LVGL演示_晨之清风的博客-CSDN博客_esp32 tftlcd在ESP32开发框架ESP-IDF中用LVGL库驱动TFT-LCD(ST7735 128x160) 显示屏演示GUIicon-default.png?t=N7T8https://blog.csdn.net/chentuo2000/article/details/126668088?spm=1001.2014.3001.5502

和《ESP32 ESP-IDF LVGL ST7789 演示lv_demo_music》

ESP32 ESP-IDF LVGL ST7789 演示lv_demo_music_晨之清风的博客-CSDN博客_espidf lvgl例程在ESP32的ESP-IDF开发环境下移植LVGL,配置ST7789 演示lv_demo_musicicon-default.png?t=N7T8https://blog.csdn.net/chentuo2000/article/details/126807644?spm=1001.2014.3001.5501

两篇文章中,我们演示了LVGL官方ESP32移植项目https://github.com/lvgl/lv_port_esp32

该项目使用使用的LVGL 7.9版本。

本文在此基础上移植LVGL8.3.3。

官方文档:http://docs.lvgl.io/8.3/

下面的例子中任然使用前面两篇文章中使用的ST7735和ST7789显示屏。

2. 构建ESP32 ESP-IDF开发环境

首先构建ESP32 ESP-IDF开发环境,可用参考《Ubuntu构建ESP32 ESP-IDF开发环境(简约版)》

https://blog.csdn.net/chentuo2000/article/details/128034585?spm=1001.2014.3001.5502

3. LVGL官方文档查看

https://docs.lvgl.io/master/get-started/platforms/espressif.html

LVGL可作为标准ESP-IDF组件使用和配置。

  • ESP32的LVGL演示项目

我们创建了lv_port_esp32(https://github.com/lvgl/lv_port_esp32),这是一个使用ESP-IDF和LVGL来展示demos (https://github.com/lvgl/lvgl/tree/master/demos)中的一个演示的项目。您可以将项目配置为许多受支持的显示控制器和目标芯片之一。

请参阅lvgl_esp32_drivers(https://github.com/lvgl/lvgl_esp32_drivers)存储库,以获取支持的显示器和独立触摸控制器和目标的完整列表。

  • 在ESP-IDF项目中使用LVGL

ESP-IDF v4.1及以上版本。

查看我的ESP-IDF版本:

get_idf

idf.py --version

  • 获取LVGL

只需将LVGL克隆到project_root/components目录中,它就会自动集成到项目中。

  • 配置

在项目根目录中使用idf.py menuconfig命令配置LVGL。

  • 在ESP-IDF项目中使用lvgl_esp32_drivers。

您还可以将lvgl_esp32_drivers添加为“组件”。该组件应位于项目根目录中名为“components”的目录中,和lvgl目录并列。

4. 创建工程项目

  • 复制项目模板

mkdir ~/esp442

cd ~/esp442/

cp -r ~/esp442/esp-idf/examples/get-started/sample_project/ ./esp32_lvgl833

  • 获取LVGL

cd esp32_lvgl833

mkdir components

cd components

  • 下载LVGL最新版本

https://github.com/lvgl/lvgl/tags

git clone -b v8.3.3 https://github.com/lvgl/lvgl.git

  • 获取lvgl_esp32_drivers

git clone https://github.com/lvgl/lvgl_esp32_drivers.git

  • 项目目录结构

其中:Makefile和component.mk可用删除。

5. 编译

  • 刷新esp-idf环境

get_idf

  • 设定目标芯片

idf.py set-target esp32

删除build目录:

rm -r build/

idf.py set-target esp32

  • 配置项目

idf.py menuconfig

1) 将闪存设置为4MB

2) 不选择开发板

3) 选择显示屏控制芯片

或者

4) SPI总线选择

默认是SPI2_HOST。

ESP32有4组SPI外设。

SPI0和SPI1在内部用于访问ESP32所连接的闪存。

SPI2和SPI3是通用SPI控制器,分别称为HSPI和VSPI(LVGL 默认是HSPI)。它们向用户开放。

SPI2和SPI3的默认引脚:

这些引脚是可以重新映射的,所以下面我们的接线和默认并不相同。

在我们的实验中没有使用MISO,所以下面的接线表中没有MISO。

5) 定义引脚

接线表:

ST7735或ST7789         ESP32

GND                              GND

VCC                              3V3

SCL                              IO14(CLK)

SDA                              IO27(MOSI)

RES                              IO16

DC                               IO17(DC)

CS                                IO25

BLK                              IO26

背光控制:

6) 屏幕方向

ST7735横屏

ST7789横屏

7) 设置显示字符大小

对于ST7735因为屏幕小,选用更小的字号12,默认是14。

对于ST7789使用默认14号字:

8) 交换16位颜色的2个字节

ST7735和ST7789的颜色深度是16位,选择Color depth. (16:RGB565),颜色值用2字节表示,ESP32是小端Little Endian模式,先发送低位字节,如果颜色失真,可以选交换颜色值的高低字节。

哪些显示屏需要交换颜色字节,在lvgl_esp32_drivers/README.md中有说明:

9) 不使用定制的lv_conf.h,这是默认

保存,退出。

  • 编译项目

idf.py build

编译警告:

如果开发板(例如M5StickC)上有AXP192电池管理单元,需要在idf.py menuconfig配置中启用:

我们的板子上没有AXP192,所以忽略这些警告。或者删除

~/esp442/esp32_lvgl833/components/lvgl_esp32_drivers/lvgl_tft/st7735s.c

中相关代码。

编译错误:

/home/ct/esp442/esp32_lvgl833/components/lvgl_esp32_drivers/lvgl_helpers.h中添加宏定义:

对于ST7735

/*********************
 *      DEFINES
 *********************/

#define LV_HOR_RES_MAX 160
#define LV_VER_RES_MAX 128
#define SPI_HOST_MAX 3

再修改st7735s.h以适合我们的显示屏

~/esp/lv_port_esp32/components/lvgl_esp32_drivers/lvgl_tft/st7735s.h

#define ST7735_GREENTAB160x80 // For 160 x 80 display (BGR, inverted, 26 / 1 offset)
#define COLSTART            0 //26
#define ROWSTART            0 //1

原来的参数是针对160x80写的,要将COLSTART和ROWSTART都改为0。

对于ST7789只需要修改:

#define LV_HOR_RES_MAX 320
#define LV_VER_RES_MAX 240
#define SPI_HOST_MAX 3

其他地方都不用动。

再编译:

idf.py build

编译通过,这样移植就完成了。

6. LVGL演示

为了看LVGL的效果,我们以

https://github.com/lvgl/lv_port_esp32/tree/master/main/main.c

为例进行演示,其中的代码是针对LVGL 7.9版本写的,我们需要做一些修改。

6.1 基本演示

  1. 修改main.c

现在的main.c是空的:

#include <stdio.h>

void app_main(void)
{

}

用下面的代码替换:

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "lvgl.h"
#include "freertos/semphr.h"
#include "esp_system.h"
#include "lvgl_helpers.h"

/*********************
 *      DEFINES
 *********************/
#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(void)
{
    // xTaskCreate(guiTask, "gui", 4096*2, NULL, 1, NULL);
    // xTaskCreatePinnedToCore(guiTask, "gui", 4096*2, NULL, 1, NULL, 1);
    /* 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_draw_buf_t disp_buf;
    uint32_t size_in_px = DISP_BUF_SIZE;
    /* Initialize the working buffer depending on the selected display. */
    lv_disp_draw_buf_init(&disp_buf, buf1, buf2, size_in_px);

    lv_disp_drv_t disp_drv;
    lv_disp_drv_init(&disp_drv);
    disp_drv.hor_res = LV_HOR_RES_MAX;
    disp_drv.ver_res = LV_VER_RES_MAX;
    disp_drv.flush_cb = disp_driver_flush;
    disp_drv.draw_buf = &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));
        lv_task_handler();

        /* Try to take the semaphore, call lvgl related function on success */
        if (pdTRUE == xSemaphoreTake(xGuiSemaphore, portMAX_DELAY)) {
            lv_task_handler();
            xSemaphoreGive(xGuiSemaphore);
       }
    }
}

static void create_demo_application(void)
{
    /* 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);
    /*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, LV_ALIGN_CENTER, 0, 0);
}

static void lv_tick_task(void *arg) {
    (void) arg;

    lv_tick_inc(LV_TICK_PERIOD_MS);
}
  • 编译

idf.py build

  • 烧写项目

查看USB转串口设备:

ls -l /dev/ttyUSB*

修改权限:

sudo chmod 777 /dev/ttyUSB0

烧写:

idf.py -p /dev/ttyUSB0 -b 460800 flash

  • 启用监视器

idf.py monitor -p /dev/ttyUSB0

当示例正常运行时,将观察到以下输出:

  • ST7735屏显示

  • ST7789屏显示

6.2 examples演示lv_example_get_started_1.c

  • 选择一个例子lv_example_get_started_1.c进行测试

  • 配置项目

idf.py menuconfig

  • 修改main.c

添加头文件:

#include "examples/lv_examples.h"

修改create_demo_application函数

static void create_demo_application(void)
{
    lv_example_get_started_1();
}
  • 修改main目录下的 CMakelists.txt 
idf_component_register(SRCS "main.c" 
"../components/lvgl/examples/get_started/lv_example_get_started_1.c"                     
                    INCLUDE_DIRS ".")
  • 编译、烧写

idf.py build

idf.py -p /dev/ttyUSB0 -b 460800 flash

  • ST7735显示

按钮的颜色是反转的(蓝光与黄光互为补色),字符是正常的,因为字符颜色是白色,高低字节相同,高低字节交换不受影响。

我的解决方法见《ESP32 ESP-IDF LVGL ST7735颜色修正》

ESP32 ESP-IDF LVGL8.3.3 ST7735颜色修正_晨之清风的博客-CSDN博客ESP32 ESP-IDF LVGL8.3.3 ST7735颜色修正。icon-default.png?t=N7T8https://blog.csdn.net/chentuo2000/article/details/128269784?spm=1001.2014.3001.5502这是颜色修正后的效果:

  • ST7789显示

ST7789显示的颜色是正常的。

有一些型号的屏需要在设置中选中Invert colors in display反转颜色,要根据所使用的屏进行测试。

6.3 examples演示lv_example_btnmatrix_2.c

  • 选择另一个例子lv_example_btnmatrix_2.c进行测试

~/esp442/esp32_lvgl833/components/lvgl/examples/widgets/btnmatrix/lv_example_btnmatrix_2.c

  • 修改main.c

添加头文件:

#include "examples/lv_examples.h"

修改create_demo_application函数

static void create_demo_application(void)
{
    lv_example_btnmatrix_2();
}
  • 修改main目录下的 CMakelists.txt 
idf_component_register(SRCS "main.c" 
"../components/lvgl/examples/get_started/lv_example_get_started_1.c" 
"../components/lvgl/examples/widgets/btnmatrix/lv_example_btnmatrix_2.c" 
"../components/lvgl/examples/assets/img_star.c"                    
                    INCLUDE_DIRS ".")
  • 编译、烧写

idf.py build

idf.py -p /dev/ttyUSB0 -b 460800 flash

  • 经过颜色校正的ST7735S显示

对比下面ST7789的显示,小部件(widget)的颜色都对了,五角星图像的颜色还是反转的。如果有需求可以参照《ESP32 ESP-IDF LVGL ST7735颜色修正》一文的方法对图像进行颜色修正。

  • ST7789显示

6.4 demos 演示

  • 配置项目

idf.py menuconfig

选择Show some widget和Enable slide show

  • 修改main.c

添加头文件:

#include "demos/lv_demos.h"
  • 修改create_demo_application函数
static void create_demo_application(void)
{
    #if defined CONFIG_LV_USE_DEMO_WIDGETS
        lv_demo_widgets();
    #elif defined CONFIG_LV_USE_DEMO_KEYPAD_AND_ENCODER
        lv_demo_keypad_encoder();
    #elif defined CONFIG_LV_USE_DEMO_BENCHMARK
        lv_demo_benchmark();
    #elif defined CONFIG_LV_USE_DEMO_STRESS
        lv_demo_stress();
    #else
        #error "No demo application selected."
    #endif
}
  • 修改main目录下的 CMakelists.txt 
idf_component_register(SRCS "main.c" 
"../components/lvgl/demos/widgets/lv_demo_widgets.c" 
"../components/lvgl/demos/widgets/assets/img_lvgl_logo.c" 
"../components/lvgl/demos/widgets/assets/img_demo_widgets_avatar.c"
"../components/lvgl/demos/widgets/assets/img_clothes.c"
                    INCLUDE_DIRS ".")
  • 编译

idf.py build

内存不足,无法运行lv_demo_widget。请将LV_MEM_SIZE设置为至少38KB(38ul*1024ul)。建议使用48KB。

再编译,成功。

  • 烧写

idf.py -p /dev/ttyUSB0 -b 460800 flash

  • 经过颜色校正的ST7735S显示

  • ST7789显示

6.5 其他的官方示例的演示类似。

参考文档

  1. ESP32-IDF Cmake编写要点
    https://blog.csdn.net/qq_43940227/article/details/120893146
  2. 如何在ESP32-C3上添加自己的工程
    https://www.pudn.com/news/6228e06b9ddf223e1ad2e675.html
  3. ESP32,Linux下使用ESP-IDF添加自己的组件库(components)
    https://blog.csdn.net/weixin_41683042/article/details/120698215

ESP32 ESP-IDF LVGL 是一种用于嵌入式系统的开发框架,LVGL 则是一个用于创建嵌入式图形界面的开源图形库。关于视频流的处理,可以通过调用 ESP-IDF 中的函数来实现。在这个项目中,作者使用了 JPEG 流封装 AVI 视频的方法,将实时读取的图片写入 AVI 文件,并保存到 SD 卡中。通过调用相关函数,如 `jpeg2avi_start`、`jpeg2avi_add_frame` 和 `jpeg2avi_end`,可以实现将一帧帧的图片构成的视频保存下来。这个方法结合了作者原理的讲解和详细的代码示例,非常值得参考和感谢作者原野追逐的贡献。在这个项目中,ESP32 通过 LVGL 图形库提供的界面,可以实时读取摄像头数据,并将视频流传输到网页上,同时将读取的图片写入 SD 卡中的 AVI 文件中。然而,由于 ESP32 的处理能力有限,同时完成读取摄像头数据、传输到网页、写入 SD 卡这三个功能对其来说是一项挑战。在测试中,视频流的帧率较低,不够流畅。因此,需要进行性能优化或者考虑其他解决方案来改善视频流的流畅度。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [VScode+esp-idf:例程(esp32-web-camera)保存视频到sd卡(附源码)](https://blog.csdn.net/hwd00001/article/details/126679619)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

晨之清风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值