基于ST7789TFT移植LVGL

原创 嵌入式Lee 2024-05-26 08:00

一. 准备代码

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

下载指定版本,版本9和版本8变化有点大,我这里以用的比较多的版本8为例。

git clone --branch v8.4.0 https://github.com/lvgl/lvgl.git

删除不必要的文件,只保留src,examples/portingdemos文件夹,以及2h文件lv_conf_template.hlvgl.h

|-- demos|   |-- README.md|   |-- benchmark|   |-- keypad_encoder|   |-- lv_demos.h|   |-- lv_demos.mk|   |-- music|   |-- stress|   `-- widgets|-- examples|   `-- porting|-- lv_conf_template.h|-- lvgl.h`-- src    |-- core    |-- draw    |-- extra    |-- font    |-- hal    |-- lv_api_map.h    |-- lv_conf_internal.h    |-- lv_conf_kconfig.h    |-- lvgl.h    |-- misc`-- widgets

Src下是源码,按需添加无需修改

demos下是demo程序

examples/porting下有显示,输入,文件等移植模板

lv_conf_template.h是配置文件模板

lvgl.h是总的头文件

二. 添加源码到自己的工程

添加源码

lvgl/src/core/*.clvgl/src/draw/*.clvgl/src/draw/sw/*.clvgl/src/extra/*.clvgl/src/extra/layouts/flex/*.clvgl/src/extra/layouts/grid/*.clvgl/src/extra/libs/bmp/*.clvgl/src/extra/libs/ffmpeg/*.clvgl/src/extra/libs/freetype/*.clvgl/src/extra/libs/gif/*.clvgl/src/extra/libs/png/*.clvgl/src/extra/libs/qrcode/*.clvgl/src/extra/libs/rlottie/*.clvgl/src/extra/libs/sjpg/*.clvgl/src/extra/libs/tiny_ttf/*.clvgl/src/extra/others/fragment/*.clvgl/src/extra/others/grianav/*.clvgl/src/extra/others/ime/*.clvgl/src/extra/others/imgfont/*.clvgl/src/extra/others/monkey/*.clvgl/src/extra/others/msg/*.clvgl/src/extra/others/snapshot/*.clvgl/src/extra/themes/basic/*.clvgl/src/extra/themes/default/*.clvgl/src/extra/themes/mono/*.clvgl/src/extra/widgets/animimg/*.clvgl/src/extra/widgets/calendar/*.clvgl/src/extra/widgets/chart/*.clvgl/src/extra/widgets/colorwheel/*.clvgl/src/extra/widgets/imgbtn/*.clvgl/src/extra/widgets/keyboard/*.clvgl/src/extra/widgets/led/*.clvgl/src/extra/widgets/list/*.clvgl/src/extra/widgets/menu/*.clvgl/src/extra/widgets/meter/*.clvgl/src/extra/widgets/msgbox/*.clvgl/src/extra/widgets/span/*.clvgl/src/extra/widgets/spinbox/*.clvgl/src/extra/widgets/spinner/*.clvgl/src/extra/widgets/tabview/*.clvgl/src/extra/widgets/tileview/*.clvgl/src/extra/widgets/win/*.clvgl/src/font/*.clvgl/src/hal/*.clvgl/src/misc/*.clvgl/src/widgets/*.c

准备配置文件

复制lv_conf_template.hlv_conf.h放置在lvgl文件夹外和lvgl并列。

#if 0 /*Set it to "1" to enable content*/

改为

#if 1 /*Set it to "1" to enable content*/

准备显示适配文件

复制examples/porting下的lv_port_disp_template.c/h到工程目录,修改为

lv_port_disp.c/h

添加源码lv_port_disp.c到工程,有必要的话需要添加头文件lv_port_disp.h包含路径。

头文件包含路径

lvgl目录添加到头文件包含路径

完成以上工作后,基本完成了框架,但是还没有适配接口,编译还有问题,详细的适配见后面。

三. 适配

3.1 显示适配

前面已经准备好了lv_port_disp.clv_port_disp.h文件。

