LVGL 移植到 STM32 通法 ( 例:LVGL 9.2.2 到 STM32F429 )

 

心法:

以往看过很多的移植教程、在 Keil 里面添加很多的文件分组、进到 LVGL 源码文件夹,进进出出多级目录添加很多的源码文件、这个添加,那个不需要添加,着实吓人 + 劝退人。

 但其实:

1. Keil 里面的文件分组的 组织结构、取名对编译根本不重要,只是方便程序员管理文件。 不过要注意,需要把  .c 文件添加 (实际就是让 Keil 记录该文件的路径) 到 Keil 工程,Keil 才会编译该源码文件,生成对应的  .o 文件。

2. 把 LVGL 源码全添加进 Keil 编译也是没问题的、把  .c  文件编译成  .o  二进制文件,在链接阶段,链接器需要哪个 .o  文件自己拿去链接就行,对这方面感到疑惑的可以看 C/C++编译过程

对于各种工程 (包括非 STM32 的 C/C++工程):

多余添加源码文件进编译:

绝大部分情况下是没问题的,不被调用的函数 链接器 不会使用 那个函数所在的  .o  文件。多余添加源码文件的影响只有增加编译时间、产生多一点的  .o  文件占用电脑硬盘,最终编译出来的目标文件即烧录进 STM32 的那个文件保持不变。

极少数情况下,多添加文件进行编译会产生冲突,比如 STM32F429 的 FMC 和 FSMC 源文件,同时只能编译一个,这还可能是 库文件设计者 有意为之。

少添加源码文件进编译:

必定出问题,找不到头文件、函数未定义、符号未定义 等等。

 

材料准备:

1. 获取 LVGL 源码

建议电脑安装 TortoiseGit ,可以以图形界面方式使用 Git。

(选择)进到一个文件夹,空白处右键  再点击Git Clone , 输入 LVGL 源码链接 https://github.com/lvgl/lvgl.git,将LVGL 源码克隆到本地。

进到 LVGL 源码目录,如需回退源码到最新发布的版本,以图更稳定可靠,可右键选择 TortoiseGit--》 Switch/Checkout --》选择 Tag , 往下拉选择最新的 Tag。 

 按需 取消勾选 Create New Brach。 

 LVGL 9.2.2 源码文件夹 如下图:

不管版本如何变,移植到 STM32 (用 Keil 编译) 时,src 文件夹和 源码根目录 下的 .h 、.c  文件都一概先复制过去。

下图高亮的是本次移植用到的文件(夹)

2. STM32 触摸屏工程

 广告:如 野火的工程:

野火的教程、代码风格真是好,SMT32 和 FreeRTOS 教会了我很多,感谢野火。可惜我当年不懂得,错买了正点的板子。

所以呢,我这个列子用的是 正点原子 的板子 STM32F429,搭载的是 SPI 接口的 4.3 寸 MCU 电容式触摸屏。

吐槽:鉴于商家配套教材信息密度、行文风格、源码风格、PDF手册权限等问题,不建议购买正点原子的东西。

 

文件路径及组织结构

一级 lvgls:

在 触摸屏 工程根目录下创建一个 lvgls 文件夹 ( 可以取名其它英文字母名 )。

二级 lvgl 及 lv_app:

lvgls 下创建 lvgl 和 lv_app 文件夹,同理 这两个文件夹也可以取名其它英文字母名 。lv_app 是后面放自己写的 代码,本次工程没用到。

三级源码文件(夹):

lvgl 下的 demos、src 文件夹 直接原封不动从 LVGL 源码文件夹复制过来。

examples 文件夹也可以直接从 LVGL 源码文件夹原封不动复制过来,但实际只需要里面的 porting 文件夹,所以自己精简。

LVGL 源码文件夹根目录的  .c 、.h  文件一并复制过来。

lvgl 下的 lv_conf_template.h 复制到上一层目录,并改名为  lv_conf.h 。

 将 lvgl / examples / porting 中选中的文件复制到 与 lv_conf.h 文件同一目录下,并把 template 字眼去掉。分别是 ( **disp )显示 设备和 (**indev )输入设备的接口。

 完成后  lvgls 文件夹下 :

 

LVGL文件添加到 Keil 工程:

src 文件分组

根据 lvgl / src 下的文件夹 (左) 在 keil 中创建相应的分组 (右),并多加一个 LVGL_SRC  用于添加 lvgl /src 下的  .c  文件,本例子中是 lv_init.c 。

 

没有注明的话,src 文件夹包括 各级子文件夹 所有  .c 文件都添加到 Keil 的相应分组中。

当然根据文章开头说的,不嫌麻烦可以一股脑添加完所有  .c 文件进 Keil 编译。

draw 中不需要添加 nxp 、renesas 、sdl 文件夹,其他均添加。

drivers 文件夹 都不 添加

libs 一定要添加 bin_decoder , 实际操作我把 图里 框中的都加上了,其它都不加。

 

千万记得 lvgl / src 下面的  .c  文件也要添加进 Keil , 本例中加到 LVGL_SRC 分组,本例中是 lv_init.c 。

 把头文件路径加到 Keil : 深度只需要到 lvgl / src /core 这个级别。当然,手动添加头文件路径有点烦,后面有骚操作

 

骚操作:你可以先保存好 Keil 工程、关闭工程,用高级一点的文本编辑器打开 Keil 工程文件( .uvprojx 文件)。

所谓的高级一点为的是 能 设置、区分 Windows、Unix、Macintosh文件?结尾 。这么说只是为了更保险,一般编辑软件都可以。

工程文件中搜索 IncludePath 观察已有的 头文件路径信息,确定好该往这个位置加入新的头文件路径,即可复制我的路径去使用。

如果你的 lvgl 文件位置和文件夹名称和我的一样,就可以啥也不改,直接黏贴。( 可以删除下面 每行末尾的回车符,多余加的回车符是为了利于阅读)

复制代码
..\lvgls;
..\lvgls\lvgl;
..\lvgls\lvgl\src;
..\lvgls\lvgl\src\core; ..\lvgls\lvgl\src\display;
..\lvgls\lvgl\src\draw;
..\lvgls\lvgl\src\drivers; ..\lvgls\lvgl\src\font;
..\lvgls\lvgl\src\indev;
..\lvgls\lvgl\src\layouts; ..\lvgls\lvgl\src\libs;
..\lvgls\lvgl\src\misc;
..\lvgls\lvgl\src\osal; ..\lvgls\lvgl\src\others;
..\lvgls\lvgl\src\stdlib;
..\lvgls\lvgl\src\themes; ..\lvgls\lvgl\src\tick;
..\lvgls\lvgl\src\widgets;
..\lvgls\lvgl\demos; ..\lvgls\lvgl\demos\benchmark;
..\lvgls\lvgl\demos\widgets; ..\lvgls\lvgl\demos\scroll;
..\lvgls\lvgl\demos\music
复制代码

 

其实 Keil 中的文件分组也可以用这个套路快速添加,我添加的时候 修改两个工程文件,那个修改包含太多文字,就不贴出来了,大家还是多熟悉一下操作。

Keil 中再 创建 LVGL_PORTING 和 LVGL_DEMO 分组:

LVGL_PORTING 添加 lvgls 文件夹下的  .c  文件——显示和触摸驱动接口文件,把 lv_conf.h 也加进来便于修改。

LVGL_DEMO 添加  lvgl /demos  根目录下的  .c 文件 ( 本例是 lv_demos.c) 以及 widgets 子文件夹下所有  .c 文件,我们先跑 widgets 这个例子。

还想跑其他例子,就自己加相应例子文件, 实际我还加了 bechmark、scroll、music 例子的。

 给 Keil 添加头文件路径:

 

 

修改 Keil 工程代码:

涉及的文件:

 

改堆栈 大小 

启动文件 startup_stm32f429xx.s 改 stack 和 heap 大小, 都为 0x2000 ,即 8 K 

 

给 lvgl 加心跳

伴随 HAL_IncTick(); 所在位置,本例是 stm32f4xx_it.c  文件中:

复制代码
 #include "lv_tick.h"

/****其它******/

void SysTick_Handler(void)
{
    HAL_IncTick();
    lv_tick_inc(1);
}
复制代码

