欢迎光临散文网 会员登陆 & 注册

MCU如何高效地驱动LCD——RGB篇

2023-10-30 21:27 作者:奥大梨呀  | 我要投稿

    承接上一篇文章,这次来说说MCU该如何高效地驱动RGB接口的LCD,同时避免画面撕裂。本片文章将会以带LTDC外设的STM32型号来说明几种驱动方法,并结合lvgl这个UI库进行实战。中间还会穿插一点关于ESP32S3的内容,因为ESP32S3也有LCD控制器,但没有STM32的LTDC这么强大。

    这里插入一张RGB LCD的时间参数图,下文会提到其中的一些参数。

RGB LCD 时间参数描述

    首先要说的就是关于RGB屏如何避免撕裂。在上篇文章《LCD撕裂的产生原因和双缓冲的概念》中有说到,避免LCD撕裂最重要的就是进行读写指针同步,而像RGB LCD这类GRAM在MCU侧的LCD,最好的方法就是双缓冲,创建2个帧缓冲区(framebuffer),在垂直消隐区(非可视区)直接修改LCD控制器的帧缓冲区地址,即可避免画面撕裂。那么如何能够直到当前LCD控制器刷新到垂直消隐区了呢,就需要使用中断了。

    在说明具体的思路之前,先说一种非常常见的错误方式,这在上篇文章也有简略提到。就是直接使用DMA2D将渲染好的数据填入当前的帧缓冲区,就像下面的代码这样。

    这个代码着非常致命的一点,没有做读写指针同步,假设当前LCD控制器已经刷新了半屏,突然DMA2D将整个framebuffer全部更新了,这时LCD控制器刷新下半屏的时候就会产生一个错位线,即撕裂现象。

    为了避免这种现象的产生,我们可以利用LTDC的行中断进行读写指针同步,将LTDC的行中断配置为在消隐区的行,最简单的是配置为第0行,因为这行一般都位于帧同步区(VSYNC)。然后在行中断中设置标志位或者开启DMA2D的中断传输,如果使用了RTOS,还可以使用信号量(Semphore)配合,就像下面这样。

    这是避免撕裂最常用且最简单有效的方法。像乐鑫官方的esp32s3的RGB例程就是这么做的,在lvgl需要进行拷贝时,先利用信号量等待帧(vsync)事件,当vsync事件产生并中断时,此时LCD控制器正好刷到垂直消隐区后沿(VBP)之前,这时再发送信号量令lvgl开始进行数据拷贝,从而达到消除撕裂的效果。乐鑫官方的RGB例程lvgl flush代码如下。

    上面说的是RGB LCD最通用的消除画面撕裂的方法。对于STM32强大的LTDC而言,还有另一种更为 方便高效的方法——双缓冲(2个全尺寸framebuffer)。通过查看ltdc的HAL库函数我们会发现,有许多函数分为两种,一种为带_NoReload后缀的函数,另一种则不带后缀。先说一下这两类函数的区别:

带_NoReload后缀的函数是没有配置重装载寄存器的,调用该函数后配置只写到影子寄存器中,不更新现有寄存器配置。

不带后缀的函数配置了重装载寄存器,调用该函数后配置写入刀影子寄存器中后,立刻更新了现有寄存器的配置。

    跳转到函数查看代码,可以发现,没有带后缀的函数多了一句代码, 这句代码配置了SRCR寄存器。

STM32 LTDC SRCR寄存器描述

    通过查阅手册可以看到,对SRCR这个寄存器的bit 0写1表示立即更新寄存器,对bit 1写1则表示在垂直消隐区前沿(VFP)的第一行进行更新。后者正是我们所需要的,而且HAL库已经提供了一个函数用于配置重装载和装载中断HAL_Reload(),直接使用即可。那么显而易见,使用LTDC令lvgl更新framebuffer的步骤因该是下面这样:

1.调用HAL_LTDC_SetAddress_NoReload()设置新的framebuffer地址。

2.调用HAL_Reload()配置在垂直消隐区进行寄存器更新并开启中断。

3.在重装载中断回调HAL_LTDC_RealoadEventCallback()中设置标志位或则发送信号量。

4.在lvgl的disp_wait_flush()函数中获取标志为或者信号量并调用lv_disp_flush_ready()。

以下是代码示例:

    这种方法还可以与lvgl的双缓冲结合,需要令lvgl开启全屏刷新,然后当lvgl绘制好一帧数据后,交换LTDC的帧缓冲区,令LTDC刷新刚渲染好的这个缓冲区,另一块缓冲区则交给lvgl渲染下一帧图像。上篇文章也说过,LCD控制器层面的双缓冲可以解决画面撕裂,UI层面的双缓冲可以提高渲染帧率,像这样就可以达到了两者都具有双缓冲的效果了,既避免了画面撕裂,又提高了渲染帧率。具体的代码我将会提交到gitee供大家参考,链接在文章末尾,板子是我以往视频中开源的一块带3.5寸LCD的UI开发板。

    RGB LCD除了比较吃RAM的空间和带宽以外,算是要达到高效无撕裂最容易驱动的LCD了。后面我将会继续讲解8080接口的MCU屏和SPI屏该如何避免撕裂且高效地驱动。不过目前手头上暂时没有可用的板子,可能会鸽一段时间搞个板子吧。如果觉得对你有帮助的话还望点点大拇指,给Up一份支持。

gitee链接:https://gitee.com/Jumping99/ltdc-lvgl-demo.git


MCU如何高效地驱动LCD——RGB篇的评论 (共 条)

分享到微博请遵守国家法律