STM32F429-LTDC模块的颜色混合

1.前言
STM32F429单片机内部集成了一个RGB屏的控制器,这个控制器和STM32F103系列中使用FSMC的SRAM时序控制的8080接口的LCD不一样,这种RGB时序的屏可以做比较大尺寸,比如4.3寸、5寸、7寸等,而8080接口的LCD一般都在4寸以下。两种屏幕的最大区别是在显存存放的位置,RGB接口屏幕的显存在单片机中,也就是需要单片机提供足够的内存空间作为显存使用,而8080接口屏幕的显存是在屏幕内部集成在控制器中的,单片机通过8080总线接口操作屏幕内部的显存,无需单片机提供显存,但是这也限制了显存的大小,不可能做到很大。我想使用的7寸以上的LCD屏幕分辨率都在800480以上,没有8080接口的控制芯片集成了这么大的显存空间(至少没有厂家生产这种屏幕),所以没法使用STM32103系列的FSMC接口来直接控制屏幕。所以我选择了STM32F429单片机,看中的就是它的LTDC控制器,可以直接连接RGB显示器,但是需要外挂一个SDRAM作为显存,因为内部的SRAM只有256KB,而800480分辨率的24位色显示器需要的显存为8004803≈1.1MB。

STM32F429与之前的系列强大之处就在于增加了LTDC个功能,从手册上看STM32F429的LTDC可以用于驱动1024x768分辨率的LCD屏幕。
LTDC其实就是TFT LCD控制器的意思,在arm9/arm11/cortex-A系列CPU当中,这个是必须有的外设,在小型单片机中,有这个功能的不多。LCD控制器的功能就是生成LCD像素时钟,将GRAM中的数据搬运到LCD屏幕上去显示。在一般的小型LCD模块一般都集成了一个LCD控制器,如常用的ili9320/ili9325等型号,这些LCD模块同时还集成了几百KB大小的RAM,用于显示;这种方案,不需要占用单片机的RAM就可以稳定地驱动LCD显示图像,一般地MCU先通过8080接口或SPI向控制器发送命令,配置LCD参数,然后向集成的RAM中写入数据就可以显示,是低成本项目的首选方案。而STM32F429自带的LTDC也是LCD控制器,与ili9320相比,支持的分辨率更高,功能更多,但是LTDC只负责产生LCD需要的时序,并没有集成RAM,如640x480x16bpp的屏幕,需要600KB的RAM,在单片机中600KB的内存,已经是天文数字了,所以需要外扩一片SDRAM来充当GRAM。 那么在使用LTDC的时候,首先要配置LCD的时序,然后要设置GRAM的地址(这里GRAM的地址就是外扩的SDRAM的地址),最后开启LTDC,可以在LCD_CLK引脚测量到有稳定的频率输出,应该就差不多了;配置好LTDC之后,硬件会自动将GRAM中的内容搬运到LCD屏幕上,只要改变GRAM中的数据就可以改变显示内容。另外要说的是这个LTDC支持2个图层和1个背景图层,一般情况下用一个图层显示就可以了;这2个图层可以单独设置显示区域和GRAM地址,并且同时开启时,硬件自动将2个图层的显示内容进行混合,混合顺序是:图层2 -> 图层1 -> 背景色,图层2位于最顶层,至于怎么利用这两个图层实现特殊的功能,就仁者见仁,智者见智了。

DMA2D则是一个生活在GRAM世界中的一个搬运工,往你指定的内存地址中制造一个矩形,或者把一个矩形数据从源RAM复制到目的RAM,并且完全由硬件实现。