当然也可以 改为 选择在 定时器中断中 执行   lv_tick_inc(1); 。 

lv_confg.h 中 :

打开 lv_conf.h ,把 第一个 # if 0  改为 # if 1 从而使能文件,下文简称 使能文件。

文件中 #define LV_COLOR_DEPTH 16  是配置屏幕色彩深度、我的 LCD 屏幕是 RGB565 , 所以保持无需变更。

有使能 demo 的宏,本例跑 widgets 例子,所以使能:

lv_port_disp.c 中:

使能文件后,添加需要的 屏幕头文件,我这里多加了 usart.h 是为了使用 printf 函数,在串口打印调试信息。

修改屏幕分辨率适配自己的屏幕。

 修改 lv_port_disp_init 函数,分配 内存,有三种分配方式,本例用了模板 的 Example 1 , 目前我的理解是 LVGL 将像素信息输出到这个内存空间,然后 STM32 从这个空间获取像素信息赋值给 屏幕显示。

比如  LVGL ——》该内存空间——》DMA2D 外设自动复制该空间的(像素)数据到 ——》 STM32另一个内存空间(通常是称为 显存 的内存空间,通常在 SDRAM 中分配)——》 LTDC 自动复制 显存中的(像素)数据到 ——》LCD屏幕

本例中有 SDRAM 的,使用__attribute__ ((at( 0XC03E8000))) 分配到了 SDRAM 中,本例中SDRAM 开始的地址为 0XC0000000,之所以放到 0XC03E8000 是因为前面的空间可能被其他工程代码用作 LCD 的显存。

 修改 disp_flush 函数。这个得阅读 屏幕驱动函数了,就是找 在一个矩形空间填充彩色像素能用哪个函数,或者用绘制一个彩色点的函数一个个像素点绘制(会比较慢)。

其中  px_map 是指向像素数据的指针,目前我的理解是传入 屏幕驱动函数 如 LCD_Color_Fill  时,px_map 被强制转换成相应的类型,如本例的 (u16* ) ,

其本质是与 屏幕颜色深度相关、其次是与 LCD_Color_Fill 函数原型相关。

lv_port_indev.c 中:

使能文件、添加必要的 触摸屏头文件如 #include "touch.h"

函数 lv_port_indev_init 中仅保留 touchpad 部分的代码,其他可以用 # if  0   及 #endif 编译宏失能。 

 修改 touchpad_is_pressed 和 touchpad_get_xy 函数 :

main.c 中:

引入头文件

#include "lvgl.h"
#include "lv_port_disp.h"
#include "lv_port_indev.h"
#include "lv_demos.h"
#include "lv_demo_widgets.h

mian 函数

复制代码
int main(void)
{
    HAL_Init();                      //初始化HAL库   
    Stm32_Clock_Init(360,25,2,8);   //设置时钟,180Mhz
    delay_init(180);                //初始化延时函数
    uart_init(115200);              //初始化USART
    LED_Init();                     //初始化LED 
    KEY_Init();                     //初始化按键
    SDRAM_Init();                   //初始化SDRAM
    LCD_Init();                     //初始化LCD
    tp_dev.init();                  //触摸屏初始化 

#if 1
    LCD_Display_Dir(1);       // LCD 设为横屏
    tp_dev.touchtype = 1;   // 触摸屏 设为横屏
    lv_init();
    lv_port_disp_init();
    lv_port_indev_init();

    lv_demo_widgets();
    //lv_demo_scroll();
    //lv_demo_benchmark();
    //lv_demo_music();

    while (1)
    {
        lv_timer_handler();
        HAL_Delay(5);
    }

#endif 
}
复制代码

设置 Keil 使用 C99 标准编译:

 

编译、烧录、运行、大功告成。

 

个人想法:

就 移植中看到的,LVGL 和 FreeRTOS 很像,都有一个心跳(如 lv_tick_inc(1); )用于知晓时间、一个句柄(如 lv_timer_handler(); )作为入口,然后创建一些任务,它们会自己去处理、执行任务。

 

posted @   星云体  阅读(1644)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· NetPad:一个.NET开源、跨平台的C#编辑器
点击右上角即可分享
微信分享提示