现在来实现接口,显示适配很简单,只需要实现自己的写点函数或者显示区域函数即可,最开始可以先适配为写点,后面再优化为写区域。

1.使能条件编译

lv_port_disp.c#if 0改为#if 1

lv_port_disp.h#if 0改为#if 1

2.头文件改名

#include "lv_port_disp_template.h"

改为

#include "lv_port_disp.h"

3.设置分辨率

#include

添加

#define MY_DISP_HOR_RES 240

#define MY_DISP_VER_RES 320

4.显示初始化

lv_port_disp_init中保留

Example for 1) 后的代码,注释掉

Example for 2)  Example for 3)后的代码,即使用一个行缓存。

 /* 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[MY_DISP_HOR_RES * 10];                        /*A buffer for 10 rows*/    //static lv_color_t buf_2_2[MY_DISP_HOR_RES * 10];                        /*An other buffer for 10 rows*/    //lv_disp_draw_buf_init(&draw_buf_dsc_2, buf_2_1, buf_2_2, MY_DISP_HOR_RES * 10);   /*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*/

实现初始化

static void disp_init(void){    st7789_itf_init();    /*You code here*/}

5.显示

disp_flush

/*put_px(x, y, *color_p)*/

后添加我们的写点函数

st7789_itf_set_pixel(x, y, *((uint16_t*)color_p));当然前面要包含头文件

#include "st7789_itf.h"

6.颜色格式设置

根据实际配置,我这里是RGB565,所以是16位。

lv_conf.h

#define LV_COLOR_DEPTH 16

这里还可以使用宏LV_COLOR_16_SWAP配置是否交换高低字节(即大小端交换),这适用于适配8位接口传输16位数据时的大小端对应。

LV_COLOR_16_SWAP配置为0不交换,配置为1交换。

7.调用初始化

注意在lv_init后调用lv_port_disp_init

#include "lv_port_disp.h"
lv_init();lv_port_disp_init();

4.1 适配时间戳

lvgl有两种方式获取时间戳,一种是

lv_conf.h中配置宏LV_TICK_CUSTOM0(默认)

然后周期调用lv_tick_inc,比如1ms调用一次即lv_tick_inc(1).

LV_TICK_CUSTOM配置为1

实现宏LV_TICK_CUSTOM_INCLUDE LV_TICK_CUSTOM_SYS_TIME_EXPR

分别是用户提供的实现时间戳获取的头文件和函数。

我这里使用前者,固定周期调用lv_tick_inc

4.2 适配日志打印于assert

lv_conf.h,设置

#define LV_USE_LOG 1 使能日志

设置日志等级,调试时可以设置LV_LOG_LEVEL_TRACE看详细过程,一般设置WARN即可。

#define LV_LOG_LEVEL LV_LOG_LEVEL_WARN

设置打印接口,

#define LV_LOG_PRINTF 1,则使用printf,需要有stdio.h

#define LV_LOG_PRINTF 0,则需要调用lv_log_register_print_cb初始化打印,

比如

static void my_print(const char * buf)

{

wq_printf("%s\r\n",buf);

}

lv_log_register_print_cb(my_print);

lv_init();

lv_conf.h

LV_USE_ASSERT开头的宏设置为1,使能对应的assert

4.5 输入适配

下次再分享

4.6 文件系统适配

下次再分享

.简单测试

参考

examples/get_started/lv_example_get_started_1.c

代码如下:

#include "lvgl.h"#include "lv_port_disp.h"static void tick_callback(void){    lv_tick_inc(1);}
static void my_print(const char * buf){    wq_printf("%s\r\n",buf);}

static void btn_event_cb(lv_event_t * e){    lv_event_code_t code = lv_event_get_code(e);    lv_obj_t * btn = lv_event_get_target(e);    if(code == LV_EVENT_CLICKED) {        static uint8_t cnt = 0;        cnt++;
        /*Get the first child of the button which is the label and change its text*/        lv_obj_t * label = lv_obj_get_child(btn, 0);        lv_label_set_text_fmt(label, "Button: %d", cnt);    }}
