STM32H7的LTCD控制学习和应用

STM32H7的LTCD控制学习和应用仅供个人学习 参考 armfly

大家好,欢迎来到IT知识分享网。

仅供个人学习,参考armfly

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 位蓝色数据。



























LTDC时钟源选择

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混合

BC = BF1 x C + BF2 x Cs 混合后的颜色= 混合系数 1 x 当前层颜色 + 混合系数 2 x 底层混合后的颜色 

混合系数 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同步模式的区别

区分FPS帧率和刷新率

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

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

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

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

驱动示例

分配栈的大小

在这里插入图片描述

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 = 0x; 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 = 0x; 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); } 

初始化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); } 

初始化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)) = /((480 + 40 + 2 + 2)*(272 + 9 + 2 + 2)) = /(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)) = /((800 + 96 + 10 + 10)*(480 + 2 + 10 + 10)) = /(916*502) = 52Hz 根据需要可以加大,100Hz刷新率完全没问题,设置PeriphClkInitStruct.PLL3.PLL3N = 100即可 此时的LTDC时钟是50MHz 刷新率 = 50MHz /((Width + HSYNC_W + HBP + HFP )*(Height + VSYNC_W + VBP +VFP )) = /(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)) = /((800 + 96 + 10 + 10)*(480 + 2 + 10 + 10)) = /(916*502) = 52Hz 根据需要可以加大,100Hz刷新率完全没问题,设置PeriphClkInitStruct.PLL3.PLL3N = 100即可 此时的LTDC时钟是50MHz 刷新率 = 50MHz /((Width + HSYNC_W + HBP + HFP )*(Height + VSYNC_W + VBP +VFP )) = /(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); /* 打开背光,设置为缺省亮度 */ } 

应用

 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); 

总结框图

在这里插入图片描述


免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/124884.html

(0)
上一篇 2025-10-02 17:45
下一篇 2025-10-02 18:10

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信