前段时间首次接触lvgl,准备用来在嵌入式Linux板卡上做一些界面功能,使用的是lvgl6.1.1,好像比较老了,为啥找的这个版本因为是网上找了一个在qt中开发lvgl的例子,就直接在上面改了。。。主要用了按钮、文本、标签、图表等控件,我的主要应用是有一些数据会频繁刷新,间隔大概1s,发现存在运行直接段错误或者界面卡死不刷新的问题。

1、界面“卡死”问题。运行过程中发现界面没反应,以为是板卡死机了,但是发现板卡网络均正常,通过调试发现在lv_task_handler函数没有返回导致没有刷新界面,出现的“死机”现象,lv_task_handler函数我放在while(1)循环中的,每隔100ms执行一次,通过调试打印最终定位是卡在后台的anim_task任务函数的LV_LL_READ(LV_GC_ROOT(_lv_anim_ll), a)中,如下图:

看了下源码,这个是任务是lvgl的动画效果的任务, LV_LL_READ是对所有的包含动画效果的控件句柄枚举初始化:

 发现卡在这个for循环没有出来,真的是奇怪,通过打印发现lv_ll_get_next获取的节点和当前节点的地址一样,就是同一个,导致就一直卡在这里。

2、段错误问题。运行过程中出现段错误,一般跑1小时内基本会出现,通过gdb调试找到段错误位置:

 发现还是发生在lv_task_handler函数中,在刷新label控件时,最终在lv_draw_label函数中,text参数是null导致段错误,text是label的内容,怎么会变成了null了呢?查看源码label控件的text是怎么来的,发现每次调用lv_label_set_text后会分配一段新的内存来存储内容,其他控件如按钮,textarea都包含了label控件,其刷新的时候都是调用了lv_label_set_text函数。然后仔细分析了自己的程序逻辑,我是一开始初始化lvgl后就创建了一个线程作为控件定时刷新数据,然后主线程就while(1)运行lv_task_handler函数,是不是存在一种可能:当执行lv_task_handler函数刷新label内容的时候,另一个线程正好调用了lv_label_set_text去刷新内容,该函数会重新分配一段内存作为保存内容,并free掉上一次的内存,导致lv_task_handler函数在刷新的时候获取的是上一次分配的地址,导致出现操作了空地址出现段错误。顿时感觉lvgl这么low吗,这种互斥操作没做好?还是版本太低的问题。然后我就尝试修改了自己的程序逻辑,把刷新控件函数放在while(1)中,和lv_task_handler顺序执行,这样就不会出现上述的问题了。

经过上述修改并测试发现程序可以正常跑了,问题1和问题2都没有了,正常运行24小时无异常。那可以得出结论:lv_task_handler和刷新文本类控件并行执行可能会出现这种内存共用导致的问题,不知道是使用问题还是自身存在的问题,其他版本的lvgl未测试是否存在同样的问题。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