2、像素透明度:
透明度这个概念是针对数字图片中的像素而言的,但是屏幕像素本身是没有透明度这一个概念的,图片像素有很多格式例如RGB565、RGB888、ARGB1555、ARGB8888,前两种是没有透明度的像素,后两种是有透明度的,以ARGB8888为例,其中ARGB分别表示Alpha、Red、Green、Blue,Alpha就是透明度的分量,值为0到255,0表示这个像素完全透明,255表示这个像素完全不透明。要解释完全不透明和完全透明这两个概念需要加一个背景色,背景色就是这个像素背后的颜色…假设这个背景色为Cb。那么完全不透明表示背景色完全不被显示出来,也就是只显示这个像素的颜色(前景色,表示为Cf)。完全透明表示只显示背景色,不显示前景色。介于完全不透明和完全透明中间表示显示一部分前景色和一部分背景色,也就是将前景色和背景色混合起来显示。例如前景色的像素的透明度为127,背景色的红色分量为100,前景色的红色分量为50,那么混合之后得到的混合色的红色分量为:Cm=Cb*(1- 127 / 255) + Cf*(127 / 255)=50+25=75,这就是混合后的红色分量值。

3、LTDC的颜色混合
STM32f429的LTDC控制器包含了两个Layer,如果两个层都开启,叠加在一起就需要使用透明度来混合两个层的颜色和背景色。在初始化LTDC的时候需要给定一个LCD背景色(这里假设背景色为蓝色),这个颜色是作为最最底层的颜色,

/* 默认背景颜色,该颜色在定义的层窗口外或在层禁止时使用。 */          
LTDC_Layer_InitStruct.LTDC_DefaultColorBlue = 0xFF;        
LTDC_Layer_InitStruct.LTDC_DefaultColorGreen = 0xFF;       
LTDC_Layer_InitStruct.LTDC_DefaultColorRed = 0xFF;         
LTDC_Layer_InitStruct.LTDC_DefaultColorAlpha = 0;

然后再初始化Layer,每一个Layer也都有一个背景色,这个背景色包含了透明度分量,而LTDC的背景色没有透明度,因为那是最底层的背景色了,不能有透明度了。同时每一个Layer有一个固定Alpha值LTDC_ConstantAlpha(0~255)。

每个Layer都有两个混合因子 BlendingFactor_1 和 BlendingFactor_2,我一直没搞懂ST为什么要这样设计,感觉又繁琐又鸡肋。这两个混合因子可以简写成BF1和BF2,BF1可以取值为LTDC_BlendingFactor1_CA和LTDC_BlendingFactor1_PAxCA,BF2可以取值为LTDC_BlendingFactor2_CA和LTDC_BlendingFactor2_PAxCA,这两个分别代表前景色和背景色的混合比例的组成。
LTDC_BlendingFactorx_CA表示混合系数使用Layer的固定Alpha值,也就是每个前景色像素的透明度是无效的,进行混合运算的时候只使用Layer的固定Alpha值来计算混合比例α1。混合比例α1的计算方式是 Alpha / 255 ,那么(1 - α1)就是(1 - Alpha / 255)。
LTDC_BlendingFactorx_PAxCA表示混合系数使用Layer的固定Alpha值(A1)和像素Alpha值(A2)的混合值来计算混合比例α2。混合比例α2的计算方式是 (A1 / 255)(A2 / 255),(1 - α2)就是(1 - (A1 / 255)(A2 / 255))。
在这里我BF1和BF2都使用LTDC_BlendingFactorx_PAxCA,然后将Layer的背景色的Alpha分量设置成0,旁路Layer的背景色,直接透明到最底层的背景色上去。同时将Layer的固定Alpha值LTDC_ConstantAlpha设置成255,那么上面的式子中α2的值就是 A2 / 255,(1 - α2)的值就是(1 - A2 / 255),这时候的混合运算就只是Layer的前景色和底层背景色根据像素的Alpha值的混合。

LTDC一共有两个Layer,Layer2在Layer1之上,三层颜色的示意图如下:
在这里插入图片描述
所以计算最上层Layer2的颜色的时候如果考虑透明度的话,其背景色是由Layer1和LCD背景色混合后的颜色作为其背景色。为了方便可以将Layer1的像素颜色的Alpha通道都设置成255,也就是完全不透明,这样Layer2层颜色的计算只要跟Layer1层的像素色混合就行了,不牵扯LCD背景色了。

这时候我们设计GUI系统的时候在Layer1上可以绘制背景图片或者背景色,然后在Layer2上绘制GUI内容(文本框、按键等)

猜你喜欢

转载自blog.csdn.net/qizhi321123/article/details/124592336