嵌入式系统与单片机|技术阅读
登录|注册

您现在的位置是:嵌入式系统与单片机 > 技术阅读 > ESP32S3(ESP-idf v5.1)移植lvgl(v8.3)

ESP32S3(ESP-idf v5.1)移植lvgl(v8.3)


  • 前言

  • 准备工作

    • 硬件

    • 环境

  • 移植

    • 1.新建工程

  • 2.下载额外组件

    • 3. 修改menuconfig

    • 4 编译

    • 5 编写main函数

    • 6 下载

  • 成果

  • 不足


前言

现在开始学习ESP32了,在网上买了块ESP32s3的开发板,点完灯以后的首要事则是点亮屏幕。在点亮屏幕的过程中,发现lvgl仓库中提供的lvgl_esp32_drivers并不能顺利,原因在于ESP-idf和lvgl更新的太快,导致有的函数不在适用。本文将使用最新的ESP-idf(v5.1)和lvgl(v8.3)点亮屏幕。

准备工作

硬件

没有使用官方的(有点小贵),顺便买个平替版。flash为16M

屏幕使用一款TFT屏幕,分辨率为240*240,通信方式为SPI,驱动为ST7789。没有触摸芯片

环境

使用vscode插件:vscode-esp-idf-extension。其安装方法见官网;选择最新的稳定版本v5.1;

移植

1.新建工程

在vscode中打开命令面板,输入ESP-IDF:New Project

填写工程名字,选择路径,选择芯片,最后选择模板

本次选择ESP-idf

2.下载额外组件

