LTDC/DMA2D——液晶显示(代码)
如何使用 LTDC 及 DMA2D 外设控制型号为“STD800480”的 5 寸液晶屏,该液晶屏的分辨率为 800x480,支持 RGB888 格式
液晶排线接口:
使用5寸屏,通过屏幕上的排针接入到实验板的液晶排母接口,与STM32芯片的引脚相连。连接图如下:
//1.初始化LCD驱动的引脚
//2.使用LTDC初始化结构体,配置液晶屏的控制参数
//3.使用LTDC的层级初始化结构体,配置各层的控制参数
//4.直接操控显存,控制液晶屏显示图形
//5.使用DMA2D快速绘制直线及矩形
1、初始化LCD驱动的引脚,根据硬件结构分别初始化各个引脚。
以上代码根据硬件的连接,把与 LTDC与液晶屏通讯使用的引脚号、引脚源以及复用功能映射都以宏封装起来。其中部分 LTDC信号的复用功能映射比较特殊,如用作 R3 信号线的 PB0,它的复用功能映射值为 AF9,而大部分 LTDC的信号线都是 AF14。
初始化 LTDC 的 GPIO
利用上面的宏,编写 LTDC 的 GPIO 引脚初始化函数
与所有使用到 GPIO 的外设一样,都要先把使用到的 GPIO 引脚模式初始化,以上代码把 LTDC的信号线全都初始化为 LCD 复用功能,而背光 BL及液晶使能 DISP信号则被初始化成普通的推挽输出模式,并且在初始化完毕后直接控制它们开启背光及使能液晶屏。
配置 LTDC
接下来需要配置 LTDC的工作模式,这个函数的主体是根据液晶屏的硬件特性,设置LTDC 与液晶屏通讯的时序参数及信号有效极性
函数的执行流程如下:
1. 初始化 GPIO 引脚以及 LTDC、DMA2D 时钟
函数开头调用了前面定义的 LCD_GPIO_Config 函数对液晶屏用到的 GPIO 进行初始化,并且使用库函数 RCC_APB2PeriphClockCmd 及 RCC_AHB1PeriphClockCmd 使能LTDC和 DMA2D 外设的时钟。
2. 初始化 SDRAM
接下来调用前面章节讲解的 SDRAM_Init 函数初始化 FMC外设控制 SDRAM,以便使用 SDRAM 的存储空间作为显存。
3. 设置像素同步时钟
在“LTDC结构框图的时钟信号”小节讲解到,LTDC与液晶屏通讯的像素同步时钟CLK 是由 PLLSAI分频器控制输出的,它的时钟源为外部高速晶振 HSE 经过分频因子M 分频后的时钟,按照默认设置,一般分频因子 M 会把 HSE 分频得到 1MHz 的时钟,如 HSE 晶振频率为 25MHz 时,把 M 设置为 25,HSE 晶振频率为 8MHz时,把 M设置为 8,然后调用 SystemInit 函数初始化系统时钟。经过 M 分频得到的 1MHz 时钟输入到 PLLSAI分频器后,使用倍频因子“N”倍频,然后再经过“R”因子分频,得到PLLCDCLK 时钟,再由“DIV”因子分频得到 LTDC通讯的同步时钟 LCD_CLK。
利用库函数 RCC_PLLSAIConfig及 RCC_LTDCCLKDivConfig函数可以配置 PLLSAI分频器的这些参数,其中库函数 RCC_PLLSAIConfig 的三个输入参数分别是倍频因子N、分频因子 Q和分频因子 R,其中“Q”因子是作用于 SAI接口的分频时钟,与LTDC无关,RCC_LTDCCLKDivConfig函数的输入参数为分频因子“DIV”。在配置完这些分频参数后,需要调用库函数 RCC_PLLSAICmd使能 PLLSAI的时钟并且检测标志位等待时钟初始化完成。
在上面的代码中调用函数设置 N=420,R=6,DIV=8,计算得 LCD_CLK 的时钟频率为 8.75MHz,这个时钟频率是我们根据实测效果选定的,若使用的是 16位数据格式,可把时钟频率设置为 24MHz,若只使用单层液晶屏数据源,则可配置为 34MHz。然而根据液晶屏的数据手册查询可知它支持最大的同步时钟为 50MHz,典型速率为33.3Mhz。由此说明传输速率主要受限于 STM32 一方。LTDC外设需要从SDRAM 显存读取数据,这会消耗一定的时间,所以使用 32 位像素格式的数据要比使用 16 位像素格式的慢,如若只使用单层数据源,还可以进一步减少一半的数据量,所以更快。
4. 配置信号极性
接下来根据液晶屏的时序要求,配置 LTDC 与液晶屏通讯时的信号极性,
在程序中配置的 HSYNC、VSYNC、DE 有效信号极性均为低电平,同步时钟信号极性配置为上升沿。其中 DE 信号的极性跟液晶屏时序图的要求不一样,文档中 DE 的有效电平为高电平,而实际测试中把设置为 DE 低电平有效时屏幕才能正常工作,我们以实际测试为准。
5. 配置时间参数
液晶屏通讯中还有时间参数的要求,接下来的程序我们根据液晶屏手册给出的时间参数,配置 HSW、VSW、HBP、HFP、VBP、VFP、有效像素宽度及有效行数。这些参数都根据图 27-28 的说明以宏定义在程序中给出。
6. 写入参数到寄存器并使能外设
经过上面步骤,赋值完了初始化结构体,接下来调用库函数 LTDC_Init 把各种参数写入到 LTDC的控制寄存器中,然后调用库函数 LTDC_Cmd使能 LTDC。
配置 LTDC 的层级初始化
在上面配置完成 STM32 的 LTDC外设基本工作模式后,还需要针对液晶屏的各个数据源层进行初始化,才能正常工作。
LTDC的层级初始化函数执行流程如下:
(1) 配置窗口边界
每层窗口都需要配置有效显示窗口,使用 LTDC_HorizontalStart/ HorizontalStop/LTDC_VerticalStart/ LTDC_VerticalStop成员来确定这个窗口的左右上下边界,各个成员应写入的值与前面 LTDC 初始化结构体中某些参数类似,注意某些成员要求加 1 或减 1。
(2) 配置像素的格式
LTDC_PixelFormat 成员用于配置本层像素的格式,在这个实验中我们把这层设置为RGB888 格式,两层数据源的像素可以配置成不同的格式,层与层之间是独立的。
(3) 配置默认背景颜色
在定义的层窗口外或在层禁止时,该层会使用默认颜色作为数据源,默认颜色使用LTDC_DefaultColorBlue/Green/Red/Alpha 成员来配置,本实验中我们把默认颜色配置成透明了。
(4) 配置第 1 层的恒定 Alpha 与混合因子
前面提到两层数据源混合时可根据混合因子设置只使用恒定 Alpha 运算,还是把像素的 Alpha 也加入到运算中。对于第 1 层数据源,我们不希望 LTDC 的默认背景层参与到混合运算中,而希望第 1 层直接作为背景(因为第 1 层的数据每个像素点都是可控的,而背景层所有像素点都是同一个颜色)。因此我们把恒定 Alpha 值(LTDC_ConstantAlpha)设置为 255,即完全不透明,混合因子 BF1/BF2 参数(LTDC_BlendingFactor_1/2)都配置成 LTDC_BlendingFactor1/2_CA,即只使用恒定Alpha 值运算,这样配置的结果是第 1 层的数据颜色直接等于它像素本身的 RGB值,不受像素中的 Alpha 值及背景影响。
(5) 配置层的数据量
通过参数 LTDC_CFBLineLength及 LTDC_CFBLineNumber 可设定层的数据量,层的数据量跟显示窗口大小及像素格式有关,由于我们把这层的像素格式设置成了RGB888,所以每个像素点的大小为 3 字节,LTDC_CFBLineLength参数写入值:行有效像素个数 x3+3 。而 LTDC_CFBLineNumber 参数直接写入有效行数(LCD_PIXEL_HEIGHT)。还有一个参数 LTDC_CFBPitch它用于配置上一行起始像素与下一行起始像素的数据增量,我们直接写入:行有效像素个数 x3 即可。
(6) 配置显存首地址
每一层都有独立的显存空间,向 LTDC_CFBStartAdress 参数赋值可设置该层的显存首地址,我们把第 1 层的显存首地址直接设置成宏 LCD_FRAME_BUFFER,该宏表示的地址为 0xD0000000,即 SDRAM 的首地址,从该地址开始,BUFFER_OFFSET个字节的空间都用作这一层的显存空间(BUFFER_OFFSET宏的值为 800x480x3:行有效像素宽度 x行数 x每个字节的数据量),向这些空间写入的数据会被解释成像素数据,LTDC会把这些数据传输到液晶屏上,所以我们要控制液晶屏的输出,只要修改这些空间的数据即可,包括变量操作、指针操作、DMA操作以及 DMA2D 操作等一切可修改 SDRAM 内容的操作都支持。
实际设置中不需要刻意设置成 SDRAM 首地址,只要能保证该地址后面的数据空间足够存储该层的一帧数据即可。
(7) 向寄存器写入配置参数
赋值完后,调用库函数 LTDC_LayerInit 可把这些参数写入到 LTDC 的层控制寄存器,根据函数的第一个参数 LTDC_Layer1/2 来决定配置的是第 1 层还是第 2层。
(8) 配置第 2 层控制参数
要想有混合效果,还需要使用第 2 层数据源,它与第 1 层的配置大致是一样的,主要区别是显存首地址和混合因子。在程序中我们把第 2 层的显存首地址设置成紧挨着第 1 层显存空间的结尾。而混合因子都配置成 PAxCA以便它的透明像素能参与运算,实现透明效果,但实际上我们并没有修改第 2 层像素数据的格式,它依然使用RGB888 格式,由于像素本身并没有 Alpha 通道的数据,所以是没有透明混合效果的。
正常使用时可把第 2层配置成 ARGB8888 或 ARGB1555 格式,才能正常使用两层数据混合的功能。本程序没有配置透明格式主要是因为各种描绘函数(如画点、画线等)是要根据像素格式进行修改的。两层使用不同的像素格式那么就要有两套同样功能的
函数,容易造成混乱,而 ARGB8888 的数据量太大,所以我们把两层的像素格式都设置成了 RGB888。
(9) 重载 LTDC配置并使能数据层
把两层的参数都写入到寄存器后,使用库函数 LTDC_ReloadConfig让 LTDC外设立即重新加载这些配置,并使用库函数 LTDC_LayerCmd 使能两层的数据源。至此,LTDC配置就完成,可以向显存空间写入数据进行显示了。
辅助显示的全局变量及函数
欢迎加入作者的小圈子
扫描下方左边二维码加入QQ交流群,扫描下方右边二维码关注个人微信公众号并,获取更多隐藏干货,QQ交流群:859800032 微信公众号:Crystal软件学堂
作者:Liu_Jing bilibili视频教程地址:https://space.bilibili.com/5782182 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在转载文章页面给出原文连接。 如果你觉得文章对你有所帮助,烦请点个推荐,你的支持是我更文的动力。 文中若有错误,请您务必指出,感谢给予我建议并让我提高的你。 |