• STM32H7的LCD控制学习和应用



    仅供个人学习,参考armfly

    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 里面存储。

    硬件框图

    在这里插入图片描述
    通过这个框图,我们可以得到如下信息:
    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 位蓝色数据。

    LTDC时钟源选择

    LTDC 仅有一个时钟源可供选择,即 PLL3R。
    在这里插入图片描述

    LTDC的时序配置

    在这里插入图片描述
    HSYNC width
    水平同步宽度设置,以 LCD_CLK 的像素时钟输出为单位。
    HBP(horizontal back porch period)
    水平后沿周期设置,以 LCD_CLK 的像素时钟输出为单位。
    Active width
    有效宽度设置,以 LCD_CLK 的像素时钟输出为单位。以 800480 分辨率为例,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 的像素时钟输出为单位。

    LTDC背景层、图层1、图层2和Alpha混合

    LTDC除了图层1和图层2两个以外,还有一个背景层,背景层的刷新不需要显存空间,所以可以用这个图层验证LTDC时序配置是否有问题。
    在这里插入图片描述
    对于背景层,只支持单色设置,固定颜色RGB888。
    对于图层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
    • 2

    混合系数 1 可以选择:
    常数 Alpha
    像素 Alpha x 常数 Alpha
    混合系数 2 可以选择:
    1 - 常数 Alpha
    1 - 像素 Alpha x 常数 Alpha
    底层混合后的颜色:
    可以是背景层。
    可以是背景层与图层 1 混合后的颜色。
    那么公式就变成如下形式(主要是如下两种):
    混合后的颜色 = 常数 Alpha x 当前层颜色 + (1 - 常数 Alpha) x 底层混合后的颜色。
    混合后的颜色 = 像素 Alpha x 常数 Alpha x 当前层颜色 + (1 - 像素 Alpha x 常数 Alpha) x 底层混合后的颜色。

    LTDC的水平消隐和垂直消隐

    正常情况下,LCD 的刷新就是从左到右,从上到下进行逐个像素点刷新。但仅刷新有效的显示区是不够的,比如 800480 分辨率,我们不仅仅要刷 **800480** 这段有效区域,边界区也是要刷新的,即下图总宽度以内,有效宽度以外的区域。
    水平消隐就是 LCD 扫描一行结束到另一行开始的时间,这段消失的时间就是水平消隐,即 HSYNC宽度+ HBP + HFP 这段消失的时间
    垂直消隐就是 LCD 扫描最后一行结束到第一行开始的时间,这段消失的时间就是垂直消隐,即 VSYNC宽度+ VBP + VFP 这段消失的时间
    在这里插入图片描述

    LCD的DE同步模式和HV同步模式的区别

    一般情况下,STM32H7都是用SDRAM作为LCD的显存,LTDC控制器会从SDRAM读取数据刷新到LCD显示屏上,具体如何刷新,涉及到了DE同步模式和HV同步模式。
    具体支持哪种模式是由裸屏自带的DriverIC决定。
    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,又重新从第一行扫描开始。

    区分FPS帧率和刷新率

    FPS 帧率是对 STM32H7 刷到显存,也就是 SDRAM 里面来说的,而是刷新率是实际 LCD 显示的速度。

    刷新率 = LTDC 输出时钟 /((Width + HSYNC_W + HBP + HFP )*(Height + VSYNC_W + VBP +VFP ))
    
    • 1

    一般情况下,帧率是远高于刷新率的,比如H7刷800*480的显示屏,帧数可以达到300多,但刷新率才108hz。我们可以使用emWin支持三缓冲,多余的帧数输出到其他的缓冲区,有效降低撕裂感和帧延迟,让多余的帧数有意义。

    避免LTDC刷新撕裂感的解决方法

    如果用户快速刷新颜色差异比较大的两种界面,会容易碰到这种撕裂问题。
    原因:
    用户更新显存数据期间,LTDC也在不断地读取显存的数据到显示屏上,如果用户才更新了部分界面,后面一部分还没有更新,就会出现撕裂感。
    解决方法:
    LTDC 刷新还在垂直消隐期间就将整个界面刷新完成,而我们如何只知道 LTDC 在垂直消隐期,通过函数 HAL_LTDC_ProgramLineEvent 设置刷新到指定行时进入中断即可,一般设置为第 0 行进入中断,然后设置个标志即可。
    一旦检测到这个标志,就通过 DMA2D 快速将界面刷新好,这样就有效的避免了撕裂感。

    驱动示例

    分配栈的大小

    在这里插入图片描述

    MPU和Cache配置

    数据 Cache 和指令 Cache 都开启。配置了 AXI SRAM 区(本例子未用到 AXI SRAM),FMC 的扩展 IO 区和 SDRAM。由于 SDRAM 要用于 LCD 的显存,方便起见,直接将其配置为 WT 模式。

    static void MPU_Config( void )
    {
    MPU_Region_InitTypeDef MPU_InitStruct;
    /* 禁止 MPU */
    HAL_MPU_Disable();
    /* 配置 AXI SRAM 的 MPU 属性为 Write back, Read allocate,Write allocate */
    MPU_InitStruct.Enable = MPU_REGION_ENABLE;
    MPU_InitStruct.BaseAddress = 0x24000000;
    MPU_InitStruct.Size = MPU_REGION_SIZE_512KB;
    MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
    MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
    MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
    MPU_InitStruct.Number = MPU_REGION_NUMBER0;
    MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
    MPU_InitStruct.SubRegionDisable = 0x00;
    MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
    HAL_MPU_ConfigRegion(&MPU_InitStruct);
    /* 配置 FMC 扩展 IO 的 MPU 属性为 Device 或者 Strongly Ordered */
    MPU_InitStruct.Enable = MPU_REGION_ENABLE;
    MPU_InitStruct.BaseAddress = 0x60000000;
    MPU_InitStruct.Size = ARM_MPU_REGION_SIZE_64KB;
    MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
    MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
    MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
    MPU_InitStruct.Number = MPU_REGION_NUMBER1;
    MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
    MPU_InitStruct.SubRegionDisable = 0x00;
    MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
    HAL_MPU_ConfigRegion(&MPU_InitStruct);
     /* 配置 SDRAM 的 MPU 属性为 Write through, read allocate,no write allocate */
    MPU_InitStruct.Enable = MPU_REGION_ENABLE;
    MPU_InitStruct.BaseAddress = 0xC0000000;
    MPU_InitStruct.Size = MPU_REGION_SIZE_32MB;
    MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
    MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
    MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
    MPU_InitStruct.Number = MPU_REGION_NUMBER2;
    MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
    MPU_InitStruct.SubRegionDisable = 0x00;
    MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
    HAL_MPU_ConfigRegion(&MPU_InitStruct);
    /*使能 MPU */
    HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    初始化SDRAM

    /*
    *********************************************************************************************************
    *	函 数 名: SDRAM_GPIOConfig
    *	功能说明: 配置连接外部SDRAM的GPIO
    *	形    参: 无
    *	返 回 值: 无
    *********************************************************************************************************
    */
    static void SDRAM_GPIOConfig(void)
    {
    	GPIO_InitTypeDef GPIO_Init_Structure;
    
        /*##-1- 使能FMC时钟和GPIO时钟 ##################################################*/
    	__HAL_RCC_GPIOD_CLK_ENABLE();
    	__HAL_RCC_GPIOE_CLK_ENABLE();
    	__HAL_RCC_GPIOF_CLK_ENABLE();
    	__HAL_RCC_GPIOG_CLK_ENABLE();
    	__HAL_RCC_GPIOH_CLK_ENABLE();
    	__HAL_RCC_GPIOI_CLK_ENABLE();
    
    	  /* 使能FMC时钟 */
    	  __HAL_RCC_FMC_CLK_ENABLE();
    		
    	/*-- 安富莱STM32-V7发板 SDRAM GPIO 定义 -----------------------------------------------------*/
    	/*
    	 +-------------------+--------------------+--------------------+--------------------+
    	 +                       SDRAM pins assignment                                      +
    	 +-------------------+--------------------+--------------------+--------------------+
    	 | PD0  <-> FMC_D2   | PE0  <-> FMC_NBL0  | PF0  <-> FMC_A0    | PG0 <-> FMC_A10    |
    	 | PD1  <-> FMC_D3   | PE1  <-> FMC_NBL1  | PF1  <-> FMC_A1    | PG1 <-> FMC_A11    |
    	 | PD8  <-> FMC_D13  | PE7  <-> FMC_D4    | PF2  <-> FMC_A2    | PG4 <-> FMC_A14    |
    	 | PD9  <-> FMC_D14  | PE8  <-> FMC_D5    | PF3  <-> FMC_A3    | PG5 <-> FMC_A15    |
    	 | PD10 <-> FMC_D15  | PE9  <-> FMC_D6    | PF4  <-> FMC_A4    | PG8 <-> FC_SDCLK   |
    	 | PD14 <-> FMC_D0   | PE10 <-> FMC_D7    | PF5  <-> FMC_A5    | PG15 <-> FMC_NCAS  |
    	 | PD15 <-> FMC_D1   | PE11 <-> FMC_D8    | PF11 <-> FC_NRAS   |--------------------+
    	 +-------------------| PE12 <-> FMC_D9    | PF12 <-> FMC_A6    | PG2  --- FMC_A12 (预留64M字节容量,和摇杆上键复用)
    	                     | PE13 <-> FMC_D10   | PF13 <-> FMC_A7    |
    	                     | PE14 <-> FMC_D11   | PF14 <-> FMC_A8    |
    	                     | PE15 <-> FMC_D12   | PF15 <-> FMC_A9    |
    	 +-------------------+--------------------+--------------------+
    	 | PH2 <-> FMC_SDCKE0| PI4 <-> FMC_NBL2   |
    	 | PH3 <-> FMC_SDNE0 | PI5 <-> FMC_NBL3   |
    	 | PH5 <-> FMC_SDNW  |--------------------+
    	 +-------------------+
    	 +-------------------+------------------+
    	 +   32-bits Mode: D31-D16              +
    	 +-------------------+------------------+
    	 | PH8 <-> FMC_D16   | PI0 <-> FMC_D24  |
    	 | PH9 <-> FMC_D17   | PI1 <-> FMC_D25  |
    	 | PH10 <-> FMC_D18  | PI2 <-> FMC_D26  |
    	 | PH11 <-> FMC_D19  | PI3 <-> FMC_D27  |
    	 | PH12 <-> FMC_D20  | PI6 <-> FMC_D28  |
    	 | PH13 <-> FMC_D21  | PI7 <-> FMC_D29  |
    	 | PH14 <-> FMC_D22  | PI9 <-> FMC_D30  |
    	 | PH15 <-> FMC_D23  | PI10 <-> FMC_D31 |
    	 +------------------+-------------------+
    
    	 +-------------------+
    	 +  Pins remapping   +
    	 +-------------------+
    	 | PC0 <-> FMC_SDNWE |
    	 | PC2 <-> FMC_SDNE0 |
    	 | PC3 <-> FMC_SDCKE0|
    	 +-------------------+
    
    	*/
    	 /*##-2- 配置GPIO ##################################################*/
    	GPIO_Init_Structure.Mode      = GPIO_MODE_AF_PP;
    	GPIO_Init_Structure.Pull      = GPIO_PULLUP;
    	GPIO_Init_Structure.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
    	GPIO_Init_Structure.Alternate = GPIO_AF12_FMC;
    
    	/* GPIOD */
    	GPIO_Init_Structure.Pin  = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_8| GPIO_PIN_9 | GPIO_PIN_10 |\
    							   GPIO_PIN_14 | GPIO_PIN_15;
    	HAL_GPIO_Init(GPIOD, &GPIO_Init_Structure);
    
    	/* GPIOE */  
    	GPIO_Init_Structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_7| GPIO_PIN_8 | GPIO_PIN_9 |\
    							  GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 |\
    							  GPIO_PIN_15;	  
    	HAL_GPIO_Init(GPIOE, &GPIO_Init_Structure);
    
    	/* GPIOF */  
    	GPIO_Init_Structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2| GPIO_PIN_3 | GPIO_PIN_4 |\
    							  GPIO_PIN_5 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 |\
    							  GPIO_PIN_15;
    	HAL_GPIO_Init(GPIOF, &GPIO_Init_Structure);
    
    	/* GPIOG */  
    	GPIO_Init_Structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 |  
    							  GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_8 | GPIO_PIN_15;
    	HAL_GPIO_Init(GPIOG, &GPIO_Init_Structure);
    
    	/* GPIOH */  
    	GPIO_Init_Structure.Pin = GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_5 | GPIO_PIN_8 | GPIO_PIN_9 |\
    							  GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 |\
    							  GPIO_PIN_15;	
    	HAL_GPIO_Init(GPIOH, &GPIO_Init_Structure); 
    
    	/* GPIOI */  
    	GPIO_Init_Structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 |\
    							  GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_9 | GPIO_PIN_10;
    	HAL_GPIO_Init(GPIOI, &GPIO_Init_Structure);  
    }
    /*
    *********************************************************************************************************
    *	函 数 名: SDRAM初始化序列
    *	功能说明: 完成SDRAM序列初始化
    *	形    参: hsdram: SDRAM句柄
    *			  Command: 命令结构体指针
    *	返 回 值: None
    *********************************************************************************************************
    */
    static void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram, FMC_SDRAM_CommandTypeDef *Command)
    {
    	__IO uint32_t tmpmrd =0;
     
        /*##-1- 时钟使能命令 ##################################################*/
    	Command->CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
    	Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;;
    	Command->AutoRefreshNumber = 1;
    	Command->ModeRegisterDefinition = 0;
    
    	/* 发送命令 */
    	HAL_SDRAM_SendCommand(hsdram, Command, SDRAM_TIMEOUT);
    
        /*##-2- 插入延迟,至少100us ##################################################*/
    	HAL_Delay(1);
    
        /*##-3- 整个SDRAM预充电命令,PALL(precharge all) #############################*/
    	Command->CommandMode = FMC_SDRAM_CMD_PALL;
    	Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
    	Command->AutoRefreshNumber = 1;
    	Command->ModeRegisterDefinition = 0;
    
    	/* 发送命令 */
    	HAL_SDRAM_SendCommand(hsdram, Command, SDRAM_TIMEOUT);
    
        /*##-4- 自动刷新命令 #######################################################*/
    	Command->CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
    	Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
    	Command->AutoRefreshNumber = 8;
    	Command->ModeRegisterDefinition = 0;
    
    	/* 发送命令 */
    	HAL_SDRAM_SendCommand(hsdram, Command, SDRAM_TIMEOUT);
    
        /*##-5- 配置SDRAM模式寄存器 ###############################################*/
    	tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1          |
    					 SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL   |
    					 SDRAM_MODEREG_CAS_LATENCY_3           |
    					 SDRAM_MODEREG_OPERATING_MODE_STANDARD |
    					 SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;
    
    	Command->CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
    	Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
    	Command->AutoRefreshNumber = 1;
    	Command->ModeRegisterDefinition = tmpmrd;
    
    	/* 发送命令 */
    	HAL_SDRAM_SendCommand(hsdram, Command, SDRAM_TIMEOUT);
    
        /*##-6- 设置自刷新率 ####################################################*/
        /*
            SDRAM refresh period / Number of rows)*SDRAM时钟速度 – 20
          = 64ms / 4096 *100MHz - 20
          = 1542.5 取值1543
        */
    	HAL_SDRAM_ProgramRefreshRate(hsdram, REFRESH_COUNT); 
    }
    /*
    *********************************************************************************************************
    *	函 数 名: bsp_InitExtSDRAM
    *	功能说明: 配置连接外部SDRAM的GPIO和FMC
    *	形    参: 无
    *	返 回 值: 无
    *********************************************************************************************************
    */
    void bsp_InitExtSDRAM(void)
    {
        SDRAM_HandleTypeDef      hsdram = {0};
    	FMC_SDRAM_TimingTypeDef  SDRAM_Timing = {0};
    	FMC_SDRAM_CommandTypeDef command = {0};
    
        
    	/* FMC SDRAM所涉及到GPIO配置 */
    	SDRAM_GPIOConfig();
    
    	/* SDRAM配置 */
    	hsdram.Instance = FMC_SDRAM_DEVICE;
    
    	/* 
           FMC使用的HCLK3时钟,200MHz,用于SDRAM的话,至少2分频,也就是100MHz,即1个SDRAM时钟周期是10ns
           下面参数单位均为10ns。
        */
    	SDRAM_Timing.LoadToActiveDelay    = 2; /* 20ns, TMRD定义加载模式寄存器的命令与激活命令或刷新命令之间的延迟 */
    	SDRAM_Timing.ExitSelfRefreshDelay = 7; /* 70ns, TXSR定义从发出自刷新命令到发出激活命令之间的延迟 */
    	SDRAM_Timing.SelfRefreshTime      = 4; /* 50ns, TRAS定义最短的自刷新周期 */
    	SDRAM_Timing.RowCycleDelay        = 7; /* 70ns, TRC定义刷新命令和激活命令之间的延迟 */
    	SDRAM_Timing.WriteRecoveryTime    = 2; /* 20ns, TWR定义在写命令和预充电命令之间的延迟 */
    	SDRAM_Timing.RPDelay              = 2; /* 20ns, TRP定义预充电命令与其它命令之间的延迟 */
    	SDRAM_Timing.RCDDelay             = 2; /* 20ns, TRCD定义激活命令与读/写命令之间的延迟 */
    
    	hsdram.Init.SDBank             = FMC_SDRAM_BANK1;               /* 硬件设计上用的BANK1 */
    	hsdram.Init.ColumnBitsNumber   = FMC_SDRAM_COLUMN_BITS_NUM_9;   /* 9列 */
    	hsdram.Init.RowBitsNumber      = FMC_SDRAM_ROW_BITS_NUM_12;     /* 12行 */
    	hsdram.Init.MemoryDataWidth    = FMC_SDRAM_MEM_BUS_WIDTH_32;	/* 32位带宽 */
    	hsdram.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;  /* SDRAM有4个BANK */
    	hsdram.Init.CASLatency         = FMC_SDRAM_CAS_LATENCY_3;       /* CAS Latency可以设置Latency1,2和3,实际测试Latency3稳定 */
    	hsdram.Init.WriteProtection    = FMC_SDRAM_WRITE_PROTECTION_DISABLE; /* 禁止写保护 */
    	hsdram.Init.SDClockPeriod      = SDCLOCK_PERIOD;                /* FMC时钟200MHz,2分频后给SDRAM,即100MHz */
    	hsdram.Init.ReadBurst          = FMC_SDRAM_RBURST_ENABLE;       /* 使能读突发 */
    	hsdram.Init.ReadPipeDelay      = FMC_SDRAM_RPIPE_DELAY_0;       /* 此位定CAS延时后延后多少个SDRAM时钟周期读取数据,实际测此位可以设置无需延迟 */
    
    	/* 配置SDRAM控制器基本参数 */
    	if(HAL_SDRAM_Init(&hsdram, &SDRAM_Timing) != HAL_OK)
    	{
    		/* Initialization Error */
    		Error_Handler(__FILE__, __LINE__);
    	}
    
    	/* 完成SDRAM序列初始化 */
    	SDRAM_Initialization_Sequence(&hsdram, &command);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225

    初始化LCD

    /*
    *********************************************************************************************************
    *	函 数 名: LCD_HardReset
    *	功能说明: 硬件复位. 针对复位口线由GPIO控制的产品。
    *	形    参: 无
    *	返 回 值: 无
    *********************************************************************************************************
    */
    void LCD_HardReset(void)
    {
    #if 0	
    	GPIO_InitTypeDef GPIO_InitStructure;
    
    	/* 使能 GPIO时钟 */
    	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
    	
    	/* 配置背光GPIO为推挽输出模式 */
    	GPIO_InitStructure.GPIO_Pin = GPIO_PIN_1;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    	GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;
    	GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    	GPIO_ResetBits(GPIOB, GPIO_PIN_1);
    	bsp_DelayMS(20);
    	GPIO_SetBits(GPIOB, GPIO_PIN_1);
    #endif	
    }
    static void LCDH7_ConfigLTDC(void)
    {
    	/* 配置LCD相关的GPIO */
    	{
    		/* GPIOs Configuration */
    		/*
    		+------------------------+-----------------------+----------------------------+
    		+                       LCD pins assignment                                   +
    		+------------------------+-----------------------+----------------------------+
    		|  LCDH7_TFT R0 <-> PI.15  |  LCDH7_TFT G0 <-> PJ.07 |  LCDH7_TFT B0 <-> PJ.12      |
    		|  LCDH7_TFT R1 <-> PJ.00  |  LCDH7_TFT G1 <-> PJ.08 |  LCDH7_TFT B1 <-> PJ.13      |
    		|  LCDH7_TFT R2 <-> PJ.01  |  LCDH7_TFT G2 <-> PJ.09 |  LCDH7_TFT B2 <-> PJ.14      |
    		|  LCDH7_TFT R3 <-> PJ.02  |  LCDH7_TFT G3 <-> PJ.10 |  LCDH7_TFT B3 <-> PJ.15      |
    		|  LCDH7_TFT R4 <-> PJ.03  |  LCDH7_TFT G4 <-> PJ.11 |  LCDH7_TFT B4 <-> PK.03      |
    		|  LCDH7_TFT R5 <-> PJ.04  |  LCDH7_TFT G5 <-> PK.00 |  LCDH7_TFT B5 <-> PK.04      |
    		|  LCDH7_TFT R6 <-> PJ.05  |  LCDH7_TFT G6 <-> PK.01 |  LCDH7_TFT B6 <-> PK.05      |
    		|  LCDH7_TFT R7 <-> PJ.06  |  LCDH7_TFT G7 <-> PK.02 |  LCDH7_TFT B7 <-> PK.06      |
    		-------------------------------------------------------------------------------
    		|  LCDH7_TFT HSYNC <-> PI.12  | LCDTFT VSYNC <->  PI.13 |
    		|  LCDH7_TFT CLK   <-> PI.14  | LCDH7_TFT DE   <->  PK.07 |
    		-----------------------------------------------------
    		*/		
    		GPIO_InitTypeDef GPIO_Init_Structure;
    
    		/*##-1- Enable peripherals and GPIO Clocks #################################*/  
    		/* 使能LTDC时钟 */
    		__HAL_RCC_LTDC_CLK_ENABLE();
    		/* 使能GPIO时钟 */
    		__HAL_RCC_GPIOI_CLK_ENABLE();
    		__HAL_RCC_GPIOJ_CLK_ENABLE();
    		__HAL_RCC_GPIOK_CLK_ENABLE();
    
    		/* GPIOI 配置 */
    		GPIO_Init_Structure.Pin       = GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; 
    		GPIO_Init_Structure.Mode      = GPIO_MODE_AF_PP;
    		GPIO_Init_Structure.Pull      = GPIO_NOPULL;
    		GPIO_Init_Structure.Speed     = GPIO_SPEED_FREQ_HIGH;
    		GPIO_Init_Structure.Alternate = GPIO_AF14_LTDC;  
    		HAL_GPIO_Init(GPIOI, &GPIO_Init_Structure);
    
    		/* GPIOJ 配置 */  
    		GPIO_Init_Structure.Pin       = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | \
    									  GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | \
    									  GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | \
    									  GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; 
    		GPIO_Init_Structure.Mode      = GPIO_MODE_AF_PP;
    		GPIO_Init_Structure.Pull      = GPIO_NOPULL;
    		GPIO_Init_Structure.Speed     = GPIO_SPEED_FREQ_HIGH;
    		GPIO_Init_Structure.Alternate = GPIO_AF14_LTDC;  
    		HAL_GPIO_Init(GPIOJ, &GPIO_Init_Structure);  
    
    		/* GPIOK 配置 */  
    		GPIO_Init_Structure.Pin       = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | \
    									  GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7; 
    		GPIO_Init_Structure.Mode      = GPIO_MODE_AF_PP;
    		GPIO_Init_Structure.Pull      = GPIO_NOPULL;
    		GPIO_Init_Structure.Speed     = GPIO_SPEED_FREQ_HIGH;
    		GPIO_Init_Structure.Alternate = GPIO_AF14_LTDC;  
    		HAL_GPIO_Init(GPIOK, &GPIO_Init_Structure);  	
    	}
    	
    	/*##-2- LTDC初始化 #############################################################*/  
    	{	
    		LTDC_LayerCfgTypeDef      pLayerCfg;
    		uint16_t Width, Height, HSYNC_W, HBP, HFP, VSYNC_W, VBP, VFP;
    		RCC_PeriphCLKInitTypeDef  PeriphClkInitStruct;
    
    		/* 支持6种面板 */
    		switch (g_LcdType)
    		{
    			case LCD_35_480X320:	/* 3.5寸 480 * 320 */	
    				Width = 480;
    				Height = 272;
    				HSYNC_W = 10;
    				HBP = 20;
    				HFP = 20;
    				VSYNC_W = 20;
    				VBP = 20;
    				VFP = 20;
    				break;
    			
    			case LCD_43_480X272:		/* 4.3寸 480 * 272 */			
    				Width = 480;
    				Height = 272;
    
    				HSYNC_W = 40;
    				HBP = 2;
    				HFP = 2;
    				VSYNC_W = 9;
    				VBP = 2;
    				VFP = 2;
    		
    				/* LCD 时钟配置 */
    				/* PLL3_VCO Input = HSE_VALUE/PLL3M = 25MHz/5 = 5MHz */
    				/* PLL3_VCO Output = PLL3_VCO Input * PLL3N = 5MHz * 24 = 120MHz */
    				/* PLLLCDCLK = PLL3_VCO Output/PLL3R = 120 / 10 = 12MHz */
    				/* LTDC clock frequency = PLLLCDCLK = 24MHz */
    				/*
    					刷新率 = 12MHz /((Width + HSYNC_W  + HBP  + HFP)*(Height + VSYNC_W +  VBP  + VFP))
                       		   = 12000000/((480 + 40  + 2  + 2)*(272 + 9 +  2  + 2)) 
    			               = 12000000/(524*285)
                               = 80Hz	
    
    					当前这个配置方便用户使用PLL3Q输出的48MHz时钟供USB使用。
    			    */
    				PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
    				PeriphClkInitStruct.PLL3.PLL3M = 5;
    				PeriphClkInitStruct.PLL3.PLL3N = 36;
    				PeriphClkInitStruct.PLL3.PLL3P = 2;
    				PeriphClkInitStruct.PLL3.PLL3Q = 5;
    				PeriphClkInitStruct.PLL3.PLL3R = 10;				
    				HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);     			
    				break;
    			
    			case LCD_50_480X272:		/* 5.0寸 480 * 272 */
    				Width = 480;
    				Height = 272;
    			
    				HSYNC_W = 40;
    				HBP = 2;
    				HFP = 2;
    				VSYNC_W = 9;
    				VBP = 2;
    				VFP = 2;			
    				break;
    			
    			case LCD_50_800X480:		/* 5.0寸 800 * 480 */
    			case LCD_70_800X480:		/* 7.0寸 800 * 480 */					
    				Width = 800;
    				Height = 480;
    
    				HSYNC_W = 96;	/* =10时,显示错位,20时部分屏可以的,80时全部OK */
    				HBP = 10;
    				HFP = 10;
    				VSYNC_W = 2;
    				VBP = 10;
    				VFP = 10;			
    
    				/* LCD 时钟配置 */
    				/* PLL3_VCO Input = HSE_VALUE/PLL3M = 25MHz/5 = 5MHz */
    				/* PLL3_VCO Output = PLL3_VCO Input * PLL3N = 5MHz * 48 = 240MHz */
    				/* PLLLCDCLK = PLL3_VCO Output/PLL3R = 240 / 10 = 24MHz */
    				/* LTDC clock frequency = PLLLCDCLK = 24MHz */
    				/*
    					刷新率 = 24MHz /((Width + HSYNC_W  + HBP  + HFP)*(Height + VSYNC_W +  VBP  + VFP))
                       		   = 24000000/((800 + 96  + 10  + 10)*(480 + 2 +  10  + 10)) 
    			               = 24000000/(916*502)
                               = 52Hz	
    			
    					根据需要可以加大,100Hz刷新率完全没问题,设置PeriphClkInitStruct.PLL3.PLL3N = 100即可
    					此时的LTDC时钟是50MHz
    					刷新率 = 50MHz /((Width + HSYNC_W  + HBP  + HFP )*(Height + VSYNC_W +  VBP  +VFP  )) 
    					       = 5000000/(916*502) 
    					       = 108.7Hz
    
    					当前这个配置方便用户使用PLL3Q输出的48MHz时钟供USB使用。
    			    */ 
    				PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
    				PeriphClkInitStruct.PLL3.PLL3M = 5;
    				PeriphClkInitStruct.PLL3.PLL3N = 48;
    				PeriphClkInitStruct.PLL3.PLL3P = 2;
    				PeriphClkInitStruct.PLL3.PLL3Q = 5;
    				PeriphClkInitStruct.PLL3.PLL3R = 10; 
    				HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);     			
    				break;
    			
    			case LCD_70_1024X600:		/* 7.0寸 1024 * 600 */
    				/* 实测像素时钟 = 53.7M */
    				Width = 1024;
    				Height = 600;
    
    				HSYNC_W = 2;	/* =10时,显示错位,20时部分屏可以的,80时全部OK */
    				HBP = 157;
    				HFP = 160;
    				VSYNC_W = 2;
    				VBP = 20;
    				VFP = 12;		
    			
    				PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
    				PeriphClkInitStruct.PLL3.PLL3M = 5;
    				PeriphClkInitStruct.PLL3.PLL3N = 48;
    				PeriphClkInitStruct.PLL3.PLL3P = 2;
    				PeriphClkInitStruct.PLL3.PLL3Q = 5;
    				PeriphClkInitStruct.PLL3.PLL3R = 10;
    				HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct); 			
    				break;
    			
    			default:
    				Width = 800;
    				Height = 480;
    
    				HSYNC_W = 80;	/* =10时,显示错位,20时部分屏可以的,80时全部OK */
    				HBP = 10;
    				HFP = 10;
    				VSYNC_W = 10;
    				VBP = 10;
    				VFP = 10;		
    			
    				/* LCD 时钟配置 */
    				/* PLL3_VCO Input = HSE_VALUE/PLL3M = 25MHz/5 = 5MHz */
    				/* PLL3_VCO Output = PLL3_VCO Input * PLL3N = 5MHz * 48 = 240MHz */
    				/* PLLLCDCLK = PLL3_VCO Output/PLL3R = 240 / 10 = 24MHz */
    				/* LTDC clock frequency = PLLLCDCLK = 24MHz */
    				/*
    					刷新率 = 24MHz /((Width + HSYNC_W  + HBP  + HFP)*(Height + VSYNC_W +  VBP  + VFP))
                       		   = 24000000/((800 + 96  + 10  + 10)*(480 + 2 +  10  + 10)) 
    			               = 24000000/(916*502)
                               = 52Hz
    
    					根据需要可以加大,100Hz刷新率完全没问题,设置PeriphClkInitStruct.PLL3.PLL3N = 100即可
    					此时的LTDC时钟是50MHz
    					刷新率 = 50MHz /((Width + HSYNC_W  + HBP  + HFP )*(Height + VSYNC_W +  VBP  +VFP  )) 
    					       = 5000000/(916*502) 
    					       = 108.7Hz
    
    					当前这个配置方便用户使用PLL3Q输出的48MHz时钟供USB使用。
    			    */ 
    				PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
    				PeriphClkInitStruct.PLL3.PLL3M = 5;
    				PeriphClkInitStruct.PLL3.PLL3N = 48;
    				PeriphClkInitStruct.PLL3.PLL3P = 2;
    				PeriphClkInitStruct.PLL3.PLL3Q = 5;
    				PeriphClkInitStruct.PLL3.PLL3R = 10;  
    				HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct); 			
    				break;
    		}		
    
    		g_LcdHeight = Height;
    		g_LcdWidth = Width;
    		
    		/* 配置信号极性 */	
    		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__);
    		}  
    		
    		#if 0
    		/* 配置图层2 */
    		if (HAL_LTDC_ConfigLayer(&hltdc_F, &pLayerCfg, LTDC_LAYER_2) != HAL_OK)
    		{
    			/* 初始化错误 */
    			Error_Handler(__FILE__, __LINE__);
    		} 
            #endif 		
    	}  
    
    #if	1
    	HAL_NVIC_SetPriority(LTDC_IRQn, 0xE, 0);
    	HAL_NVIC_EnableIRQ(LTDC_IRQn);
    #endif	
    }
    /*
    *********************************************************************************************************
    *	函 数 名: LCDH7_InitDMA2D
    *	功能说明: 配置DMA2D
    *	形    参: 无
    *	返 回 值: 无
    *********************************************************************************************************
    */
    static void LCDH7_InitDMA2D(void)
    {
    	/* 使能DMA2D时钟 */
    	__HAL_RCC_DMA2D_CLK_ENABLE();   
    	
    	/* 配置默认模式 */ 
    	hdma2d.Init.Mode         = DMA2D_R2M;
    	hdma2d.Init.ColorMode    = DMA2D_INPUT_RGB565;
    	hdma2d.Init.OutputOffset = 0x0;     
    
    	hdma2d.Instance          = DMA2D; 
    
    	if (HAL_DMA2D_Init(&hdma2d) != HAL_OK)
    	{
    		Error_Handler(__FILE__, __LINE__);
    	}
     }
     /*
    *********************************************************************************************************
    *	函 数 名: LCDH7_SetLayer
    *	功能说明: 切换层。只是更改程序变量,以便于后面的代码更改相关寄存器。硬件支持2层。
    *	形    参: 无
    *	返 回 值: 无
    *********************************************************************************************************
    */
    void LCDH7_SetLayer(uint8_t _ucLayer)
    {
    	if (_ucLayer == LCD_LAYER_1)
    	{
    		s_CurrentFrameBuffer = LCDH7_FRAME_BUFFER;
    		s_CurrentLayer = LCD_LAYER_1;
    	}
    	else if (_ucLayer == LCD_LAYER_2)
    	{
    		s_CurrentFrameBuffer = LCDH7_FRAME_BUFFER + BUFFER_OFFSET;
    		s_CurrentLayer = LCD_LAYER_2;
    	}
    }
    /*
    *********************************************************************************************************
    *	函 数 名: LCDH7_QuitWinMode
    *	功能说明: 退出窗口显示模式,变为全屏显示模式
    *	形    参: 无
    *	返 回 值: 无
    *********************************************************************************************************
    */
    void LCDH7_QuitWinMode(void)
    {
    	HAL_LTDC_SetWindowSize_NoReload(&hltdc_F, g_LcdWidth, g_LcdHeight, s_CurrentLayer);	/* 不立即更新 */
    	HAL_LTDC_SetWindowPosition(&hltdc_F, 0, 0, s_CurrentLayer);		/* 立即更新 */	
    }
    /*
    *********************************************************************************************************
    *	函 数 名: LCDH7_InitHard
    *	功能说明: 初始化LCD
    *	形    参: 无
    *	返 回 值: 无
    *********************************************************************************************************
    */
    void LCDH7_InitHard(void)
    {
    	LCDH7_ConfigLTDC();			/* 配置429 CPU内部LTDC */
    	LCDH7_InitDMA2D();          /* 使能DMA2D */
    	LCDH7_SetLayer(LCD_LAYER_1);/* 使用的图层1 */	
    	LCDH7_QuitWinMode();
    }
    
    /*
    *********************************************************************************************************
    *	函 数 名: LCDH7_SetDirection
    *	功能说明: 设置显示屏显示方向(横屏 竖屏)
    *	形    参: 显示方向代码 0 横屏正常, 1=横屏180度翻转, 2=竖屏, 3=竖屏180度翻转
    *	返 回 值: 无
    *********************************************************************************************************
    */
    void LCDH7_SetDirection(uint8_t _dir)
    {
    	uint16_t temp;
    	
    	if (_dir == 0 || _dir == 1)		/* 横屏, 横屏180度 */
    	{
    		if (g_LcdWidth < g_LcdHeight)
    		{
    			temp = g_LcdWidth;
    			g_LcdWidth = g_LcdHeight;
    			g_LcdHeight = temp;			
    		}
    	}
    	else if (_dir == 2 || _dir == 3)	/* 竖屏, 竖屏180°*/
    	{
    		if (g_LcdWidth > g_LcdHeight)
    		{
    			temp = g_LcdWidth;
    			g_LcdWidth = g_LcdHeight;
    			g_LcdHeight = temp;			
    		}
    	}
    }
    
    /*
    *********************************************************************************************************
    *	函 数 名: LCD_SetDirection
    *	功能说明: 设置显示屏显示方向(横屏 竖屏)
    *	形    参: 显示方向代码 0 横屏正常, 1=横屏180度翻转, 2=竖屏, 3=竖屏180度翻转
    *	返 回 值: 无
    *********************************************************************************************************
    */
    void LCD_SetDirection(uint8_t _dir)
    {
    	g_LcdDirection =  _dir;		/* 保存在全局变量 */
    
    	LCDH7_SetDirection(_dir);
    }
    
    *********************************************************************************************************
    *	函 数 名: LCDH7_ClrScr
    *	功能说明: 根据输入的颜色值清屏
    *	形    参: _usColor : 背景色
    *	返 回 值:*********************************************************************************************************
    */
    void LCDH7_ClrScr(uint16_t _usColor)
    {
    	LCDH7_FillRect(0, 0, g_LcdHeight, g_LcdWidth, _usColor);
    }
    /*
    *********************************************************************************************************
    *	函 数 名: LCD_ClrScr
    *	功能说明: 根据输入的颜色值清屏
    *	形    参: _usColor : 背景色
    *	返 回 值: 无
    *********************************************************************************************************
    */
    void LCD_ClrScr(uint16_t _usColor)
    {
    	LCDH7_ClrScr(_usColor);
    }
    
    void LCD_InitHard(void)
    {
    	LCD_HardReset();	/* 硬件复位 (STM32-V5, V6 无需),针对其他GPIO控制LCD复位的产品 */
    
    	LCDH7_InitHard();
    	
    	LCD_SetDirection(0);
    
    	LCD_ClrScr(CL_BLACK);	/* 清屏,显示全黑 */
    
    //	LCD_SetBackLight(BRIGHT_DEFAULT);	 /* 打开背光,设置为缺省亮度 */
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384
    • 385
    • 386
    • 387
    • 388
    • 389
    • 390
    • 391
    • 392
    • 393
    • 394
    • 395
    • 396
    • 397
    • 398
    • 399
    • 400
    • 401
    • 402
    • 403
    • 404
    • 405
    • 406
    • 407
    • 408
    • 409
    • 410
    • 411
    • 412
    • 413
    • 414
    • 415
    • 416
    • 417
    • 418
    • 419
    • 420
    • 421
    • 422
    • 423
    • 424
    • 425
    • 426
    • 427
    • 428
    • 429
    • 430
    • 431
    • 432
    • 433
    • 434
    • 435
    • 436
    • 437
    • 438
    • 439
    • 440
    • 441
    • 442
    • 443
    • 444
    • 445
    • 446
    • 447
    • 448
    • 449
    • 450
    • 451
    • 452
    • 453
    • 454
    • 455
    • 456
    • 457
    • 458
    • 459
    • 460
    • 461
    • 462
    • 463
    • 464
    • 465
    • 466
    • 467
    • 468
    • 469
    • 470
    • 471
    • 472
    • 473
    • 474
    • 475
    • 476
    • 477
    • 478
    • 479
    • 480
    • 481
    • 482
    • 483
    • 484
    • 485
    • 486
    • 487
    • 488
    • 489
    • 490
    • 491
    • 492
    • 493
    • 494
    • 495
    • 496
    • 497
    • 498
    • 499

    应用

    	FONT_T tFont12;			/* 定义一个字体结构体变量,用于设置字体参数 */
    	FONT_T tFont16;			/* 定义一个字体结构体变量,用于设置字体参数 */
        
    	uint8_t buf[100], count = 0;
    
    	/* 设置字体参数 */
    	{
    		tFont12.FontCode = FC_ST_12;	    /* 字体代码 12点阵 */
    		tFont12.FrontColor = CL_WHITE;		/* 字体颜色 */
    		tFont12.BackColor = CL_BLUE;	    /* 文字背景颜色 */
    		tFont12.Space = 0;					/* 文字间距,单位 = 像素 */
    	}
    	
    	/* 设置字体参数 */
    	{
    		tFont16.FontCode = FC_ST_16;	    /* 字体代码 16点阵 */
    		tFont16.FrontColor = CL_WHITE;		/* 字体颜色 */
    		tFont16.BackColor = CL_BLUE;	    /* 文字背景颜色 */
    		tFont16.Space = 0;					/* 文字间距,单位 = 像素 */
    	}
    	
        
    	bsp_Init();		/* 硬件初始化 */
    	PrintfLogo();	/* 打印例程名称和版本等信息 */
    
    	/* 延迟200ms再点亮背光,避免瞬间高亮 */
    	bsp_DelayMS(200); 
    	
    	/* 清屏 */
    	LCD_ClrScr(CL_BLACK);
    
    	/* 显示汉字 */
    	LCD_DispStr(5, 3, "故人西辞黄鹤楼,烟花三月下扬州。", &tFont12); 
    	LCD_DispStr(5, 18, "孤帆远影碧空尽,唯见长江天际流。", &tFont12); 
    	LCD_DispStr(5, 38, "故人西辞黄鹤楼,烟花三月下扬州。", &tFont16); 
    	LCD_DispStr(10, 58, "孤帆远影碧空尽,唯见长江天际流。", &tFont16); 
    	/* 绘制2D图形 */
    	LCD_DrawLine(5, 120, 100, 220, CL_RED);
    	LCD_DrawRect(120, 120, 100, 100, CL_RED);
    	LCD_DrawCircle(280, 170, 50, CL_RED);
    	LCD_Fill_Rect (340, 120, 100, 100, CL_BUTTON_GREY);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
  • 相关阅读:
    Bootstrap 标签
    Linux环境安装jdk
    中秋节听夜曲,Android OpenGL 呈现周董专属的玉兔主题音乐播放器
    电源自动测试系统-DC/DC 电源自动测试系统NSAT-8000,免费看方案视频效果
    通话清晰的蓝牙耳机有哪些?通话降噪蓝牙耳机推荐
    如何使用IDEA连接PostgreSQL数据库:从新手到高手的全面指南
    PHP微服务 hyperf+nacos使用
    Pytorch实战:基于鲸鱼WOA优化1DCNN的轴承故障诊断
    ios手机在app中调试h5页面
    Grafana 系列文章(十四):Helm 安装Loki
  • 原文地址:https://blog.csdn.net/yybyg/article/details/138115593