【STM32H7教程】第50章 STM32H7的LCD控制器LTDC基础知识和HAL库API
完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980
第50章 STM32H7的LCD控制器LTDC基础知识和HAL库API
本章节为大家讲解LCD控制器LTDC(LCD-TFT display controller),实际项目中用到显示屏的地方全靠它了,而且性能也比较给力。
50.1 初学者重要提示
50.2 LTDC基础知识
50.3 LTDC的HAL库用法
50.4 源文件stm32h7xx_hal_ltdc.c
50.5 总结
50.1 初学者重要提示
- 本章50.2小节中的几个知识点比较重要,比如DE同步模式和HV同步模式的区别,Alpha混合,水平消隐和垂直消隐等知识点尤其重要,需要大家理解透彻。
- 测评STM32H7的LTDC+DMA2D性能,100Hz以上无压力,刷800*480图片和色块仅需2.6ms一张:http://www.armbbs.cn/forum.php?mod=viewthread&tid=91489 。
50.2 LTDC基础知识
LTDC的几个关键知识点放在开头说:
- STM32H7的LTDC最大支持1024*768分辨率,且支持硬件双图层。实际支持的分辨率可能比1024*768要高一点,因为最终可以支持的最大分辨率是芯片后期定标的。
- 支持32位色,24位色,16位色和8位色。
- 可编程窗口位置和大小,可编程行同步,场同步和数据使能信号的极性。
- 查色表 (CLUT,Color look-up table),每个图层最高可记录256种24位色。
- 支持如下8种颜色格式:
- ARGB8888
32位颜色格式,一个像素点占用4字节,其中低位 3 字节用于颜色分量,高位字节用于 Alpha 混合。红、绿、蓝和 Alpha通道(0x00表示完全透明,0xFF表示完全不透明)都是 8 位表示。颜色格式:AAAAAAAARRRRRRRRGGGGGGGGBBBBBBBB。
- RGB888
24位颜色格式,一个像素点占用3字节,分别用于红、绿、蓝。
颜色格式:RRRRRRRRGGGGGGGGBBBBBBBB。
- RGB565
16位颜色格式,一个像素点占用2字节,分别用于红、绿、蓝。
颜色格式:RRRRRGGGGGGBBBBB。
- ARGB1555
16位颜色格式,一个像素点占用2字节,Alpha通道使用1个位表示,等于0的时候表示完全透明,等于1的时候表示完全不透明。红、绿、蓝都是用5个位表示。
颜色格式:ARRRRRGGGGGBBBBB。
- ARGB4444
16位颜色格式,一个像素点占用2字节,Alpha通道使用2个位表示(0x0表示完全透明,0x3表示完全不透明)。红、绿、蓝都是用4个位表示。
颜色格式:ARRRRRGGGGGBBBBB。
- L8 (8-bit luminance or CLUT)
8位颜色格式,实际上仅仅是8位索引值,范围0–255,而每个索引值的具体颜色值在查色表CLUT里面存储。
- AL44 (4-bit alpha + 4-bit luminance)
8位颜色格式,实际上是4位Alpha通道(0x0表示完全透明,0xF表示完全不透明)和4位的索引值,索引范围0–15,而每个索引值的具体颜色值在查色表CLUT里面存储。
- AL88 (8-bit alpha + 8-bit luminance)
16位颜色格式,实际上是8位Alpha通道(0x00表示完全透明,0xFF表示完全不透明)和8位的索引值,索引范围0–255,而每个索引值的具体颜色值在查色表CLUT里面存储。
50.2.1 LTDC硬件框图
认识一个外设,最好的方式就是看它的框图,方便我们快速地了解LTDC的基本功能,然后再看手册了解细节。框图如下所示:
通过这个框图,我们可以得到如下信息:
- ltdc_aclk
为LTDC寄存器提供时钟,时钟来自AXI时钟域。
- ltdc_pclk
LTDC寄存器接口时钟。
- ltdc_ker_ck
用于生成LCD_CLK(像素时钟输出)的LTDC内核时钟。
- ltdc_li_it
LTDC行中断,用于触发MDMA。
- ltdc_it
LTDC全局中断请求。
- ltdc_err_it
LTDC全局错误中断请求。
下面是LCD接口引脚,用于外接显示屏:
- LCD_CLK
像素时钟输出。
- LCD_HSYNC
水平同步信号。
- LCD_VSYN
垂直同步信号。
- LCD_DE
数据使能信号。
- LCD_R[7:0]
8位红色数据。
- LCD_G[7:0]
8 位绿色数据。
- LCD_B[7:0]
8位蓝色数据。
50.2.2 LTDC时钟源选择
LTDC仅有一个时钟源可供选择,即PLL3R。
50.2.3 LCD的DE同步模式和HV同步模式的区别
一般情况下,STM32H7都是用SDRAM作为LCD的显存,LTDC控制器会从SDRAM读取数据刷新到LCD显示屏上,具体如何刷新呢?这就涉及到DE同步模式和HV同步模式。
具体支持哪种模式是由裸屏自带的Driver IC决定,比如V7板子7寸裸屏的Source Driver IC OTA7001支持DE和HV两种模式。现在的大分辨率显示屏一般都是DE同步模式,小分辨率的HV同步模式多。
- DE同步模式
DE模式需要LCD_DE和LCD_CLK信号来控制刷新。比如一个800x480分辨率的裸屏,在DE有效信号的时候(高电平或低电平),就有800个LCD_CLK输出时钟来确认行中800个点。每个时钟有效的时候,从显存读取一次RGB数据。因为存在回扫信号,所以DE是个方波。一个周期的LCD_DE信号,裸屏就扫描一行。扫描480行后,又从第一行扫描开始。这个规律由裸屏的驱动IC所决定的。
- HV同步模式
HV模式需要LCD_CLK时钟信号,行同步信号LCD_HSYNC和场同步信号LCD_VSYNC来控制刷新。比如一个480x272分辨率的裸屏,有一个行同步信号LCD_HSYNC产生时(高电平或者低电平脉冲),就有480个LCD_CLK输出时钟来确认行中480个点。每个时钟有效的时候,从显存读取一次RGB数据。再来一个行同步信号LCD_HSYNC产生时(高电平或者低电平脉冲),切换到下一行,继续行同步和时钟输出,扫描272行后,发送一个场同步信号LCD_VSYNC,又重新从第一行扫描开始。
具体的时序效果可以看第51章的内容。
50.2.4 LTDC的时序配置
LTDC的时序控制就是下面几个参数的设置,这几个参数都可以通过寄存器进行配置。
- HSYNC width
水平同步宽度设置,以LCD_CLK的像素时钟输出为单位。
- HBP(horizontal back porch period)
水平后沿周期设置,以LCD_CLK的像素时钟输出为单位。
- Active width
有效宽度设置,以LCD_CLK的像素时钟输出为单位。以800*480分辨率为例,Active width = 800。
- HFP(horizontal front porch period)
水平前沿周期设置,以LCD_CLK的像素时钟输出为单位。
- VSYNC width
垂直同步宽度设置,以LCD_CLK的像素时钟输出为单位。
- VBP(vertical back porch period)
垂直后沿周期设置,以LCD_CLK的像素时钟输出为单位。
- Active height
有效高度设置,以LCD_CLK的像素时钟输出为单位。以800*480分辨率为例,Active height = 480。
- VFP(vertical front porch period)
垂直前沿周期设置,以LCD_CLK的像素时钟输出为单位。
50.2.5 LTDC背景层,图层1,图层2和Alpha混合
LTDC除了图层1和图层2两个硬件图层以外,还有一个背景层。由于背景层的刷新不需要显存空间,所以可以用这个图层验证LTDC时序配置是否有问题。
- 对于背景层来说,仅支持单色设置,固定颜色格式RGB888(LTDC_HandleTypeDef hltdc_F)hltdc_F.Init.Backcolor.Blue = 0
hltdc_F.Init.Backcolor.Green = 0
hltdc_F.Init.Backcolor.Red = 0
- 对于图层1和图层2来说,支持如下8种颜色格式:
– ARGB8888
– RGB888
– RGB565
– ARGB1555
– ARGB4444
– L8(8 位 Luminance 或 CLUT)
– AL44(4 位 alpha + 4 位 luminance)
– AL88(8 位 alpha + 8 位 luminance)
- 实现Alpha混合的关键是要有一个变量可以设置各种透明度。对此,STM32H7准备了两个Alpha供使用:
- 一个是常数Alpha(0x00表示完全透明,0xFF表示完全不透明),所有颜色格式都可以使用。
- 另一个是像素Alpha,也就是ARGB8888,ARGB1555,ARGB4444等颜色格式的Alpha通道数值,也就是我们为图层每个位置绘制的实际颜色值。
==================================
了解了这点后就是具体的实现了。STM32H7的参考手册给出了具体的混合公式
BC = BF1 x C + BF2 x Cs
混合后的颜色= 混合系数1 x 当前层颜色 + 混合系数2 x 底层混合后的颜色
- 混合系数1可以选择:
(1)常数 Alpha
(2)像素 Alpha x 常数 Alpha
- 混合系数2可以选择:
(1)1 - 常数 Alpha
(2)1 - 像素 Alpha x 常数 Alpha
- 底层混合后的颜色:
(1)可以是背景层。
(2)可以是背景层与图层1混合后的颜色。
- 那么公式就变成如下形式(主要是如下两种):
混合后的颜色 = 常数 Alpha x 当前层颜色 + (1 - 常数 Alpha) x 底层混合后的颜色。
混合后的颜色 = 像素 Alpha x 常数 Alpha x 当前层颜色 +(1 - 像素 Alpha x 常数 Alpha) x 底层混合后的颜色。
- 再进一步简化,代入HAL库参数(LTDC_LayerCfgTypeDef pLayerCfg):
像素Alpha是ARGB8888,ARGB1555等颜色格式的Alpha数值,也就是我们为图层每个位置绘制的实际颜色值,我们这里用AlphaValue表示。
混合后的颜色 = (pLayerCfg.Alpha /255 ) x 当前层颜色 +(1 - pLayerCfg.Alpha /255 ) x 底层混合后的颜色。
混合后的颜色 = (AlphaValue/255)x (pLayerCfg.Alpha /255 ) x 当前层颜色 +(1 - (AlphaValue/255)x (pLayerCfg.Alpha /255 )) x 底层混合后的颜色。
注,Alpha值要做归一化,Alpha的范围是0 - 255,比如Alpha = 100,那么代入公式的时候就是100/255。
- 举例:
(1)混合因数1选择像素 Alpha x 常数 Alpha。
(2)混合因数2选择像素 Alpha x 常数 Alpha。
(3)使用图层1和背景层,图层1使用ARGB8888颜色格式。
(4)背景色 = 0xFF0000,图层1位置坐标(0,0)颜色值0x5500FF00。
(5)Alpha常数 = 0x77
混合后的颜色 = (AlphaValue/255)x (pLayerCfg.Alpha /255 ) x 当前层颜色 +(1 - (AlphaValue/255)x (pLayerCfg.Alpha /255 )) x 底层混合后的颜色。
= (0x55/255)x (0x77/255) x 0x00FF00 +(1 - (0x55/255)x (0x77/255)) x 0xFF0000
= 0xD7809C
- 最后注意一点:
如果大家设置的图层显示区没有显示满整个显示屏,且使用的ARGB颜色格式,那么未覆盖的区域会使用图层默认颜色。对此HAL库有专门的配置:
LTDC_LayerCfgTypeDef pLayerCfg
pLayerCfg.Alpha0 = 0;
pLayerCfg.Backcolor.Blue = 0;
pLayerCfg.Backcolor.Green = 0;
pLayerCfg.Backcolor.Red = 0;
50.2.6 LTDC的水平消隐和垂直消隐
正常情况下,LCD的刷新就是从左到右,从上到下进行逐个像素点刷新。但仅刷新有效的显示区是不够的,比如800*480分辨率,我们不仅仅要刷800*480这段有效区域,边界区也是要刷新的,即下图总宽度以内,有效宽度以外的区域。
水平消隐就是LCD扫描一行结束到另一行开始的时间,这段消失的时间就是水平消隐,即HSYNC宽度+ HBP + HFP这段消失的时间。
垂直消隐就是LCD扫描最后一行结束到第一行开始的时间,这段消失的时间就是垂直消隐,即VSYNC宽度+ VBP + VFP这段消失的时间。
50.2.7 区分FPS帧率和刷新率
FPS帧率是对STM32H7刷到显存,也就是SDRAM里面来说的,而是刷新率是实际LCD显示的速度。
刷新率 = LTDC输出时钟 /((Width + HSYNC_W + HBP + HFP )*(Height + VSYNC_W + VBP +VFP ))
一般情况下,帧率是远高于刷新率的,但帧数高于刷新率有没有意义?网上普遍的看法是高于刷新率的帧数都是浪费,比如H7刷800*480分辨率显示屏,帧数可以达到300多,而刷新率估计才108Hz,多出来的不是都浪费了吗(对于那种FPS类的游戏,我们不讨论)。
对于这种观点,在一定情况下是成立的。但是有一点,即使是帧数和刷新率都是108Hz,能保证显示没有撕裂感吗?能保证没有帧延迟吗?能保证流畅的画面吗?这个时候,我们使用emWin支持的三缓冲,多余的帧数完全可以输出到其它缓冲区,有效降低撕裂感和帧延迟,保证流畅输出。
50.2.8 避免 LTDC刷新撕裂感的解决办法
如果用户快速刷新颜色差异比较大的两种界面,容易遇到这种撕裂问题。
- 出现这个问题的原因
用户更新显存数据期间,LTDC也在不断的读取显存的数据到显示屏上,如果用户才更新了部分界面数据,后面部分还没有更新,LTDC刷新到显示屏的界面效果出现撕裂感,即下面这种现象:
- 解决这个问题的办法
LTDC刷新还在垂直消隐期间就将整个界面刷新完成,而我们如何只知道LTDC在垂直消隐期,通过函数HAL_LTDC_ProgramLineEvent设置刷新到指定行时进入中断即可,一般设置为第0行进入中断,然后设置个标志即可。
一旦检测到这个标志,就通过DMA2D快速将界面刷新好,这样就有效的避免了撕裂感。
50.3 LTDC的HAL库用法
LTDC的HAL库用法其实就是几个结构体变量成员的配置和使用,然后配置GPIO、时钟,并根据需要配置NVIC、中断和DMA。下面我们逐一展开为大家做个说明。
50.3.1 LTDC寄存器结构体LTDC_TypeDef
LTDC相关的寄存器是通过HAL库中的结构体LTDC_TypeDef定义的,在stm32h743xx.h中可以找到它们的具体定义:
typedef struct { uint32_t RESERVED0[2];/*!< Reserved, 0x00-0x04 */ __IO uint32_t SSCR; /*!< LTDC Synchronization Size Configuration Register, Address offset: 0x08 */ __IO uint32_t BPCR; /*!< LTDC Back Porch Configuration Register, Address offset: 0x0C */ __IO uint32_t AWCR; /*!< LTDC Active Width Configuration Register, Address offset: 0x10 */ __IO uint32_t TWCR; /*!< LTDC Total Width Configuration Register, Address offset: 0x14 */ __IO uint32_t GCR; /*!< LTDC Global Control Register, Address offset: 0x18 */ uint32_t RESERVED1[2]; /*!< Reserved, 0x1C-0x20 */ __IO uint32_t SRCR; /*!< LTDC Shadow Reload Configuration Register, Address offset: 0x24 */ uint32_t RESERVED2[1]; /*!< Reserved, 0x28 */ __IO uint32_t BCCR; /*!< LTDC Background Color Configuration Register, Address offset: 0x2C */ uint32_t RESERVED3[1]; /*!< Reserved, 0x30 */ __IO uint32_t IER; /*!< LTDC Interrupt Enable Register, Address offset: 0x34 */ __IO uint32_t ISR; /*!< LTDC Interrupt Status Register, Address offset: 0x38 */ __IO uint32_t ICR; /*!< LTDC Interrupt Clear Register, Address offset: 0x3C */ __IO uint32_t LIPCR; /*!< LTDC Line Interrupt Position Configuration Register, Address offset: 0x40 */ __IO uint32_t CPSR; /*!< LTDC Current Position Status Register, Address offset: 0x44 */ __IO uint32_t CDSR; /*!< LTDC Current Display Status Register, Address offset: 0x48 */ } LTDC_TypeDef;
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:
#define __O volatile /*!< Defines 'write only' permissions */ #define __IO volatile /*!< Defines 'read / write' permissions */
下面我们再看LTDC的定义,在stm32h743xx.h文件。
#define PERIPH_BASE ((uint32_t)0x40000000) #define D1_APB1PERIPH_BASE (PERIPH_BASE + 0x10000000) #define LTDC_BASE (D1_APB1PERIPH_BASE + 0x1000) #define LTDC ((LTDC_TypeDef *)LTDC_BASE) <----- 展开这个宏,(LTDC_TypeDef *) 0x50001000
我们访问LTDC的ISR寄存器可以采用这种形式:LTDC->ISR = 0。
50.3.2 LTDC参数初始化结构体LTDC_InitTypeDef
此结构体用于配置LTDC的基本参数,具体定义如下:
typedef struct { uint32_t HSPolarity; uint32_t VSPolarity; uint32_t DEPolarity; uint32_t PCPolarity; uint32_t HorizontalSync; uint32_t VerticalSync; uint32_t AccumulatedHBP; uint32_t AccumulatedVBP; uint32_t AccumulatedActiveW; uint32_t AccumulatedActiveH; uint32_t TotalWidth; uint32_t TotalHeigh; LTDC_ColorTypeDef Backcolor; } LTDC_InitTypeDef;
下面将这几个参数逐一为大家做个说明:
- uint32_t HSPolarity
此参数用于设置水平同步信号极性,具体支持的参数如下:
#define LTDC_HSPOLARITY_AL (0x00000000U) /* 水平同步极性低电平有效 */ #define LTDC_HSPOLARITY_AH LTDC_GCR_HSPOL /* 水平同步极性高电平有效 */
- uint32_t VSPolarity
此参数用于设置垂直同步信号极性,具体支持的参数如下:
#define LTDC_VSPOLARITY_AL (0x00000000U) /* 垂直同步极性低电平有效 */ #define LTDC_VSPOLARITY_AH LTDC_GCR_VSPOL /* 垂直同步极性高电平有效 */
- uint32_t DEPolarity
此参数用于设置数据使能极性,具体支持的参数如下:
#define LTDC_DEPOLARITY_AL (0x00000000U) /* 数据使能极性低电平有效 */ #define LTDC_DEPOLARITY_AH LTDC_GCR_DEPOL /* 数据使能极性高电平有效 */
- uint32_t PCPolarity
此参数用于设置像素时钟极性,具体支持的参数如下:
#define LTDC_PCPOLARITY_IPC (0x00000000U) /* 像素时钟极性低电平有效 */ #define LTDC_PCPOLARITY_IIPC LTDC_GCR_PCPOL /* 像素时钟极性告电平有效 */
- uint32_t HorizontalSync
此参数用于设置水平同步宽度,范围0x000 – 0xFFF,单位像素时钟个数。
- uint32_t VerticalSync
此参数用于设置垂直同步宽度,范围0x000 – 0x7FF,单位像素时钟个数。
- uint32_t AccumulatedHBP
此参数用于设置HSYNC水平同步宽度 + HBP水平后沿之和,范围HSYNC水平同步宽度到0xFFF,单位像素时钟个数。
- uint32_t AccumulatedVBP
此参数用于设置VSYNC垂直同步宽度 + VBP垂直后沿之和,范围VSYNC垂直同步宽度到0x7FF,单位像素时钟个数。
- uint32_t AccumulatedActiveW
此参数用于设置HSYNC水平同步宽度 + HBP水平后沿 + 有效宽度之和,范围AccumulatedHBP到0xFFF,单位像素时钟个数。
- uint32_t AccumulatedActiveH
此参数用于设置VSYNC垂直同步宽度 + VBP垂直后沿 + 有效高度之和,范围AccumulatedVBP到0x7FF,单位像素时钟个数。
- uint32_t TotalWidth
此参数用于设置HSYNC水平同步宽度 + HBP水平后沿 + 有效宽度 + HFP水平前沿之和,范围AccumulatedActiveW到0xFFF,单位像素时钟个数。
- uint32_t TotalHeigh
此参数用于设置VSYNC垂直同步宽度 + VBP垂直后沿 + 有效高度 +VFP垂直前沿之和,范围AccumulatedActiveH到0x7FF,单位像素时钟个数。
- LTDC_ColorTypeDef Backcolor
此参数用于设置背景层颜色,结构体LTDC_ColorTypeDef的定义如下:
typedef struct { uint8_t Blue; uint8_t Green; uint8_t Red; uint8_t Reserved; } LTDC_ColorTypeDef;
Bule用于设置蓝色值,范围0x00到0xFF。
Green用于设置绿色值,范围0x00到0xFF。
Red用于设置红色值,范围0x00到0xFF。
50.3.3 LTDC图层配置结构体LTDC_LayerCfgTypeDef
此结构体用于配置LTDC的图层,图层1和图层2均通过此结构体配置。
typedef struct { uint32_t WindowX0; uint32_t WindowX1; uint32_t WindowY0; uint32_t WindowY1; uint32_t PixelFormat; uint32_t Alpha; uint32_t Alpha0; uint32_t BlendingFactor1; uint32_t BlendingFactor2; uint32_t FBStartAdress; uint32_t ImageWidth; uint32_t ImageHeight; LTDC_ColorTypeDef Backcolor; } LTDC_LayerCfgTypeDef;
下面将这几个参数逐一为大家做个说明。
- uint32_t WindowX0
设置图层水平起始位置,范围0x000到0xFFF。
- uint32_t WindowX1
设置图层水平结束位置,范围0x000到0xFFF。
- uint32_t WindowY0
设置图层垂直起始位置,范围0x000到0x7FF。
- uint32_t WindowY1
设置图层垂直结束位置,范围0x000到0x7FF。
- uint32_t PixelFormat
设置图层所使用的颜色格式。
- uint32_t Alpha
设置常数Alpha,范围0x00 – 0xFF。
- uint32_t Alpha0
设置图层默认Alpha值,范围0x00 – 0xFF,与结构体成员Backcolor一起使用,组成ARGB颜色格式用于图层背景色。
- uint32_t BlendingFactor1
设置混合因数1,具体支持的参数如下:
#define LTDC_BLENDING_FACTOR1_CA (0x00000400U) /* 常数Alpha */ #define LTDC_BLENDING_FACTOR1_PAxCA (0x00000600U) /* 常数Alpha * 像素Alpha */
- uint32_t BlendingFactor2
设置混合因数2,具体支持的参数如下:
#define LTDC_BLENDING_FACTOR2_CA (0x00000400U) /* 常数Alpha */ #define LTDC_BLENDING_FACTOR2_PAxCA (0x00000600U) /* 常数Alpha * 像素Alpha */
- uint32_t FBStartAdress
设置颜色帧缓冲区地址,即图层的显存地址。
- uint32_t ImageWidth
设置颜色帧缓冲区行长,即要从显存读取一行的长度,范围0x0000到0x1FFF。
- uint32_t ImageHeight
设置颜色帧缓冲区行数,即要从显存读取的行数,范围0x000到0xFFF。
- LTDC_ColorTypeDef Backcolor
此参数用于设置图层默认色,结构体LTDC_ColorTypeDef的定义如下:
typedef struct { uint8_t Blue; uint8_t Green; uint8_t Red; uint8_t Reserved; } LTDC_ColorTypeDef;
Bule用于设置蓝色值,范围0x00到0xFF。
Green用于设置绿色值,范围0x00到0xFF。
Red用于设置红色值,范围0x00到0xFF。
注:如果大家设置的图层显示区没有显示满整个显示屏,且使用的ARGB颜色格式,那么未覆盖的区域会使用图层默认颜色。
50.3.4 LTDC句柄结构体LTDC_HandleTypeDef
HAL库在LTDC_TypeDef, LTDC_InitTypeDef和LTDC_LayerCfgTypeDef的基础上封装了一个结构体LTDC_HandleTypeDef,定义如下:
typedef struct { LTDC_TypeDef *Instance; LTDC_InitTypeDef Init; LTDC_LayerCfgTypeDef LayerCfg[MAX_LAYER]; HAL_LockTypeDef Lock; __IO HAL_LTDC_StateTypeDef State; __IO uint32_t ErrorCode; } LTDC_HandleTypeDef;
下面将这几个参数逐一做个说明。
- LTDC_TypeDef *Instance
这个参数是寄存器的例化,方便操作寄存器,详见本章3.1小节。
- LTDC_InitTypeDef Init;
这个参数是用户接触较多的,用于配置LTDC的时序参数配置,详见本章3.2小节。
- LTDC_LayerCfgTypeDef LayerCfg[MAX_LAYER]
这个参数用于LTDC的图层配置,对于STM32H7来说,支持双图层,MAX_LAYER=2。详见本章3.3小节。
- HAL_LockTypeDef Lock
__IO uint32_t State;
__IO uint32_t ErrorCode
这三个变量主要供函数内部使用。Lock用于设置锁状态,State用于设置LTDC通信状态,而ErrorCode用于配置代码错误。
50.3.5 LTDC初始化流程总结
在下章的51.4小节给出了详细的设计步骤。
50.4 源文件stm32h7xx_hal_ltdc.c
这里把我们把如下几个常用到的函数做个说明:
- HAL_LTDC_Init
- HAL_LTDC_ConfigLayer
- HAL_LTDC_SetAlpha
- HAL_LTDC_Reload
- HAL_LTDC_SetPixelFormat
- HAL_LTDC_SetWindowPosition
- HAL_LTDC_SetWindowSize_NoReload
LTDC的API函数主要分为两类:
- 一类是以_NoReload作为后缀
带后缀_NoReload的函数没有对重装寄存器进行配置。如果要配置的话,可以通过函数HAL_LTDC_Reload来立即更新配置或者在垂直消隐期间更新。
- 另一类是没有此后缀
不带后缀_NoReload的函数会立即更新配置。
===========================================================
能够实现这种操作的关键是LTDC外设有影子寄存器。如果选择不立即更新,可以将用户配置先放到影子寄存器,等垂直消隐期间再更新,这样做的好处是可以整体更新这些寄存器。下面是部分函数:
HAL_StatusTypeDef HAL_LTDC_ConfigLayer(LTDC_HandleTypeDef *hltdc, LTDC_LayerCfgTypeDef *pLayerCfg, uint32_t LayerIdx); HAL_StatusTypeDef HAL_LTDC_ConfigLayer_NoReload(LTDC_HandleTypeDef *hltdc, LTDC_LayerCfgTypeDef *pLayerCfg, uint32_t LayerIdx); HAL_StatusTypeDef HAL_LTDC_SetWindowSize(LTDC_HandleTypeDef *hltdc, uint32_t XSize, uint32_t YSize, uint32_t LayerIdx); HAL_StatusTypeDef HAL_LTDC_SetWindowSize_NoReload(LTDC_HandleTypeDef *hltdc, uint32_t XSize, uint32_t YSize, uint32_t LayerIdx); HAL_StatusTypeDef HAL_LTDC_SetWindowPosition(LTDC_HandleTypeDef *hltdc, uint32_t X0, uint32_t Y0, uint32_t LayerIdx); HAL_StatusTypeDef HAL_LTDC_SetWindowPosition_NoReload(LTDC_HandleTypeDef *hltdc, uint32_t X0, uint32_t Y0, uint32_t LayerIdx); HAL_StatusTypeDef HAL_LTDC_SetPixelFormat(LTDC_HandleTypeDef *hltdc, uint32_t Pixelformat, uint32_t LayerIdx); HAL_StatusTypeDef HAL_LTDC_SetPixelFormat_NoReload(LTDC_HandleTypeDef *hltdc, uint32_t Pixelformat, uint32_t LayerIdx); HAL_StatusTypeDef HAL_LTDC_SetAlpha(LTDC_HandleTypeDef *hltdc, uint32_t Alpha, uint32_t LayerIdx); HAL_StatusTypeDef HAL_LTDC_SetAlpha_NoReload(LTDC_HandleTypeDef *hltdc, uint32_t Alpha, uint32_t LayerIdx); HAL_StatusTypeDef HAL_LTDC_SetAddress(LTDC_HandleTypeDef *hltdc, uint32_t Address, uint32_t LayerIdx); HAL_StatusTypeDef HAL_LTDC_SetAddress_NoReload(LTDC_HandleTypeDef *hltdc, uint32_t Address, uint32_t LayerIdx); HAL_StatusTypeDef HAL_LTDC_SetPitch(LTDC_HandleTypeDef *hltdc, uint32_t LinePitchInPixels, uint32_t LayerIdx); HAL_StatusTypeDef HAL_LTDC_SetPitch_NoReload(LTDC_HandleTypeDef *hltdc, uint32_t LinePitchInPixels, uint32_t LayerIdx); HAL_StatusTypeDef HAL_LTDC_ConfigColorKeying(LTDC_HandleTypeDef *hltdc, uint32_t RGBValue, uint32_t LayerIdx); HAL_StatusTypeDef HAL_LTDC_ConfigColorKeying_NoReload(LTDC_HandleTypeDef *hltdc, uint32_t RGBValue, uint32_t LayerIdx); HAL_StatusTypeDef HAL_LTDC_EnableColorKeying(LTDC_HandleTypeDef *hltdc, uint32_t LayerIdx); HAL_StatusTypeDef HAL_LTDC_EnableColorKeying_NoReload(LTDC_HandleTypeDef *hltdc, uint32_t LayerIdx); HAL_StatusTypeDef HAL_LTDC_DisableColorKeying(LTDC_HandleTypeDef *hltdc, uint32_t LayerIdx); HAL_StatusTypeDef HAL_LTDC_DisableColorKeying_NoReload(LTDC_HandleTypeDef *hltdc, uint32_t LayerIdx); HAL_StatusTypeDef HAL_LTDC_EnableCLUT(LTDC_HandleTypeDef *hltdc, uint32_t LayerIdx); HAL_StatusTypeDef HAL_LTDC_EnableCLUT_NoReload(LTDC_HandleTypeDef *hltdc, uint32_t LayerIdx); HAL_StatusTypeDef HAL_LTDC_DisableCLUT(LTDC_HandleTypeDef *hltdc, uint32_t LayerIdx); HAL_StatusTypeDef HAL_LTDC_DisableCLUT_NoReload(LTDC_HandleTypeDef *hltdc, uint32_t LayerIdx);
50.4.1 函数HAL_LTDC_Init
函数原型:
HAL_StatusTypeDef HAL_LTDC_Init(LTDC_HandleTypeDef *hltdc) { uint32_t tmp = 0, tmp1 = 0; /* 检测参数是否有效 */ if(hltdc == NULL) { return HAL_ERROR; } /* 检查函数参数 */ assert_param(IS_LTDC_ALL_INSTANCE(hltdc->Instance)); assert_param(IS_LTDC_HSYNC(hltdc->Init.HorizontalSync)); assert_param(IS_LTDC_VSYNC(hltdc->Init.VerticalSync)); assert_param(IS_LTDC_AHBP(hltdc->Init.AccumulatedHBP)); assert_param(IS_LTDC_AVBP(hltdc->Init.AccumulatedVBP)); assert_param(IS_LTDC_AAH(hltdc->Init.AccumulatedActiveH)); assert_param(IS_LTDC_AAW(hltdc->Init.AccumulatedActiveW)); assert_param(IS_LTDC_TOTALH(hltdc->Init.TotalHeigh)); assert_param(IS_LTDC_TOTALW(hltdc->Init.TotalWidth)); assert_param(IS_LTDC_HSPOL(hltdc->Init.HSPolarity)); assert_param(IS_LTDC_VSPOL(hltdc->Init.VSPolarity)); assert_param(IS_LTDC_DEPOL(hltdc->Init.DEPolarity)); assert_param(IS_LTDC_PCPOL(hltdc->Init.PCPolarity)); if(hltdc->State == HAL_LTDC_STATE_RESET) { hltdc->Lock = HAL_UNLOCKED; /* 初始化GPIO,NVIC等 */ HAL_LTDC_MspInit(hltdc); } /* 设置LTDC外设状态 */ hltdc->State = HAL_LTDC_STATE_BUSY; /* 配置HSE,VS,DE和PC极性 */ hltdc->Instance->GCR &= ~(LTDC_GCR_HSPOL | LTDC_GCR_VSPOL | LTDC_GCR_DEPOL | LTDC_GCR_PCPOL); hltdc->Instance->GCR |= (uint32_t)(hltdc->Init.HSPolarity | hltdc->Init.VSPolarity | \ hltdc->Init.DEPolarity | hltdc->Init.PCPolarity); /* 设置水平同步宽度和垂直同步宽度 */ hltdc->Instance->SSCR &= ~(LTDC_SSCR_VSH | LTDC_SSCR_HSW); tmp = (hltdc->Init.HorizontalSync << 16); hltdc->Instance->SSCR |= (tmp | hltdc->Init.VerticalSync); /* 设置HSYNC水平同步宽度 + HBP水平后沿之和 设置VSYNC垂直同步宽度 + VBP垂直后沿之和 */ hltdc->Instance->BPCR &= ~(LTDC_BPCR_AVBP | LTDC_BPCR_AHBP); tmp = (hltdc->Init.AccumulatedHBP << 16); hltdc->Instance->BPCR |= (tmp | hltdc->Init.AccumulatedVBP); /* 设置HSYNC水平同步宽度 + HBP水平后沿 + 有效宽度之和 设置VSYNC垂直同步宽度 + VBP垂直后沿 + 有效高度之和 */ hltdc->Instance->AWCR &= ~(LTDC_AWCR_AAH | LTDC_AWCR_AAW); tmp = (hltdc->Init.AccumulatedActiveW << 16); hltdc->Instance->AWCR |= (tmp | hltdc->Init.AccumulatedActiveH); /* 设置总宽度 */ hltdc->Instance->TWCR &= ~(LTDC_TWCR_TOTALH | LTDC_TWCR_TOTALW); tmp = (hltdc->Init.TotalWidth << 16); hltdc->Instance->TWCR |= (tmp | hltdc->Init.TotalHeigh); /* 设置背景层颜色 */ tmp = ((uint32_t)(hltdc->Init.Backcolor.Green) << 8); tmp1 = ((uint32_t)(hltdc->Init.Backcolor.Red) << 16); hltdc->Instance->BCCR &= ~(LTDC_BCCR_BCBLUE | LTDC_BCCR_BCGREEN | LTDC_BCCR_BCRED); hltdc->Instance->BCCR |= (tmp1 | tmp | hltdc->Init.Backcolor.Blue); /* 使能传输错误中断和FIFO下溢中断 */ __HAL_LTDC_ENABLE_IT(hltdc, LTDC_IT_TE | LTDC_IT_FU); /* 使能LTDC */ __HAL_LTDC_ENABLE(hltdc); /* 无错误 Initialize the error code */ hltdc->ErrorCode = HAL_LTDC_ERROR_NONE; /* 设置LTDC状态 */ hltdc->State = HAL_LTDC_STATE_READY; return HAL_OK; }
函数描述:
此函数用于初始化LTDC的基本参数。
函数参数:
- 第1个参数是LTDC_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.4小节。
- 返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
注意事项:
- 如果配置了LTDC的NVIC,那么此函数会开启LTDC的传输错误中断和FIFO下溢中断,所以LTDC的中断服务程序别忘了写。
- 函数HAL_LTDC_MspInit用于初始化LTDC的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。
- 如果形参ltdc的结构体成员gState没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量LTDC_HandleTypeDef LtdcHandle。
对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_LTDC_STATE_RESET = 0x00U。
解决办法有三
方法1:用户自己初始LTDC和涉及到的GPIO等。
方法2:定义LTDC_HandleTypeDef LtdcHandle为全局变量。
方法3:下面的方法
if(HAL_LTDC_DeInit(&LtdcHandle) != HAL_OK) { Error_Handler(); } if(HAL_LTDC_Init(&LtdcHandle) != HAL_OK) { Error_Handler(); }
使用举例:
static LTDC_HandleTypeDef hltdc_F; uint16_t Width, Height, HSYNC_W, HBP, HFP, VSYNC_W, VBP, VFP; /* 配置信号极性 */ hltdc_F.Init.HSPolarity = LTDC_HSPOLARITY_AL; /* HSYNC 低电平有效 */ hltdc_F.Init.VSPolarity = LTDC_VSPOLARITY_AL; /* VSYNC 低电平有效 */ hltdc_F.Init.DEPolarity = LTDC_DEPOLARITY_AL; /* DE 低电平有效 */ hltdc_F.Init.PCPolarity = LTDC_PCPOLARITY_IPC; /* 时序配置 */ hltdc_F.Init.HorizontalSync = (HSYNC_W - 1); hltdc_F.Init.VerticalSync = (VSYNC_W - 1); hltdc_F.Init.AccumulatedHBP = (HSYNC_W + HBP - 1); hltdc_F.Init.AccumulatedVBP = (VSYNC_W + VBP - 1); hltdc_F.Init.AccumulatedActiveH = (Height + VSYNC_W + VBP - 1); hltdc_F.Init.AccumulatedActiveW = (Width + HSYNC_W + HBP - 1); hltdc_F.Init.TotalHeigh = (Height + VSYNC_W + VBP + VFP - 1); hltdc_F.Init.TotalWidth = (Width + HSYNC_W + HBP + HFP - 1); /* 配置背景层颜色 */ hltdc_F.Init.Backcolor.Blue = 0; hltdc_F.Init.Backcolor.Green = 0; hltdc_F.Init.Backcolor.Red = 0; hltdc_F.Instance = LTDC; /* 配置LTDC */ if (HAL_LTDC_Init(&hltdc_F) != HAL_OK) { /* 初始化错误 */ Error_Handler(__FILE__, __LINE__); }
50.4.2 函数HAL_LTDC_ConfigLayer
函数原型:
HAL_StatusTypeDef HAL_LTDC_ConfigLayer(LTDC_HandleTypeDef *hltdc, LTDC_LayerCfgTypeDef *pLayerCfg, uint32_t LayerIdx) { /* 检测参数 */ assert_param(IS_LTDC_LAYER(LayerIdx)); assert_param(IS_LTDC_HCONFIGST(pLayerCfg->WindowX0)); assert_param(IS_LTDC_HCONFIGSP(pLayerCfg->WindowX1)); assert_param(IS_LTDC_VCONFIGST(pLayerCfg->WindowY0)); assert_param(IS_LTDC_VCONFIGSP(pLayerCfg->WindowY1)); assert_param(IS_LTDC_PIXEL_FORMAT(pLayerCfg->PixelFormat)); assert_param(IS_LTDC_ALPHA(pLayerCfg->Alpha)); assert_param(IS_LTDC_ALPHA(pLayerCfg->Alpha0)); assert_param(IS_LTDC_BLENDING_FACTOR1(pLayerCfg->BlendingFactor1)); assert_param(IS_LTDC_BLENDING_FACTOR2(pLayerCfg->BlendingFactor2)); assert_param(IS_LTDC_CFBLL(pLayerCfg->ImageWidth)); assert_param(IS_LTDC_CFBLNBR(pLayerCfg->ImageHeight)); /* 上锁 */ __HAL_LOCK(hltdc); /* 设置LTDC外设状态 */ hltdc->State = HAL_LTDC_STATE_BUSY; /* 结构体之间直接赋值 */ hltdc->LayerCfg[LayerIdx] = *pLayerCfg; /* 配置LTDC图层 */ LTDC_SetConfig(hltdc, pLayerCfg, LayerIdx); /* 设置立即更新 */ hltdc->Instance->SRCR = LTDC_SRCR_IMR; /* 设置LTDC就绪 */ hltdc->State = HAL_LTDC_STATE_READY; /* 解锁 */ __HAL_UNLOCK(hltdc); return HAL_OK; }
函数描述:
此函数主要用于配置LTDC的图层。
函数参数:
- 第1个参数是LTDC_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.4小节。
- 第2个参数是LTDC_LayerCfgTypeDef类型的结构体指针变量,用于图层配置,结构体变量成员的详细介绍看本章3.3小节。
- 第3个参数用于要配置的图层,LTDC_LAYER_1表示配置图层1,LTDC_LAYER_2表示配置图层2。
- 返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
使用举例:
static LTDC_HandleTypeDef hltdc_F; uint16_t Width, Height, HSYNC_W, HBP, HFP, VSYNC_W, VBP, VFP; LTDC_LayerCfgTypeDef pLayerCfg; * 配置信号极性 */ hltdc_F.Init.HSPolarity = LTDC_HSPOLARITY_AL; /* HSYNC 低电平有效 */ hltdc_F.Init.VSPolarity = LTDC_VSPOLARITY_AL; /* VSYNC 低电平有效 */ hltdc_F.Init.DEPolarity = LTDC_DEPOLARITY_AL; /* DE 低电平有效 */ hltdc_F.Init.PCPolarity = LTDC_PCPOLARITY_IPC; /* 时序配置 */ hltdc_F.Init.HorizontalSync = (HSYNC_W - 1); hltdc_F.Init.VerticalSync = (VSYNC_W - 1); hltdc_F.Init.AccumulatedHBP = (HSYNC_W + HBP - 1); hltdc_F.Init.AccumulatedVBP = (VSYNC_W + VBP - 1); hltdc_F.Init.AccumulatedActiveH = (Height + VSYNC_W + VBP - 1); hltdc_F.Init.AccumulatedActiveW = (Width + HSYNC_W + HBP - 1); hltdc_F.Init.TotalHeigh = (Height + VSYNC_W + VBP + VFP - 1); hltdc_F.Init.TotalWidth = (Width + HSYNC_W + HBP + HFP - 1); /* 配置背景层颜色 */ hltdc_F.Init.Backcolor.Blue = 0; hltdc_F.Init.Backcolor.Green = 0; hltdc_F.Init.Backcolor.Red = 0; hltdc_F.Instance = LTDC; /* 开始配置图层 ------------------------------------------------------*/ /* 窗口显示区设置 */ pLayerCfg.WindowX0 = 0; pLayerCfg.WindowX1 = Width; pLayerCfg.WindowY0 = 0; pLayerCfg.WindowY1 = Height; /* 配置颜色格式 */ pLayerCfg.PixelFormat = LTDC_PIXEL_FORMAT_RGB565; /* 显存地址 */ pLayerCfg.FBStartAdress = LCDH7_FRAME_BUFFER; /* Alpha常数 (255 表示完全不透明) */ pLayerCfg.Alpha = 255; /* 无背景色 */ pLayerCfg.Alpha0 = 0; /* 完全透明 */ pLayerCfg.Backcolor.Blue = 0; pLayerCfg.Backcolor.Green = 0; pLayerCfg.Backcolor.Red = 0; /* 配置图层混合因数 */ pLayerCfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_CA; pLayerCfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_CA; /* 配置行列大小 */ pLayerCfg.ImageWidth = Width; pLayerCfg.ImageHeight = Height; /* 配置LTDC */ if (HAL_LTDC_Init(&hltdc_F) != HAL_OK) { /* 初始化错误 */ Error_Handler(__FILE__, __LINE__); } /* 配置图层1 */ if (HAL_LTDC_ConfigLayer(&hltdc_F, &pLayerCfg, LTDC_LAYER_1) != HAL_OK) { /* 初始化错误 */ Error_Handler(__FILE__, __LINE__); }
50.4.3 函数HAL_LTDC_SetAlpha
函数原型:
HAL_StatusTypeDef HAL_LTDC_SetAlpha(LTDC_HandleTypeDef *hltdc, uint32_t Alpha, uint32_t LayerIdx) { LTDC_LayerCfgTypeDef *pLayerCfg; /* 检查参数 */ assert_param(IS_LTDC_ALPHA(Alpha)); assert_param(IS_LTDC_LAYER(LayerIdx)); /* 上锁 */ __HAL_LOCK(hltdc); /* 设置LTDC状态 */ hltdc->State = HAL_LTDC_STATE_BUSY; /* 获取图层配置 */ pLayerCfg = &hltdc->LayerCfg[LayerIdx]; /* 配置图层Alpha值 */ pLayerCfg->Alpha = Alpha; /* 重新配置LTDC */ LTDC_SetConfig(hltdc, pLayerCfg, LayerIdx); /* 设置立即更新 */ hltdc->Instance->SRCR = LTDC_SRCR_IMR; /* 设置LTDC状态就绪 */ hltdc->State = HAL_LTDC_STATE_READY; /* 解锁 */ __HAL_UNLOCK(hltdc); return HAL_OK; }
函数描述:
此函数用于设置图层的常数Alpha。
函数参数:
- 第1个参数是LTDC_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.4小节。
- 第2个参数是Alpha值设置,0x00表示完全透明,0xFF表示完全不透明。
- 第3个参数用于要配置的图层,LTDC_LAYER_1表示配置图层1,LTDC_LAYER_2表示配置图层2。
- 返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
使用举例:
此函数的使用相对比较简单,直接调用即可。
50.4.4 函数HAL_LTDC_Reload
函数原型:
HAL_StatusTypeDef HAL_LTDC_Reload(LTDC_HandleTypeDef *hltdc, uint32_t ReloadType) { /* 检测参数 */ assert_param(IS_LTDC_RELOAD(ReloadType)); /* 上锁 */ __HAL_LOCK(hltdc); /* 设置LTDC状态 Change LTDC peripheral state */ hltdc->State = HAL_LTDC_STATE_BUSY; /* 使能LTDC重装中断 */ __HAL_LTDC_ENABLE_IT(hltdc, LTDC_IT_RR); /* 设置立即更新或者下一个垂直消隐期更新Apply Reload type */ hltdc->Instance->SRCR = ReloadType; /* 设置LTDC就绪 */ hltdc->State = HAL_LTDC_STATE_READY; /* 解锁 */ __HAL_UNLOCK(hltdc); return HAL_OK; }
函数描述:
此函数主要用于配合其它以_NoReload结尾的函数,可以设置立即更新配置或者下一个垂直消隐期更新。
函数参数:
- 第1个参数是LTDC_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.4小节。
- 第2个参数设置为LTDC_RELOAD_IMMEDIATE表示立即更新。
设置为LTDC_RELOAD_VERTICAL_BLANKING表示下一个垂直消隐期更新。
- 返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
使用举例:
此函数的使用相对比较简单,直接调用即可。
50.4.5 函数HAL_LTDC_SetPixelFormat
函数原型:
HAL_StatusTypeDef HAL_LTDC_SetPixelFormat(LTDC_HandleTypeDef *hltdc, uint32_t Pixelformat, uint32_t LayerIdx) { LTDC_LayerCfgTypeDef *pLayerCfg; /* 检测参数 */ assert_param(IS_LTDC_PIXEL_FORMAT(Pixelformat)); assert_param(IS_LTDC_LAYER(LayerIdx)); /* 上锁 */ __HAL_LOCK(hltdc); /* 设置LTDC状态 */ hltdc->State = HAL_LTDC_STATE_BUSY; /* 获取图层配置 */ pLayerCfg = &hltdc->LayerCfg[LayerIdx]; /* 重新配置图层颜色格式 */ pLayerCfg->PixelFormat = Pixelformat; /* 配置LTDC */ LTDC_SetConfig(hltdc, pLayerCfg, LayerIdx); /* 设置立即更新 */ hltdc->Instance->SRCR = LTDC_SRCR_IMR; /* 设置LTDC就绪 */ hltdc->State = HAL_LTDC_STATE_READY; /* 解锁 */ __HAL_UNLOCK(hltdc); return HAL_OK; }
函数描述:
此函数用于设置图层的颜色格式。
函数参数:
- 第1个参数是LTDC_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.4小节。
- 第2个参数是STM32H7支持的颜色格式,具体有如下8种:
#define LTDC_PIXEL_FORMAT_ARGB8888 (0x00000000U) /*!< ARGB8888 LTDC pixel format */ #define LTDC_PIXEL_FORMAT_RGB888 (0x00000001U) /*!< RGB888 LTDC pixel format */ #define LTDC_PIXEL_FORMAT_RGB565 (0x00000002U) /*!< RGB565 LTDC pixel format */ #define LTDC_PIXEL_FORMAT_ARGB1555 (0x00000003U) /*!< ARGB1555 LTDC pixel format */ #define LTDC_PIXEL_FORMAT_ARGB4444 (0x00000004U) /*!< ARGB4444 LTDC pixel format */ #define LTDC_PIXEL_FORMAT_L8 (0x00000005U) /*!< L8 LTDC pixel format */ #define LTDC_PIXEL_FORMAT_AL44 (0x00000006U) /*!< AL44 LTDC pixel format */ #define LTDC_PIXEL_FORMAT_AL88 (0x00000007U) /*!< AL88 LTDC pixel format */
- 第3个参数用于要配置的图层,LTDC_LAYER_1表示配置图层1,LTDC_LAYER_2表示配置图层2。
- 返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
使用举例:
此函数的使用相对比较简单,直接调用即可。
50.4.6 函数HAL_LTDC_SetWindowPosition
函数原型:
HAL_StatusTypeDef HAL_LTDC_SetWindowPosition(LTDC_HandleTypeDef *hltdc, uint32_t X0, uint32_t Y0, uint32_t LayerIdx) { LTDC_LayerCfgTypeDef *pLayerCfg; /* 检测参数 */ assert_param(IS_LTDC_LAYER(LayerIdx)); assert_param(IS_LTDC_CFBLL(X0)); assert_param(IS_LTDC_CFBLNBR(Y0)); /* 上锁 */ __HAL_LOCK(hltdc); /* 设置LTDC状态 */ hltdc->State = HAL_LTDC_STATE_BUSY; /* 获取图层配置 */ pLayerCfg = &hltdc->LayerCfg[LayerIdx]; /* 更新水平起始和结束位置 */ pLayerCfg->WindowX0 = X0; pLayerCfg->WindowX1 = X0 + pLayerCfg->ImageWidth; /* 更新垂直起始和结束位置 */ pLayerCfg->WindowY0 = Y0; pLayerCfg->WindowY1 = Y0 + pLayerCfg->ImageHeight; /* 设置LTDC参数 */ LTDC_SetConfig(hltdc, pLayerCfg, LayerIdx); /* 设置立即更新 */ hltdc->Instance->SRCR = LTDC_SRCR_IMR; /* 设置LTDC就绪 */ hltdc->State = HAL_LTDC_STATE_READY; /* 解锁 */ __HAL_UNLOCK(hltdc); return HAL_OK; }
函数描述:
此函数用于设置显示区在图层中的起始位置。
函数参数:
- 第1个参数是LTDC_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.4小节。
- 第2个参数是设置显示区在图层中的X轴起始位置。
- 第3个参数是设置显示区在图层中的Y轴起始位置。
- 第4个参数用于要配置的图层,LTDC_LAYER_1表示配置图层1,LTDC_LAYER_2表示配置图层2。
- 返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
使用举例:
此函数的使用相对比较简单,直接调用即可,注意设置的显示区最好不要超出图层范围。
50.4.7 函数HAL_LTDC_SetWindowSize_NoReload
函数原型:
HAL_StatusTypeDef HAL_LTDC_SetWindowSize_NoReload(LTDC_HandleTypeDef *hltdc, uint32_t XSize, uint32_t YSize, uint32_t LayerIdx) { LTDC_LayerCfgTypeDef *pLayerCfg; /* 检测参数 */ assert_param(IS_LTDC_LAYER(LayerIdx)); assert_param(IS_LTDC_CFBLL(XSize)); assert_param(IS_LTDC_CFBLNBR(YSize)); /* 上锁 */ __HAL_LOCK(hltdc); /* 设置LTDC状态 */ hltdc->State = HAL_LTDC_STATE_BUSY; /* 获取图层配置 */ pLayerCfg = &hltdc->LayerCfg[LayerIdx]; /* 更新水平结束位置 */ pLayerCfg->WindowX1 = XSize + pLayerCfg->WindowX0; /* 更新垂直解锁位置 */ pLayerCfg->WindowY1 = YSize + pLayerCfg->WindowY0; /* 重新配置颜色帧缓冲的行长 */ pLayerCfg->ImageWidth = XSize; /* 重新配置颜色帧缓冲的行数 */ pLayerCfg->ImageHeight = YSize; /* 设置LTDC参数 */ LTDC_SetConfig(hltdc, pLayerCfg, LayerIdx); /* 此函数没有配置立即更新配置,绘制下一个垂直消隐期更新 */ /* 设置LTDC就绪 */ hltdc->State = HAL_LTDC_STATE_READY; /* 解锁 */ __HAL_UNLOCK(hltdc); return HAL_OK; }
函数描述:
此函数用于设置图层显示区的大小,但不会立即更新,会在下一个垂直消隐期更新。
函数参数:
- 第1个参数是LTDC_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.4小节。
- 第2个参数设置图层显示区的行长,单位像素。
- 第3个参数是设置图层显示区的行数,单位像素。
- 第4个参数用于要配置的图层,LTDC_LAYER_1表示配置图层1,LTDC_LAYER_2表示配置图层2。
- 返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
使用举例:
此函数的使用相对比较简单,直接调用即可,注意设置的显示区最好不要超出图层范围。
50.5 总结
本章节涉及到的知识点比较多,而且比较重要,特别是第2小节中的几个知识点尤其重要,望初学者熟练掌握。