/** * Create a button with a label and react on click event. */static void lv_example_get_started_1(void){    lv_obj_t * btn = lv_btn_create(lv_scr_act());     /*Add a button the current screen*/    lv_obj_set_pos(btn, 10, 10);                            /*Set its position*/    lv_obj_set_size(btn, 120, 50);                          /*Set its size*/    lv_obj_add_event_cb(btn, btn_event_cb, LV_EVENT_ALL, NULL);           /*Assign a callback to the button*/
    lv_obj_t * label = lv_label_create(btn);          /*Add a label to the button*/    lv_label_set_text(label, "Button");                     /*Set the labels text*/    lv_obj_center(label);}
void main(void){
    while(1)    {       
        lv_log_register_print_cb(my_print);        lv_init();        lv_port_disp_init();        os_hook_tick_register_callback(tick_callback);    lv_example_get_started_1();        while (1) {            uint32_t delay = lv_timer_handler();            if (delay < 1) delay = 1;            os_delay(delay);            st7789_itf_sync();        }        lv_deinit();    }    return;}

测试效果如下

DEMO测试

添加如下代码到自己的工程

lvgl/demos/benchmark/*.clvgl/demos/benchmark/assets/*.clvgl/demos/keypad_encoder/*.clvgl/demos/music/*.clvgl/demos/music/assets/*.clvgl/demos/stress/*.clvgl/demos/widgets/*.clvgl/demos/widgets/assets/*.c

lv_conf.h中将带DEMO的宏配置为1,可以挑选部分。

这里以MUSICDEMO为例,如果空间不够可以设置LV_DEMO_MUSIC_LARGE0

/*Music player demo*/#define LV_USE_DEMO_MUSIC 1#if LV_USE_DEMO_MUSIC    #define LV_DEMO_MUSIC_SQUARE    1    #define LV_DEMO_MUSIC_LANDSCAPE 1    #define LV_DEMO_MUSIC_ROUND     1    #define LV_DEMO_MUSIC_LARGE     0    #define LV_DEMO_MUSIC_AUTO_PLAY 1#endif

demo需要用到一些字体,lv_conf.h设置LV_FONT_MONTSERRAT_12LV_FONT_MONTSERRAT_22LV_FONT_MONTSERRAT_32,,LV_FONT_MONTSERRAT_16的宏为1

使能以下宏计算帧率

#define LV_USE_PERF_MONITOR 1 

代码如下

#include "lvgl.h"#include "demos/lv_demos.h"#include "lv_port_disp.h"#include "st7789_itf.h"
static void tick_callback(void){    lv_tick_inc(1);}
static void my_print(const char * buf){    wq_printf("%s\r\n",buf);}

