1.硬件
1.硬件设计
① 开发板型号:ESP32-WROOM-32
2.显示屏幕:
① 2.4寸液晶屏2.4寸TFT LCD SPI串口240*320模块TFT彩屏ST7789驱动
本次2.4寸显示器链接
2.软件设计
2.1 创建一个示例项目
1.怎么创建一个示例项目和创建lvgl组件,添加后先编译,确保创建示例没有问题,请参考前面的文档。
2.2 添加lvgl相关文件
2.2.1 下载相关文件
1.下载lvgl/lvgl中的release/v8.3
下载lvgl v8.3链接
2.需要下载ESP32的驱动程序
下载ESP32的驱动程序链接
2.2.2配置components的文件
① 找到项目的 components/lvgl 文件夹,将上面下载的文件解压到 components/lvgl 中,
并将
lvgl_esp32_drivers-master —> lvgl_esp32_drivers
lvgl-release-v8.3 —> lvgl
② 在示例中的components/lvgl/lvgl-release-v8.3/examples中的porting复制到lvgl中,重命名为lvgl_porting。
如下:
2.2.3添加CMakeLists.txt的文件
1.添加CMakeLists.txt文件相当于告诉编译器文件到哪里去找。
2.在lvgl_porting文件中添加CMakeLists.txt内容如下:
file(GLOB_RECURSE SOURCES ./*.c
)
idf_component_register(SRCS ${SOURCES}
INCLUDE_DIRS
.
REQUIRES lvgl
lvgl_esp32_drivers)
3.修改顶层CMakeLists.txt中添加如下:
set(EXTRA_COMPONENT_DIRS "${EXTRA_COMPONENT_DIRS} components/lvgl")
4.顶层Makefile中添加
EXTRA_COMPONENT_DIRS += $(PROJECT_PATH)/components/lvgl
5.在项目中找到components/lvgl/env_support/cmake/esp.cmake 代码如下:
file(GLOB_RECURSE SOURCES ${LVGL_ROOT_DIR}/src/*.c
${LVGL_ROOT_DIR}/demos/*.c)
idf_build_get_property(LV_MICROPYTHON LV_MICROPYTHON)
if(LV_MICROPYTHON)
idf_component_register(
SRCS
${SOURCES}
INCLUDE_DIRS
${LVGL_ROOT_DIR}
${LVGL_ROOT_DIR}/src
${LVGL_ROOT_DIR}/../
${LVGL_ROOT_DIR}/demos
REQUIRES
main)
target_compile_definitions(${COMPONENT_LIB}
INTERFACE "-DLV_CONF_INCLUDE_SIMPLE")
if(CONFIG_LV_ATTRIBUTE_FAST_MEM_USE_IRAM)
target_compile_definitions(${COMPONENT_LIB}
INTERFACE "-DLV_ATTRIBUTE_FAST_MEM=IRAM_ATTR")
endif()
else()
idf_component_register(SRCS ${SOURCES} INCLUDE_DIRS ${LVGL_ROOT_DIR}
${LVGL_ROOT_DIR}/src ${LVGL_ROOT_DIR}/../ ${LVGL_ROOT_DIR}/demos)
target_compile_definitions(${COMPONENT_LIB} PUBLIC "-DLV_CONF_INCLUDE_SIMPLE")
if(CONFIG_LV_ATTRIBUTE_FAST_MEM_USE_IRAM)
target_compile_definitions(${COMPONENT_LIB}
PUBLIC "-DLV_ATTRIBUTE_FAST_MEM=IRAM_ATTR")
endif()
endif()
2.3 配置lvgl文件程序和配置
2.3.1配置lvgl文件程序
1.将 lvgl_porting中 的 lv_port_disp_template.c 改为 lv_port_disp.c 并将#if 0 改为#if 1 如下:
#if 1
#include "lv_port_disp_template.h"
#include <stdbool.h>
....
#endif
2.将 lvgl_porting 中的 lv_port_disp_template.h 改为 lv_port_disp.h中 #if 0 改为#if 1 如下:
#if 1
#ifndef LV_PORT_DISP_TEMPL_H
#define LV_PORT_DISP_TEMPL_H
...
#endif
3.将lvgl_esp32_drivers中 lvgl_helpers.h 中修改:
#if defined (CONFIG_CUSTOM_DISPLAY_BUFFER_SIZE)
#define DISP_BUF_SIZE CONFIG_CUSTOM_DISPLAY_BUFFER_BYTES
#else
//添加部分
#ifndef LV_HOR_RES_MAX
#define LV_HOR_RES_MAX (320)
#endif
#ifndef LV_VER_RES_MAX
#define LV_VER_RES_MAX (240)
#endif
//end
#if defined (CONFIG_LV_TFT_DISPLAY_CONTROLLER_ST7789)
4.将lvgl_esp32_drivers中 lvgl_helpers.c 中修改如下:
bool lvgl_spi_driver_init(int host,
int miso_pin, int mosi_pin, int sclk_pin,
int max_transfer_sz,
int dma_channel,
int quadwp_pin, int quadhd_pin)
{
// assert((0 <= host) && (SPI_HOST_MAX > host));
// const char *spi_names[] = {
// "SPI1_HOST", "SPI2_HOST", "SPI3_HOST"
// };
#if defined(CONFIG_IDF_TARGET_ESP32)
assert((SPI_HOST <= host) && (VSPI_HOST >= host));
const char *spi_names[] = {
"SPI_HOST", "HSPI_HOST", "VSPI_HOST"};
dma_channel = SPI_DMA_CH_AUTO;
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
assert((SPI_HOST <= host) && (HSPI_HOST >= host));
const char *spi_names[] = {
"SPI_HOST", "", ""};
dma_channel = SPI_DMA_CH_AUTO;
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
assert((SPI1_HOST <= host) && (SPI3_HOST >= host));
const char *spi_names[] = {
"SPI1_HOST", "SPI2_HOST", "SPI3_HOST"};
dma_channel = SPI_DMA_CH_AUTO; /* SPI_DMA_CH_AUTO */;
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
assert((SPI1_HOST <= host) && (SPI3_HOST >= host));
const char *spi_names[] = {
"SPI_HOST", "HSPI_HOST", "VSPI_HOST"};
dma_channel = SPI_DMA_CH_AUTO;
#else
#error "Target chip not selected"
#endif
ESP_LOGI(TAG, "Configuring SPI host %s", spi_names[host]);
ESP_LOGI(TAG, "MISO pin: %d, MOSI pin: %d, SCLK pin: %d, IO2/WP pin: %d, IO3/HD pin: %d",
miso_pin, mosi_pin, sclk_pin, quadwp_pin, quadhd_pin);
ESP_LOGI(TAG, "Max transfer size: %d (bytes)", max_transfer_sz);
spi_bus_config_t buscfg = {
.miso_io_num = miso_pin,
.mosi_io_num = mosi_pin,
.sclk_io_num = sclk_pin,
.quadwp_io_num = quadwp_pin,
.quadhd_io_num = quadhd_pin,
.max_transfer_sz = max_transfer_sz
};
ESP_LOGI(TAG, "Initializing SPI bus...");
#if defined (CONFIG_IDF_TARGET_ESP32C3)
dma_channel = SPI_DMA_CH_AUTO;
#endif
esp_err_t ret = spi_bus_initialize(host, &buscfg, (spi_dma_chan_t)dma_channel);
assert(ret == ESP_OK);
return ESP_OK != ret;
}
4.将lvgl_porting中 lv_port_disp.c 中修改如下:
//1.删除
// #ifndef MY_DISP_HOR_RES
// #warning Please define or replace the macro MY_DISP_HOR_RES with the actual screen width, default value 320 is used for now.
// #define MY_DISP_HOR_RES 320
// #endif
// #ifndef MY_DISP_VER_RES
// #warning Please define or replace the macro MY_DISP_HOR_RES with the actual screen height, default value 240 is used for now.
// #define MY_DISP_VER_RES 240
// #endif
//2.修改lv_port_disp_init(void)
void lv_port_disp_init(void)
{
/*-------------------------
* Initialize your display
* -----------------------*/
disp_init();
/**
* LVGL requires a buffer where it internally draws the widgets.
* Later this buffer will passed to your display driver's `flush_cb` to copy its content to your display.
* The buffer has to be greater than 1 display row
*
* There are 3 buffering configurations:
* 1. Create ONE buffer:
* LVGL will draw the display's content here and writes it to your display
*
* 2. Create TWO buffer:
* LVGL will draw the display's content to a buffer and writes it your display.
* You should use DMA to write the buffer's content to the display.
* It will enable LVGL to draw the next part of the screen to the other buffer while
* the data is being sent form the first buffer. It makes rendering and flushing parallel.
*
* 3. Double buffering
* Set 2 screens sized buffers and set disp_drv.full_refresh = 1.
* This way LVGL will always provide the whole rendered screen in `flush_cb`
* and you only need to change the frame buffer's address.
*/
/* Example for 1) */
// static lv_disp_draw_buf_t draw_buf_dsc_1;
// static lv_color_t buf_1[MY_DISP_HOR_RES * 10]; /*A buffer for 10 rows*/
// lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, NULL, MY_DISP_HOR_RES * 10); /*Initialize the display buffer*/
/* Example for 2) */
static lv_disp_draw_buf_t draw_buf_dsc_2;
static lv_color_t buf_2_1[DISP_BUF_SIZE]; /*A buffer for 10 rows*/
static lv_color_t buf_2_2[DISP_BUF_SIZE]; /*An other buffer for 10 rows*/
lv_disp_draw_buf_init(&draw_buf_dsc_2, buf_2_1, buf_2_2,DISP_BUF_SIZE); /*Initialize the display buffer*/
/* Example for 3) also set disp_drv.full_refresh = 1 below*/
// static lv_disp_draw_buf_t draw_buf_dsc_3;
// static lv_color_t buf_3_1[MY_DISP_HOR_RES * MY_DISP_VER_RES]; /*A screen sized buffer*/
// static lv_color_t buf_3_2[MY_DISP_HOR_RES * MY_DISP_VER_RES]; /*Another screen sized buffer*/
// lv_disp_draw_buf_init(&draw_buf_dsc_3, buf_3_1, buf_3_2,
// MY_DISP_VER_RES * LV_VER_RES_MAX); /*Initialize the display buffer*/
/*-----------------------------------
* Register the display in LVGL
*----------------------------------*/
static lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/
lv_disp_drv_init(&disp_drv); /*Basic initialization*/
/*Set up the functions to access to your display*/
/*Set the resolution of the display*/
disp_drv.hor_res = LV_HOR_RES_MAX;
disp_drv.ver_res = LV_VER_RES_MAX;
/*Used to copy the buffer's content to the display*/
disp_drv.flush_cb = disp_driver_flush;
/*Set a display buffer*/
disp_drv.draw_buf = &draw_buf_dsc_2;
/*Required for Example 3)*/
//disp_drv.full_refresh = 1;
/* Fill a memory array with a color if you have GPU.
* Note that, in lv_conf.h you can enable GPUs that has built-in support in LVGL.
* But if you have a different GPU you can use with this callback.*/
//disp_drv.gpu_fill_cb = gpu_fill;
/*Finally register the driver*/
lv_disp_drv_register(&disp_drv);
}
3.添加lvgl_driver_init();
/*Initialize your display and the required peripherals.*/
static void disp_init(void)
{
/*You code here*/
lvgl_driver_init();
}
2.3.2 配置config
1.修改完后,就要配置lvgl的config
2.选择字体库
3.添加music的dome
4.使能spi的GPIO
配置好后保存,重新编译,下载后显示如下: