完整教程下载地址: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 初学者重要提示

  1. 本章50.2小节中的几个知识点比较重要,比如DE同步模式和HV同步模式的区别,Alpha混合,水平消隐和垂直消隐等知识点尤其重要,需要大家理解透彻。
  2. 测评STM32H7的LTDC+DMA2D性能,100Hz以上无压力,刷800*480图片和色块仅需2.6ms一张:http://www.armbbs.cn/forum.php?mod=viewthread&tid=91489

50.2 LTDC基础知识

LTDC的几个关键知识点放在开头说:

  1. STM32H7的LTDC最大支持1024*768分辨率,且支持硬件双图层。实际支持的分辨率可能比1024*768要高一点,因为最终可以支持的最大分辨率是芯片后期定标的。
  2. 支持32位色,24位色,16位色和8位色。
  3. 可编程窗口位置和大小,可编程行同步,场同步和数据使能信号的极性。
  4. 查色表 (CLUT,Color look-up table),每个图层最高可记录256种24位色。
  5. 支持如下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的基本功能,然后再看手册了解细节。框图如下所示:

【STM32H7教程】第50章  STM32H7的LCD控制器LTDC基础知识和HAL库API-LMLPHP

通过这个框图,我们可以得到如下信息:

  • 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。

【STM32H7教程】第50章  STM32H7的LCD控制器LTDC基础知识和HAL库API-LMLPHP

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的时序控制就是下面几个参数的设置,这几个参数都可以通过寄存器进行配置。

【STM32H7教程】第50章  STM32H7的LCD控制器LTDC基础知识和HAL库API-LMLPHP

  • 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时序配置是否有问题。

【STM32H7教程】第50章  STM32H7的LCD控制器LTDC基础知识和HAL库API-LMLPHP

  • 对于背景层来说,仅支持单色设置,固定颜色格式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这段有效区域,边界区也是要刷新的,即下图总宽度以内,有效宽度以外的区域。

【STM32H7教程】第50章  STM32H7的LCD控制器LTDC基础知识和HAL库API-LMLPHP

水平消隐就是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刷新到显示屏的界面效果出现撕裂感,即下面这种现象:

【STM32H7教程】第50章  STM32H7的LCD控制器LTDC基础知识和HAL库API-LMLPHP

  •   解决这个问题的办法

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[];/*!< 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[]; /*!< Reserved, 0x1C-0x20 */
__IO uint32_t SRCR; /*!< LTDC Shadow Reload Configuration Register, Address offset: 0x24 */
uint32_t RESERVED2[]; /*!< Reserved, 0x28 */
__IO uint32_t BCCR; /*!< LTDC Background Color Configuration Register, Address offset: 0x2C */
uint32_t RESERVED3[]; /*!< 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 = , tmp1 = ; /* 检测参数是否有效 */
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 << );
hltdc->Instance->SSCR |= (tmp | hltdc->Init.VerticalSync); /* 设置HSYNC水平同步宽度 + HBP水平后沿之和
设置VSYNC垂直同步宽度 + VBP垂直后沿之和 */
hltdc->Instance->BPCR &= ~(LTDC_BPCR_AVBP | LTDC_BPCR_AHBP);
tmp = (hltdc->Init.AccumulatedHBP << );
hltdc->Instance->BPCR |= (tmp | hltdc->Init.AccumulatedVBP); /* 设置HSYNC水平同步宽度 + HBP水平后沿 + 有效宽度之和
设置VSYNC垂直同步宽度 + VBP垂直后沿 + 有效高度之和 */
hltdc->Instance->AWCR &= ~(LTDC_AWCR_AAH | LTDC_AWCR_AAW);
tmp = (hltdc->Init.AccumulatedActiveW << );
hltdc->Instance->AWCR |= (tmp | hltdc->Init.AccumulatedActiveH); /* 设置总宽度 */
hltdc->Instance->TWCR &= ~(LTDC_TWCR_TOTALH | LTDC_TWCR_TOTALW);
tmp = (hltdc->Init.TotalWidth << );
hltdc->Instance->TWCR |= (tmp | hltdc->Init.TotalHeigh); /* 设置背景层颜色 */
tmp = ((uint32_t)(hltdc->Init.Backcolor.Green) << );
tmp1 = ((uint32_t)(hltdc->Init.Backcolor.Red) << );
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表示时间溢出。

注意事项:

  1. 如果配置了LTDC的NVIC,那么此函数会开启LTDC的传输错误中断和FIFO下溢中断,所以LTDC的中断服务程序别忘了写。
  2. 函数HAL_LTDC_MspInit用于初始化LTDC的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。
  3. 如果形参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 - );
hltdc_F.Init.VerticalSync = (VSYNC_W - );
hltdc_F.Init.AccumulatedHBP = (HSYNC_W + HBP - );
hltdc_F.Init.AccumulatedVBP = (VSYNC_W + VBP - );
hltdc_F.Init.AccumulatedActiveH = (Height + VSYNC_W + VBP - );
hltdc_F.Init.AccumulatedActiveW = (Width + HSYNC_W + HBP - );
hltdc_F.Init.TotalHeigh = (Height + VSYNC_W + VBP + VFP - );
hltdc_F.Init.TotalWidth = (Width + HSYNC_W + HBP + HFP - ); /* 配置背景层颜色 */
hltdc_F.Init.Backcolor.Blue = ;
hltdc_F.Init.Backcolor.Green = ;
hltdc_F.Init.Backcolor.Red = ; 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 - );
hltdc_F.Init.VerticalSync = (VSYNC_W - );
hltdc_F.Init.AccumulatedHBP = (HSYNC_W + HBP - );
hltdc_F.Init.AccumulatedVBP = (VSYNC_W + VBP - );
hltdc_F.Init.AccumulatedActiveH = (Height + VSYNC_W + VBP - );
hltdc_F.Init.AccumulatedActiveW = (Width + HSYNC_W + HBP - );
hltdc_F.Init.TotalHeigh = (Height + VSYNC_W + VBP + VFP - );
hltdc_F.Init.TotalWidth = (Width + HSYNC_W + HBP + HFP - ); /* 配置背景层颜色 */
hltdc_F.Init.Backcolor.Blue = ;
hltdc_F.Init.Backcolor.Green = ;
hltdc_F.Init.Backcolor.Red = ; hltdc_F.Instance = LTDC; /* 开始配置图层 ------------------------------------------------------*/
/* 窗口显示区设置 */
pLayerCfg.WindowX0 = ;
pLayerCfg.WindowX1 = Width;
pLayerCfg.WindowY0 = ;
pLayerCfg.WindowY1 = Height; /* 配置颜色格式 */
pLayerCfg.PixelFormat = LTDC_PIXEL_FORMAT_RGB565; /* 显存地址 */
pLayerCfg.FBStartAdress = LCDH7_FRAME_BUFFER; /* Alpha常数 (255 表示完全不透明) */
pLayerCfg.Alpha = ; /* 无背景色 */
pLayerCfg.Alpha0 = ; /* 完全透明 */
pLayerCfg.Backcolor.Blue = ;
pLayerCfg.Backcolor.Green = ;
pLayerCfg.Backcolor.Red = ; /* 配置图层混合因数 */
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小节中的几个知识点尤其重要,望初学者熟练掌握。

05-11 11:32