关注+星标公众号,不错过精彩内容
作者 | 量子君
微信公众号 | 极客工作室
【LVGL进阶日记】专栏介绍
本章目录
前言 一、问题背景/现状 二、过程分析/优化的思路 三、结论和经验 四、附录 总结
前言
一、LVGL简介
在加载外部flash字库时,字库刷新速度明显慢于内部存储的字库
字库文件组成:索引区+段位区+偏移区+MAP点阵数据区
二、过程分析/优化的思路
首先怀疑SPI读取速度过慢,由于SPI速率设置为8M,故理论上不存在此问题。
字库显示原理分为LVGL内部处理流程和通过LITTLE FS读取外部字库信息两部分,通过LOG打印时间戳(NRF_RTC1->COUNTER),查看两部分的时间差异。(为排除干扰,内外字库只显示一个相同的文字)。
首先获取整个调度逻辑的耗时,只查看内外部字库差异点时间,故从_user_font_get_glyph_dsc2接口开始打印(注:此次使用的文字unicode码为0xad6d),到_user_font_get_bitmap2接口里的mg_font_get_mapdata函数(此函数是读取外部FLASH的函数)执行完毕结束。
通过log,发现外部字库需要32个时钟周期,内部字库需要16个,且_user_font_get_glyph_dsc2函数被调用了11次,user_font_get_bitmap 2被调用了3次。
查找步骤4两个函数被多次调用的原因,查看LVGL源码,根据调用次数及文字的字模信息发现,_user_font_get_bitmap2的调用次数与字模高度有关,LVGL会按照字模高度8的倍数进行多次调用,_user_font_get_glyph_dsc2函数会在获取字模的长宽高等数据时被多次调用;等于说要显示一个文字,如果字高为24,需要至少调用三次_user_font_get_glyph_dsc2,但获取外部点阵数据的函数每次都是将所有点阵信息一次性读取,等于重复了三次,内部字库虽也需读三次,但读片内FLASH速度快,不存在此问题,故此处为一个耗时点。
上述问题采用的方案是每次调用mg_font_get_mapdata时,先判断UNICODE码和文件ID是否变化,若无变化,将上次读取的信息返回即可,若不同,才将信息清空,重新获取,但改良后发现文字刷新速度仍然肉眼可见的延迟,可见仍存在其他问题。而经过上述步骤,目前仅剩读外部字库的代码逻辑与文件系统内部逻辑未排查,故继续排查这两部分。
获取map数据需要两步,先通过mg_font_get_map_infor读取存储map信息的4字节偏移地址数据,然后根据此偏移地址和map的字节数,通过mg_font_get_mapdata读取map数据,这两个步骤为必要步骤,故无法优化此过程。
分析低层文件系统逻辑,首先查看调用的文件系统读函数需要花费多长时间,下图三函数为读数据的入口函数,读数据有两部分,seek函数定位读起始地址,read函数读取数据,通过log打印时间,发现read函数耗时较长,由于底层挂载的读函数为SPI驱动函数,之前已排除SPI驱动本身问题,故将范围缩小到文件系统内部的读处理机制上。
通过下图四log发现,一次文件的读操作,需要调用将近10次SPI读函数,读取一个map有两个读步骤(先读偏移地址,再根据偏移地址读数据),共调用近20次SPI读,继续查看文件系统读的源码,发现文件系统内部会从一个文件的末尾开始按照块的方式向前遍历,检索数据,为验证此逻辑,我们显示韩文字库最后一个字,发现时间变短,只消耗了一个时间周期,证明猜测正确。
通过步骤九,证明数据的读取速度,与数据存于文件中的位置有关,由于索引信息位于文件最开头处,虽只有4字节,但耗费时间较长,而且大部分显示的文字也位于文件前端且大小为40字节,故总体时间变长。针对此问题,解决方案为将索引与数据分为两个文件存储,这样,索引的读取时间降低,可提高一定的速度,也可将文件中位于后端的生僻字去除,减小文件大小,减少遍历时间。
在系统整体优先级优化上,由于目前key与lvgl两线程优先级相同,LVGL的卡顿会影响KEY的响应,从而也给使用者造成卡顿现象,我们可以将按键优先级变高,或采用时间片轮询模式处理相同优先级任务,提高响应速度,从而使码表整体的响应速度提高。
三、结论和经验
实现LVGL的字库调用,逻辑图如下:
- get_glyph_dsc:获取字模的各种信息,包括字模高度宽度,偏移量,字节数等,此函数会在实现逻辑里多次调用;
- get_glyph_bitmap:获取字模map数据,且调用次数需要通过调用get_glyph_dsc来获取;
文件系统内部检索逻辑:文件系统内部会从一个文件的末尾开始按照块的方式向前遍历,故越靠前的文件内容,会花费更多时间,且通过查阅资料,littlefs文件系统,有一种擦写均衡模式,不会将一个块写满再写下一个块,写入的数据越多,占的块越多,而读操作不会跨块进行,故读的次数增加。
四、附录
关于LITTLE FS读写性能的介绍参考以下文章:
LittleFs文件系统:(https://www.jianshu.com/p/e229247c4f6b)
关于littlefs文件系统的效率问题:(https://blog.csdn.net/tjcwt2011/article/details/120021910?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~aggregatepage~first_rank_ecpm_v1~rank_v31_ecpm-5-120021910-null-null.pc_agg_new_rank&utm_term=littlefs%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F&spm=1000.2123.3001.4430)
总结
本章介绍了LVGL外部字库刷新速度优化的详细步骤。