ESP-idf中不包含lvgl,所以需要将lvgl和相应的驱动lvgl_esp32_drivers作为额外组件,放在工程中

  • 新建在工程中新建文件夹components,
  • 下载lvglvgl_esp32_drivers
  • git clone git@github.com:lvgl/lvgl_esp32_drivers.git
    git clone -b release/v8.3 git@github.com:lvgl/lvgl.git

    工程结构如下


    3. 修改menuconfig

    修改flash

    lvgl_esp32_drivers

    • 驱动芯片:ST7789;
    • 引脚配置;
    TFTESP32工程配置
    SCL13CLK
    SDA12MISO
    RES11Rest
    DC10DC
    CS9CS
    BLC46勾选高电平为点亮屏幕

    4 编译

    编译阶段主要根据错误提示做出修改。

    错误1:fatal error: driver/ledc.h: No such file or directory

    D:/myself/ESP32s3/lvgl/components/lvgl_esp32_drivers/lvgl_tft/esp_lcd_backlight.c:10:10: fatal error: driver/ledc.h: No such file or directory
       10 | #include "driver/ledc.h"
          |          ^~~~~~~~~~~~~~~
    compilation terminated.
    • 原因:没有依赖driver组件
    • 办法:在components\lvgl_esp32_drivers\CMakeLists.txt中增加driver的依赖
    idf_component_register(SRCS ${SOURCES}
    INCLUDE_DIRS ${LVGL_INCLUDE_DIRS}
    REQUIRES lvgl
    REQUIRES driver)

    错误2:implicit declaration of function 'gpio_pad_select_gpio' and 'portTICK_RATE_MS' undeclared

    D:/myself/ESP32s3/lvgl/components/lvgl_esp32_drivers/lvgl_tft/st7789.c:89:5: error: implicit declaration of function 'gpio_pad_select_gpio'; did you mean 'esp_rom_gpio_pad_select_gpio'? [-Werror=implicit-function-declaration]
       89 |     gpio_pad_select_gpio(ST7789_DC);
          |     ^~~~~~~~~~~~~~~~~~~~
          |     esp_rom_gpio_pad_select_gpio
    D:/myself/ESP32s3/lvgl/components/lvgl_esp32_drivers/lvgl_tft/st7789.c:100:22: error: 'portTICK_RATE_MS' undeclared (first use in this function); did you mean 'portTICK_PERIOD_MS'?
      100 |     vTaskDelay(100 / portTICK_RATE_MS);
          |                      ^~~~~~~~~~~~~~~~
          |                      portTICK_PERIOD_MS
    • 原因:gpio_pad_select_gpio()portTICK_RATE_MS发生变化;
    • 办法:根据提示替换:gpio_pad_select_gpio()替换为esp_rom_gpio_pad_select_gpio()portTICK_RATE_MS替换为portTICK_PERIOD_MS

    错误3:error: 'LV_HOR_RES_MAX' undeclared

    D:/myself/ESP32s3/lvgl/components/lvgl_esp32_drivers/lvgl_helpers.h:41:25: error: 'LV_HOR_RES_MAX' undeclared (first use in this function); did you mean 'LV_HOR_RES'?
       41 | #define DISP_BUF_SIZE  (LV_HOR_RES_MAX * 40)
    • 原因:缺少宏定义
    • 办法:添加

    components\lvgl_esp32_drivers\lvgl_helpers.h添加缺少的宏定义

    // 屏幕分辨率
    #define LV_HOR_RES_MAX 240
    #define LV_VER_RES_MAX 240

    错误4:error: 'ledc_timer_config_t' has no member named 'bit_num'

    D:/myself/ESP32s3/lvgl/components/lvgl_esp32_drivers/lvgl_tft/esp_lcd_backlight.c:52:14: error: 'ledc_timer_config_t' has no member named 'bit_num'
       52 |             .bit_num = LEDC_TIMER_10_BIT,
    • 原因:结构体成员发生变化
    • 办法:按照新的结构体删除.bit_num成员
    typedef struct {
        ledc_mode_t speed_mode;                /*!< LEDC speed speed_mode, high-speed mode or low-speed mode */
        ledc_timer_bit_t duty_resolution;      /*!< LEDC channel duty resolution */
        ledc_timer_t  timer_num;               /*!< The timer source of channel (0 - LEDC_TIMER_MAX-1) */
        uint32_t freq_hz;                      /*!< LEDC timer frequency (Hz) */
        ledc_clk_cfg_t clk_cfg;                /*!< Configure LEDC source clock from ledc_clk_cfg_t.
                                                    Note that LEDC_USE_RC_FAST_CLK and LEDC_USE_XTAL_CLK are
                                                    non-timer-specific clock sources. You can not have one LEDC timer uses
                                                    RC_FAST_CLK as the clock source and have another LEDC timer uses XTAL_CLK
                                                    as its clock source. All chips except esp32 and esp32s2 do not have
                                                    timer-specific clock sources, which means clock source for all timers
                                                    must be the same one. */

    ledc_timer_config_t;

    错误5:error: implicit declaration of function 'gpio_matrix_out'

    D:/myself/ESP32s3/lvgl/components/lvgl_esp32_drivers/lvgl_tft/esp_lcd_backlight.c:58:9: error: implicit declaration of function 'gpio_matrix_out'; did you mean 'gpio_iomux_out'? [-Werror=implicit-function-declaration] 
       58 |         gpio_matrix_out(config->gpio_num, ledc_periph_signal[LEDC_LOW_SPEED_MODE].sig_out0_idx + config->channel_idx, config->output_invert, 0);
          |         ^~~~~~~~~~~~~~~
          |         gpio_iomux_out
    • 原因:函数名发生变化
    • 办法:将gpio_iomux_out()修改为esp_rom_gpio_connect_out_signal()

    基于参数uint32_t gpio_num, uint32_t signal_idx, bool out_inv, bool oen_inv在ESP-idf文件夹中进行查找,可以查找替换函数。

    错误6:error: 'SIG_GPIO_OUT_ID ' undeclared (first use in this function)

    • 原因:SIG_GPIO_OUT_ID宏定义不存在
    • 办法:通过查找,发现 SIG_GPIO_OUT_IDgpio_sig_map.h中,添加该头文件
    #include "soc/gpio_sig_map.h"

    5 编写main函数

    #include <stdio.h>
    #include "esp_log.h"
    #include "esp_system.h"
    #include "freertos/FreeRTOS.h"
    #include "freertos/event_groups.h"
    #include "lvgl.h"
    #include "lvgl_helpers.h"
    #include "esp_timer.h"
     
    #include "demos/lv_demos.h"
     
     
    #define TAG "main"
     
    void lv_tick_task(void *arg)
    {
        lv_tick_inc(1);
    }
     
    void app_main(void)
    {
        
        /* Initialize SPI or I2C bus used by the drivers */
        lvgl_driver_init();
     
        lv_init();
        lv_color_t *buf1 = heap_caps_malloc(DISP_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA);
        assert(buf1 != NULL);
        static lv_color_t *buf2 = NULL;
     
        static lv_disp_draw_buf_t disp_buf;
     
        uint32_t size_in_px = DISP_BUF_SIZE;
        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);
     
        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, 1 * 1000));
     
        // lvgl demo演示
        lv_demo_widgets();

        while (1)
        {
            /* Delay 1 tick (assumes FreeRTOS tick is 10ms */
            vTaskDelay(pdMS_TO_TICKS(10));
            lv_task_handler();
        }
     
     
    }

    6 下载

    报错

    E (398) spi: spi_bus_initialize(774): invalid dma channel, chip only support spi dma channel auto-alloc

    lvgl_helpers.c添加:

     #if defined (CONFIG_IDF_TARGET_ESP32C3)
        dma_channel = SPI_DMA_CH_AUTO;
        #elif defined (CONFIG_IDF_TARGET_ESP32S3)  # 添加
        dma_channel = SPI_DMA_CH_AUTO;     # 添加
        #endif

    屏幕颜色错误:

    修改lv_conf.hLV_COLOR_16_SWAP修改为1

    /*Swap the 2 bytes of RGB565 color. Useful if the display has an 8-bit interface (e.g. SPI)*/
    #define LV_COLOR_16_SWAP 1

    成果

    不足

  • 对于lv_conf.h中的参数了解不深入,基本上采用默认配置;
  • lvgl没有开线程;
  • 没有启用触摸功能;
  • 若需要完整代码,请私信(修改时忘记fock了)