void main(void){    while(1)    {        lv_log_register_print_cb(my_print);        lv_init();        lv_port_disp_init();        os_hook_tick_register_callback(tick_callback);        lv_demo_music();        uint32_t pre_time = os_get_ticks();        uint32_t cur_time = pre_time;        while (1) {            uint32_t delay = lv_timer_handler();            cur_time = os_get_ticks();            if(cur_time - pre_time >= 25)            {                pre_time = cur_time;                st7789_itf_sync();            }            if (delay < 1) delay = 1;            os_delay(delay);            //wq_printf("delay %d\r\n",delay);        }
        lv_deinit();    }    return;}

测试结果如下

六. 总结

LVGL的可移植性超级好,只需要实现一个简单的写点或者刷指定范围屏的接口即可,我们也可以其相关可移植性相关的设计。本分享实现了LVGL移植以及DEMO演示,后面可以考虑输入,文件系统相关移植,以及性能的优化。


评论 (0)
  • 什么是散新料?芯片散新料(简称“散新”)是指那些没有原厂包装的原装正品新芯片。这些芯片因为各种原因(例如运输过程中的损坏、批次检测不合格等)没有通过原厂的检测而被以较低的价格卖出,或者是在市场上流通的没有原厂包装的正品芯片。散新料的来源可能多种多样,包括原厂的多余库存、切割下来的晶圆、替换下来的库存元器件等。散新料的特点无原厂包装:散新料通常没有原厂提供的防静电包装或贴有厂商标签的包装,只是简单散装或袋装。原装正品:理论上,散新料仍然是原厂生产的正品,未经过使用或损坏,只是无法提供原厂的包装和质
    大鱼芯城 2024-06-24 11:45 105浏览
  • 在我职业生涯的早期,我曾面临一项挑战,那就是对一款通信设备的EMC测试不合格问题进行整改。那是一个令人焦虑的时刻,因为整个项目的进度都压在了这个看似微不足道的问题上。然而,正是这个挑战,让我深刻理解了EMC的重要性,以及如何有效地解决相关问题。 故事开始于一个普通的工作日,我被指派为该项目的EMC工程师,负责确保我们的产品能够符合国际电磁兼容标准。经过初步的测试,结果显示我们的设备在辐射发射方面超出了规定的限值。这意味着,如果问题不能得到解决,我们的产品将无法上市销售,这将给公司带来巨大的经济
    丙丁先生 2024-06-24 21:01 95浏览
  • 2024年6月18日—全球领先的嵌入式系统开发软件解决方案供应商IAR自豪地宣布,公司推出经TÜV SÜD认证的C-STAT静态分析工具,适用于最新发布的IAR Embedded Workbench for RISC-V V3.30.2功能安全版。经TÜV SÜD认证的C-STAT静态分析工具完全集成在IAR各种功能安全版本中,现在可用于Arm、RISC-V和Renesas RL78架构。TÜV SÜD认证保证了IAR C-STAT静态分析工具符合严格的功能安全标准,该认证包括一份全面的安全指
    电子科技圈 2024-06-25 14:22 68浏览
  • 热设计部分注:小板离变压器不能太近小板离变压器太近,会导致小板上的半导体元件容易受热而影响。工艺处理部分每一块PCB上都必须用箭头标出过锡炉的方向:布局时,DIP封装的IC摆放的方向必须与过锡炉的方向成垂直,不可平行,如下图;如果布局上有困难,可允许水平放置IC(SOP封装的IC摆放方向与DIP相反)。布线方向为水平或垂直,由垂直转入水平要走45度进入。若铜箔入圆焊盘的宽度较圆焊盘的直径小时,则需加泪滴。布线尽可能短,特别注意时钟线、低电平信号线及所有高频回路布线要更短。模拟电路及数字电路的地线
    丙丁先生 2024-06-25 08:00 101浏览
  • 安规距离要求部分包括电气间隙(空间距离),爬电距离(沿面距离)和绝缘穿透距离。1、电气间隙:两相邻导体或一个导体与相邻电机壳表面的沿空气测量的最短距离。2、爬电距离:两相邻导体或一个导体与相邻电机壳表面的沿绝绝缘表面测量的最短距离。一、爬电距离和电气间隙距离要求:1、爬电距离:输入电压50V-250V时,保险丝前L—N≥2.5mm,输入电压250V-500V时,保险丝前L—N≥5.0mm;电气间隙:输入电压50V-250V时,保险丝前L—N≥1.7mm,输入电压250V-500V时,保险丝前L—
    丙丁先生 2024-06-25 07:01 68浏览
  • 2024年6月24日 调研咨询机构环洋市场咨询出版的《2024年全球市场碲化镉薄膜太阳能电池总体规模、主要生产商、主要地区、产品和应用细分研究报告》只要分析全球碲化镉薄膜太阳能电池总体规模,主要地区规模,主要企业规模和份额,主要产品分类规模,下游主要应用规模以及未来发展前景预测。统计维度包括销量、价格、收入,和市场份额。同时也重点分析全球市场主要厂商(品牌)产品特点、产品规格、价格、销量、销售收入及发展动态。历史数据为2019至2023年,预测数据为2024至2030年。 据GIR (Glob
    GIRtina 2024-06-24 14:33 87浏览
  • 2024-6-24调研咨询机构环洋市场咨询出版的【2024年全球市场汽车线缆总体规模、主要生产商、主要地区、产品和应用细分研究报告】只要调研全球汽车线缆总体规模,主要地区规模,主要企业规模和份额,主要产品分类规模,下游主要应用规模以及未来发展前景预测。统计维度包括销量、价格、收入,和市场份额。同时也重点分析全球市场主要厂商(品牌)产品特点、产品规格、价格、销量、销售收入及发展动态。历史数据为2019至2023年,预测数据为2024至2030年。 据GIR (Global Info Resear
    GIRtina 2024-06-24 13:37 94浏览
  • 一、整体布局1、散热片分布均匀,风路通风良好。图一:散热片挡风路,不利于散热;图二:通风良好,利于散热2、电容、IC等与热元件(散热器、整流桥、续流电感、功率电阻)要保持距离以避免受热而受到影响。3、电流环:为了穿线方便,引线孔距不能太远或太近。4、输入/输出、AC/插座要满足两线长短一致,留有一定空间裕量,注意插头线扣所占的位置、插拔方便,输出线孔整齐,好焊线。5、元件之间不能相碰、MOS管、整流管的螺钉位置、压条不能与其它元相碰,以便装配工艺尽量简化电容和电阻与压条或螺钉相碰,在布板时可以先
    丙丁先生 2024-06-25 07:46 99浏览
  • 机智云Gokit 3.0开发板支持Arduino接口。具体来说,它兼容Arduino接口,并集成了经典的传感器组合,如温湿度传感器、红外感应、双向电机和RGB灯等。这使得开发者可以利用Arduino生态系统中的丰富资源和库来扩展其功能,为智能硬件项目带来更多的灵活性和创造力。机智云Gokit 2.0和3.0开发板都是面向智能硬件开发的工具,但它们在硬件设计、软件支持和社区资源等方面存在一些差异。 1. 在硬件设计上,Gokit 2.0 Arduino版本基于Arduino平台,兼容Arduin
    丙丁先生 2024-06-25 10:20 83浏览
  • 什么是UWB呢?所谓UWB(Ultra Wide Band,超宽带),是一种利用超宽带无线载波通信技术的芯片,它通过极短的电磁脉冲来传输数据,并计算从接收器和发射器之间的时间差来确定物体的位置,可以在几厘米到几毫米的范围内定位目标。UWB所使用的频段包括3.1-4.8GHz低频段和6-10.6GHz高频段两种,因此被称为“超宽带”。与不少最近热门的技术一样,UWB(Ultra-Wideband)技术也不是最新才出现的,同样是“科技考古”和“军转民”的产物。其起源于上世纪60年代,UWB技术最初用
    丙丁先生 2024-06-25 09:11 90浏览
  • 抗干扰、EMC部分一、长线路抗干扰在图二中,PCB布局时,驱动电阻R3应靠近Q1(MOS管),电流取样电阻R4、C2应靠近IC1的第4Pin,如图一所说的R应尽量靠近运算放大器缩短高阻抗线路。因运算放大器输入端阻抗很高,易受干扰。输出端阻抗较低,不易受干扰。一条长线相当于一根接收天线,容易引入外界干扰。在图三的A中排版时,R1、R2要靠近三极管Q1放置,因Q1的输入阻抗很高,基极线路过长,易受干扰,则R1、R2不能远离Q1。在图三的B中排版时,C2要靠近D2,因为Q2三极管输入阻抗很高,如Q2至
    丙丁先生 2024-06-25 07:23 80浏览
  • 2024-6-25调研咨询机构环洋市场咨询出版的【2024年全球市场汽车座舱空气质量传感器总体规模、主要生产商、主要地区、产品和应用细分研究报告】只要调研全球汽车座舱空气质量传感器总体规模,主要地区规模,主要企业规模和份额,主要产品分类规模,下游主要应用规模以及未来发展前景预测。统计维度包括销量、价格、收入,和市场份额。同时也重点分析全球市场主要厂商(品牌)产品特点、产品规格、价格、销量、销售收入及发展动态。历史数据为2019至2023年,预测数据为2024至2030年。 据GIR (Glob
    GIRtina 2024-06-25 10:55 57浏览
我要评论
0
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