如何一步一步地优化LVGL的丝滑度

经过一番周折将LVGL移植到了STM32F407单片机上,底层驱动的LCD是st7789,移植时的条件和环境如下:

●LVGL用的是单缓冲,一次刷新10行;

●刷新函数用的是最原始的一个一个打点的方式;

●ST7789底层发送数据用的是软件spi;

在这些环境下,刷屏就是在拉窗帘,特别慢。

接下来,一步一步地进行优化。

软件SPI→硬件SPI

将硬件SPI改成软件SPI,其实效果并没有什么提升,甚至可以说毫无改进。

注意,这里SPI虽然只用发送,但是接收的代码也不能省略,要不然没效果,千万注意。

虽然硬件SPI相比软件SPI没什么改善,但是硬件SPI可以结合DMA使用。

硬件SPI+DMA

结合LCD屏幕的指针自增进行区域批量赋值,不再一个一个地打点了,而是一次性填充整个区域。

Lvgl的打点调用如下

刷屏函数如下

使用DMA之后,效果提升比较明显,页面切换几乎是瞬间完成,但是还是有闪烁的感觉。

这里有一些问题需要注意下。

不知道为什么,DMA操作8位时能用,操作16位时就不好用了,虽然也把spi和DMA都改成了操作16位,还是不行,所以暂时使用8位;

理论上来说SPI的位数和DMA的位数应该是独立的,一个是发送的字节单位,一个是搬运的字节单位;暂时没搞明白,就统一使用8位吧。

另外,spi的时钟不能太低

估计是太慢的话,spi发送的速度跟不上DMA搬运数据的速度,spi的数据会被冲掉;

再就是SPI的发送和DMA的发送是可以共存的。

ST7789的驱动里涉及到发送指令和发送数据,如果是一次性的数据发送,可以使用DMA,也可以使用SPI

使用spi发送

使用dma发送

考虑到使用DMA来刷新屏幕数据可以结合lvgl的缓冲,所以上面选用spi的发送方式,然后DMA专门用来刷数据;

前面我是独立于lvgl,在LCD的驱动里给DMA专门又开了个内存空间

但其实,可以直接使用lvgl开辟的显存空间,重复申请就浪费了加倍的空间了,也省去了数据复制的步骤了。

但这样又有个问题,那就是颜色像素是个16位的数组,我DMA操作的是8位的数据,前面说了,DMA操作16位的不知道为啥不好使,所以这里面肯定要有些转化,或者解决DMA不能搬运16位数据的原因。怎么办呢?

继续往下看。

SPI+DMA+LVGL双缓冲

参考:LVGL非全尺寸双显存—SPI+DMA(中断刷新) - 哔哩哔哩

配置lvgl为双缓冲

注意下面的别忘了同步修改。

然后将上面三个静态变量的声明放到外面去,因为这里是在函数内部,属于局部静态变量,后面需要全局使用,就会识别不到,因此要上升成全局变量。

在使用LVGL的双缓冲时,DMA初始化时的发送地址可以先设置为双缓存的第一个空间,此时,将LCD的初始化函数直接放在lv_port_disp_template.c中,并且传递进入第一个缓冲区的地址。

之前单独为DMA开辟的发送空间可以去掉。

接下来开始改造刷新函数

Lvgl双缓冲的切换是lvgl自动进行的,我们不用去处理指针切换和数据交替填充的操作,只需要在刷新函数里获取对应的颜色数据的地址,就是当前要发送的数据地址,是lvgl已经帮我们切换好了双缓冲的指针。

在disp_flush函数里我们直接填充数据,接口不变。

同时有一个考虑:DMA发送数据时,之前是强行死循环等待DMA发送完成

我们现在将其改成DMA传输完成中断的方式来进行,然后在DMA传输完成中断里通知lvgl进行下一次刷新,也就是将lv_disp_flush_ready(disp_drv);函数放到DMA中断里去,这样就又有了问题,那就是这个通知函数里的disp_drv是个局部变量,想要挪到外部,就得借助一个中间的全局变量,因此,再定义一个全局的变量,类型和disp_drv的类型一致

同时,考虑到DMA一次只能发送一个字节的数据,因此我们将color_p强行转换成8位数据类型的指针。

于是,刷新函数disp_flush如下:

接下来,就要继续改造打点函数了

我们先计算下,DMA一次最多能发送65535个数据,我配置的是8位的,也就是一次最多能发送65535个字节,一个像素2个字节,那么就是说一次最多能发送32767个像素,如果屏幕是320*240的,那么一次最多能发送102行,所以,设置双缓冲时,我们的缓冲大小不要超过102行,我们这里先将缓冲设置成20行,也就是每次刷新,可以直接使用DMA发完,不必让DMA也分次发送。

DMA使能函数调整

另外,别忘了配置DMA的传输完成中断

然后按照上面说过的思路在lv_port_disp_template.c文件中写上DMA的传输完成中断,并在里面放置通知函数。

在这一过程中,其实有个隐含的答案,那就是上面提过的,关于像素是16位的,但是DMA只能处理8位数据的问题。

其实,DMA所识别的起始地址,就是个32位的地址,不管目标数据本身是什么类型,只要把首地址传给DMA即可,DMA从首地址开始,按照DMA配置的位数来搬运数据,DMA并不关心这个地址原来本身是什么类型的数据。

所以,LVGL传过来的是地址,我们只要把地址转成uint32_t然后传递给DMA,DMA就会按照初始化时配置的位数来搬运,它才不管你原来的数据是多少位的。

至此,DMA+LVGL双缓冲已完成,编译下载运行看看效果。

运行后,发现颜色不大对,原来是红绿蓝,现在变成了青紫黄,这种情况,就想到了一个颜色配置项LV_COLOR_16_SWAP,把它改成1。

再编译下载运行

颜色正常,速度也还挺好。

当然,如果想要再快,可以使用全屏幕双缓冲,此时,SRAM空间不够的话就可以将其放在外部SRAM中,用空间来换时间。我这个项目到这里帧率为35,已经够用了,就不再优化了。后续有特别的需要再说吧。

更多优化参考

LVGL显示优化—基本优化 - 哔哩哔哩

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值