STM32 LVGL界面内显示DCMI摄像头视频流
在只支持单图层的LTDC屏幕上同时显示LVGL GUI和摄像头视频流
系统环境
- 芯片:STM32F429IGT6
- CubeMX版本:6.9.2
- Keil版本:5.36
- LTDC接口16位颜色
- LVGL 8.3.10
一、理论
此篇暂不讨论如何配置LTDC屏幕,LVGL等内容,若如下前置功能还存在问题请先解决
1.确保前置功能调通
- 不带LVGL能否在显示屏上显示视频流
- 不考虑摄像头,LVGL能否成功显示在显示屏上
2.基础知识回顾
1.STM32 DCMI
该外设使用比较简单,在CubeMX中配置好像素,垂直同步,水平同步极性和跳帧功能,DMA通道等功能后编写程序软件初始化OV5640,配置OV5640为RGB565模式即可。
使用如下API开始摄像头视频流
记住 pData 这个数据地址,接着看lvgl canvas控件。
2.LVGL Canvas控件
画布需要一个缓冲区来存储绘制的图像。要为画布分配一个缓冲区,请使用
其中buffer
是一个静态缓冲区(不仅仅是一个局部变量),用于保存画布的图像。例如:
LV_CANVAS_BUF_SIZE_...
宏帮助确定不同颜色格式的缓冲区大小。
画布支持所有内置颜色格式,如LV_IMG_CF_TRUE_COLOR
或LV_IMG_CF_INDEXED_2BIT
。在颜色格式部分查看完整列表。
实现LVGL内显示摄像头画面的核心就是这个缓冲区
二、实操
为此我们需要解决两个问题
- 设置lvgl canvas对象缓冲区地址为dcmi dma通道地址
- 摄像头画面不断更新需要频繁刷新canvas对象从而显示视频流
1. 配置OV5640输出尺寸
2.开启DCMI DMA传输
首先定义缓冲区,这个变量需要定义为全局,因为你还需要让lvgl canvas对象使用,如果单片机内部没有这么大的内存可以将其指定到外部SDRAM内
3.创建lvgl canvas对象并设置其缓冲地址
4.刷新lvgl canvas对象
DCMI摄像头垂直同步中断服务例程即如下回调函数
此回调函数即用于通知DCMI一帧数据传输完成,此时告知LVGL canvas数据已经无效了,立即重绘
三、问题
1.摄像头帧率&显示屏帧率&LVGL显示帧率 问题
这三者帧率关系应该为 摄像头帧率≤LVGL显示帧率≤显示屏帧率
另外实际表现性能非常重要,并非显示屏可以跑60帧你就必须把LVGL和摄像头帧率都拉到60帧,你的MCU没有这么强的性能
我实测条件是LVGL全尺寸双缓冲30fps ,屏幕的像素时钟配置也为30fps,摄像头原始尺寸1280*800@15fps
最终是顶层GUI底层摄像头画面的情况下可以稳30fps,CPU占用80-90%,此时也仅仅是可用的状态,大幅晃动摄像头会导致图像撕裂问题
四、参考链接
文章作者:四文鱼Max
本文链接:https://blog.awolon.fun/archives/stm32-show-video-in-lvgl.html
许可协议:CC BY-SA 4.0
是否可以选择在VsyncEventCallback里调用lv_event_send ,然后在注册后的事件回调函数里处理?这种逻辑应该可以避免多线程操作GUI界面。
还有为什么选择VsyncEventCallback而非FrameEventCallback呢?
正点原子例程里jpeg模式使用的frame中断回调,我没研究过jpeg模式,估摸是开启jpeg模式后会开启frame中断;中断里调用lv_event_send应该也是没问题的,另外用lv_async_call异步调用会更稳妥,你可以参考下lvgl的官方文档https://docs.lvgl.io/master/details/main-components/timer.htm ,我不用的原因主要是任务调度和lvgl事件处理时间不稳定可能会影响屏幕刷新摄像头画面的及时性,长时间使用后只发现lvgl会报警告没有其他问题就照这个方案使用了
好的,感谢回复。
不客气,共同进步