第3版emWin教程第4章 emWin上手之STM32H7 LTDC基础知识

Posted 安富莱电子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第3版emWin教程第4章 emWin上手之STM32H7 LTDC基础知识相关的知识,希望对你有一定的参考价值。

教程不断更新中:http://www.armbbs.cn/forum.php?mod=viewthread&tid=98429

第4章   emWin上手之STM32H7 LTDC基础知识

本章教程为大家讲解LTDC应用中最基本的汉字显示和2D图形显示功能实现。

4.1 初学者重要提示

4.2 LCD相关的基础支持

4.3 LCD硬件设计

4.4 LCD驱动设计

4.5 LCD板级支持包(bsp_ltdc_h7.c和bsp_tft_lcd.c)

4.6 LCD的驱动移植和使用

4.7 实验例程设计框架

4.8 实验例程说明

4.9 总结

 

 

4.1   初学者重要提示

  1.  本章是为emWin的LTDC移植部分做准备。
  2.   本章的第4小节LCD驱动设计非常重要。
  3.   如果自己观察的话,LCD上电会有一个瞬间高亮的问题,在此贴进行了描述:http://www.armbbs.cn/forum.php?mod=viewthread&tid=82619 。这个解决方案已经应用到本章配套的例子上。
  4.   本章节用到的汉字方案会在下章专门为大家讲解,下面是小字库的制作方法:http://www.armbbs.cn/forum.php?mod=viewthread&tid=202
  5.   测评STM32H7的LTDC+DMA2D性能,100Hz以上无压力,刷800*480图片和色块仅需2.6ms一张:http://www.armbbs.cn/forum.php?mod=viewthread&tid=91489
  6.   调试状态或者刚下载LCD的程序到H7里面,屏幕会抖动,这个是正常现象,之前F429就有这个问题,详情看此贴:http://www.armbbs.cn/forum.php?mod=viewthread&tid=16892
  7.   屏蔽MDK AC6使用中文GBK编码的警告方法,让大家可以继续使用GBK编码汉字:http://www.armbbs.cn/forum.php?mod=viewthread&tid=98670

4.2   LCD相关的基础知识

4.2.1  显示屏相关知识

显示屏的结构有必要给大家普及下,这里我们通过如下三种类型的显示屏进行说明,基本已经涵盖我们常用的方式了。

  •   RA8875 + RGB接口裸屏

首先RA8875是一个显示屏控制器,自带显存,它的作用就是让不支持RGB接口的MCU也可以使用RGB接口的大屏。这起到了一个桥接的作用,可以将RGB接口屏转换成8080总线接口、SPI接口或者I2C接口方式。这种情况下,甚至低速的51单片机都可以外接大屏了。另外像SSD1963也是同样的作用。

  •   ili9488类显示屏

这种类型是把显示控制器和显示屏都集成好了,支持8080总线接口,有些还支持SPI或者I2C接口,而且显存也都集成了,不过主要是驱动一些小屏。像ili9341,ili9326,SPFD5420等也是一样的。此外还要注意,部分这种类型显示屏也是支持RGB接口的,像ST官方的STM32F429探索板外接的ili9431就是用的RGB接口。

  •   STM32H7 + SDRAM + RGB接口裸屏

这个是我们本章节要讲解的,STM32H7是自带LCD控制器的,再配合SDRAM作为显示屏的显存,整体作用跟RA8875是一样的,可以直接外接RGB接口的屏了。

 

有了这些认识后,对于裸屏还有些知识点需要了解。首先,裸屏本身不是什么控制芯片都没有,其构成也是比较复杂的,有兴趣了解的话,可以搜索关键字“TFT结构”进行学习。其次,TFT裸屏中主要的两个IC是Gate Driver IC和Source Driver IC,这两个IC的引脚都超级多,基本都是几百个引脚。最后,不管使用的哪种裸屏,一般都有规格书,会给出时序参数,这个在配置STM32H7的LTDC时要用到,如果规格书没有直接给出时序参数,则会给出使用的Driver IC型号,用户可以搜索此Driver IC的手册,在手册中会给出。

为了让大家有个感性认识,我们来看一看TFT裸屏的实际效果,下面是SPDF5420显示屏,400*240分辨率:

 

下面是TFT裸屏,480*272分辨率:

 

下面是TFT裸屏,800*480分辨率:

 

4.2.2  电阻触摸和电容触摸相关知识

有了TFT裸屏后还要配套电阻触摸板或者电容触摸板才可以获取触摸信息。触摸板是贴到TFT屏上面的,然后再通过电阻触摸芯片就可以获取电阻触摸板的信息,通过电容触摸芯片采集电容触摸板的信息。教程配套开发板的显示屏使用了三种触摸IC,电阻触摸IC是STMPE811,电容触摸IC是GT811和FT5X06。其中,电阻触摸和电容触摸两者的区别是初学者务必要知道的:

  •   电阻触摸芯片STMPE811其实就是ADC,返回的是ADC数值,而电容触摸芯片GT811,GT911和FT5X06返回的是显示屏实际的坐标值。
  •   使用电阻触摸芯片STMPE811需要做触摸校准,而使用电容触摸芯片GT811,GT911和FT5X06是自动校准的,无需手动校准。

下面是四线电阻触摸板的效果:

 

下面是电容触摸板的效果:

 

了解了这些知识,基本已经够我们本章节使用了,更多电阻触摸和电容触摸的相关知识可以看这个文档,讲解比较全面:http://www.armbbs.cn/forum.php?mod=viewthread&tid=14898

4.3   LCD硬件设计

下面是RGB888硬件接口的原理图,STM32-V7开发板制作了三个硬件接口。

  •   加高2层的双排母接口

 

  •   2.54mm的排针接口

 

  •   FPC软排线接口方式

 

了解了原理图后,再来看下实际的接口效果:

 

通过上面的原理图,我们要了解以下几个问题:

  •   V7开发板采用的是RGB888硬件接口,也许大家会问ARGB8888这种颜色格式怎么用于这种接口?Alpha通道是软件编程的时候用的,用于设置透明度,透明度会反应到RGB颜色值上。
  •   STM32H7支持的8种颜色格式都可以在RGB888硬件接口上实现。
  •   如果大家用的是16位色的RGB565颜色格式,那么仅需用到LCD_R[7:3]、LCD_G[7:2] 和 LCD_B[7:3]引脚即可,没有用到的引脚可以继续用作其它功能。

4.4   LCD驱动设计

下面将程序设计中的相关问题逐一为大家做个说明。

4.4.1      第1步,LTDC显存使用SDRAM

设计LTDC驱动前,要先保证显存可以正常使用,V7开发板用的外部SDRAM作为显存。所以一定要保证SDRAM大批量读写数据时是正常的,SDRAM的测试可以自己专门做一个工程测试下。对于SDRAM的驱动实现,可以学习V7开发板BSP驱动教程第49章。不管你使用的是镁光的,海力士的,三星的,ISSI的或者华邦的,实现方法基本都是一样的。

V7开发板使用ISSI的32位带宽、32MB的SDRAM,如果想最大限度的发挥STM32H7驱动SDRAM的性能,强烈建议使用32位带宽的SDRAM,或者两个16位SDRAM组成32位带宽的SDRAM也是可以的。那SDRAM主要起到什么作用呢?作用有二:

  •   用作显示屏的显存

STM32H7的LTDC外接RGB接口屏是没有显存的,所以需要SDRAM用作显存。如果用户选择STM32H7 LTDC的颜色格式是32位色ARGB8888,那么所需要显存大小(单位字节)是:显示屏宽 * 显示屏高 * (32/8), 其中32/8是表示这种颜色格式的一个像素点需要4个字节来表示。又比如配置颜色格式是16位色的RGB565,那么需要的显存大小是:显示屏宽 * 显示屏高 * (16/8),其中16/8是表示这种颜色格式的一个像素点需要2个字节来表示。其它的颜色格式,依此类推。

  •   用作GUI动态内存

如果想要实现炫酷效果,GUI是极其消耗动态内存的,所以用户可以将SDRAM除了用于显存以外的所有内存全部用作GUI动态内存。

 

如果SDRAM的驱动测试已经没有问题了,就可以将其添加到工程里面了,V7使用的SDRAM驱动文件是bsp_fmc_sdram.c。图层1占用2MB,图层2占用2MB,最后28MB可做其它使用。也许会有初学者会问,每个图层分配2MB是不是有些多了?实际上不多的,因为我们要让不同的颜色格式都通用,这里分配2MB的话,教程实例使用很方便。大家实际项目中的使用可以配置成实际大小。具体的配置如下,详情见bsp_fmc_sdram.h文件:

#define EXT_SDRAM_ADDR      ((uint32_t)0xC0000000)
#define EXT_SDRAM_SIZE        (32 * 1024 * 1024)

/* LCD显存,第1页, 分配2M字节 */
#define SDRAM_LCD_BUF1         EXT_SDRAM_ADDR

/* LCD显存,第2页, 分配2M字节 */
#define SDRAM_LCD_BUF2        (EXT_SDRAM_ADDR + SDRAM_LCD_SIZE)

#define SDRAM_LCD_SIZE        (2 * 1024 * 1024)        /* 每层2M */
#define SDRAM_LCD_LAYER        2                    /* 2层 */

/* 剩下的28M字节,提供给应用程序使用 */
#define SDRAM_APP_BUF        (EXT_SDRAM_ADDR + SDRAM_LCD_SIZE * SDRAM_LCD_LAYER)
#define SDRAM_APP_SIZE        (EXT_SDRAM_SIZE - SDRAM_LCD_SIZE * SDRAM_LCD_LAYER)

由于用户要刷新数据到SDRAM,而且LTDC也要从SDRAM读取数据,这就属于多总线访问SDRAM,此时就要注意Cache配置。为了使用方便起见,直接将SDRAM配置为WT模式,这样用户刷新的数据就可以立即写入到SDRAM,从而不影响LTDC刷新。

4.4.2      第2步,LTDC涉及到的引脚配置

本章第3小节用到了哪些引脚,这些引脚全部要做初始化,初始化时别忘了初始化引脚对应的时钟:

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);      
    }
   /* 其它省略未写 */

}

4.4.3      第3步,LTDC时钟和时序配置

LTDC时序配置主要分三步就可以完成:

  1. 行同步,场同步和DE的极性配置。
  2. CLK时钟配置。
  3. 时序参数配置。

下面将这三点分别做个说明:

  •   行同步,场同步和DE的极性配置

这里以V7开发板7寸RGB屏使用的source driver ic OTA7001为例进行说明(手册下载地址:

http://www.armbbs.cn/forum.php?mod=viewthread&tid=18528)。

这几项配置要看OTA7001手册上面的时序图,对于DE模式,行同步和场同步的极性配置为高或者为低均可。因为我们这里使用的就是DE模式,所以主要配置DE的极性。这里要特别注意一个小问题,看时序图是DE高电平时数据有效,但是配置的时候要设置为低电平才可以。

下面的是V7开发板配套的7寸裸屏使用的source driver ic OTA7001的时序图:

 

实际配置STM32H7的工程时,将DE配置为低有效才是上面截图的效果,这个问题的确是有些奇葩了。

大家使用的时候也特别注意。

/* 配置信号极性 */    
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; /* Pixel Clock 或者Dot Clock极性 */

ps:注意LTDC_PCPOLARITY_IPC和LTDC_PCPOLARITY_IIPC两种极性,选择不当会有一些问题。比如下面这个现象,底边会有黑的。

 

下面是用示波器实际测量的波形效果,黄色的波形是DE信号,另一个是行同步信号Hsync:

 

将波形放缩后:

 

  •   LTDC的像素时钟输出配置

在OTA7001手册上面给出了支持的时钟范围:

 

由于USB和LTDC都是用的PLL3产生时钟,为了方便起见,直接将产生LTDC时钟的PLL3R设置为24MHz(PLL3Q输出的48MHz时钟供USB使用)。

首先,输入时钟 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 时钟LTDC clock frequency = PLLLCDCLK = 24MHz 

这里再额外补充点知识,LCD_CLK=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

  •   时序参数配置

时序参数的配置也比较容易,其实就是先看STM32H7参考手册上面的公式说明,说是公式,其实就是简单的加减法。然后将OTA7001的参数代到这个公式就可以了。又因为手册一般都是给出了参数的最小值,典型值和最大值,大家可以根据实际情况做简单的调整即可。需要用到的参数:

uint16_t Width, Height, HSYNC_W, VSYNC_W, HBP, HFP, VBP, VFP;

Horizontal Synchronization (Hsync)  对应变量HSYNC_W
Horizontal Back Porch (HBP)         对应变量HBP
Active Width                        对应变量Width
Horizontal Front Porch (HFP)        对应变量HFP
Vertical Synchronization (Vsync)    对应变量VSYNC_W
Vertical Back Porch (VBP)           对应变量VBP
Active Heigh                        对应变量Heigh
Vertical Front Porch (VFP)          对应变量VFP

STM32H7参考手册上面的公式如下:

*********************************************************************************************************
*       LCD_TFT 同步时序配置(整理自官方做的一个截图,言简意赅):
*       ----------------------------------------------------------------------------
*    
*                                                 Total Width
*                             <--------------------------------------------------->
*                       Hsync width HBP             Active Width                HFP
*                             <---><--><--------------------------------------><-->
*                         ____    ____|_______________________________________|____ 
*                             |___|   |                                       |    |
*                                     |                                       |    |
*                         __|         |                                       |    |
*            /|\\    /|\\  |            |                                       |    |
*             | VSYNC|   |            |                                       |    |
*             |Width\\|/  |__          |                                       |    |
*             |     /|\\     |         |                                       |    |
*             |  VBP |      |         |                                       |    |
*             |     \\|/_____|_________|_______________________________________|    |
*             |     /|\\     |         | / / / / / / / / / / / / / / / / / / / |    |
*             |      |      |         |/ / / / / / / / / / / / / / / / / / / /|    |
*    Total    |      |      |         |/ / / / / / / / / / / / / / / / / / / /|    |
*    Heigh    |      |      |         |/ / / / / / / / / / / / / / / / / / / /|    |
*             |Active|      |         |/ / / / / / / / / / / / / / / / / / / /|    |
*             |Heigh |      |         |/ / / / / / Active Display Area / / / /|    |
*             |      |      |         |/ / / / / / / / / / / / / / / / / / / /|    |
*             |      |      |         |/ / / / / / / / / / / / / / / / / / / /|    |
*             |      |      |         |/ / / / / / / / / / / / / / / / / / / /|    |
*             |      |      |         |/ / / / / / / / / / / / / / / / / / / /|    |
*             |      |      |         |/ / / / / / / / / / / / / / / / / / / /|    |
*             |     \\|/_____|_________|_______________________________________|    |
*             |     /|\\     |                                                      |
*             |  VFP |      |                                                      |
*            \\|/    \\|/_____|______________________________________________________|
*            
*     
*     每个LCD设备都有自己的同步时序值:
*     Horizontal Synchronization (Hsync) 
*     Horizontal Back Porch (HBP)       
*     Active Width                      
*     Horizontal Front Porch (HFP)     
*   
*     Vertical Synchronization (Vsync)  
*     Vertical Back Porch (VBP)         
*     Active Heigh                       
*     Vertical Front Porch (VFP)         
*     
*     LCD_TFT 窗口水平和垂直的起始以及结束位置 :
*     ----------------------------------------------------------------
*   
*     HorizontalStart = (Offset_X + Hsync + HBP);
*     HorizontalStop  = (Offset_X + Hsync + HBP + Window_Width - 1); 
*     VarticalStart   = (Offset_Y + Vsync + VBP);
*     VerticalStop    = (Offset_Y + Vsync + VBP + Window_Heigh - 1);
*
*********************************************************************************************************

OTA7001手册中已经给出了我们需要的数值:

uint16_t Width, Height, HSYNC_W, HBP, HFP, VSYNC_W, VBP, VFP。

 

 

参数设置好了,直接代入公式并与行同步,场同步和DE一起初始化:

/* 时序配置 */    
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);

至此,时序配置工作就完成了。

这里特别注意,当前程序中实际使用的参数与本小节的参数略有区别。由于这些参数都有较大的容错范围,所以很多参数都可以正常使用。

4.4.4  第4步,如何验证LTDC的时序配置是否正确

下面说一个最重要的问题,配置好时序了,怎么检查自己的配置是否成功了?用户仅需在函数LCDH7_ConfigLTDC里面的如下代码后面加上两个函数:

/* 配置LTDC  */  
if (HAL_LTDC_Init(&hltdc_F) != HAL_OK)
{
    /* 初始化错误 */
    Error_Handler(__FILE__, __LINE__);
}

/* 下面是添加的 */
LCD_SetBackLight(BRIGHT_DEFAULT);
while(1);

加上这两行代码后,再将背景层设置为一个合适的颜色,建议设置成红色,方便观察:

/* 配置背景层颜色 */
hltdc_F.Init.Backcolor.Blue = 0;
hltdc_F.Init.Backcolor.Green = 0;
hltdc_F.Init.Backcolor.Red = 255;

如果背景层可以正常显示红色,说明引脚和时序配置都是没有问题的。如果不成功要从以下几个方面着手检查:

  •   首先要清楚一点,当前的配置是否成功与SDRAM没有任何关系,因为背景层还用不到SDRAM,图层1和图层2才需要SDRAM做显存使用。
  •   从硬件着手检查,保证STM32H7芯片焊接没问题,TFT接口一定要牢固,防止接触不良,特别是使用FPC软排线的时候,测试阶段,软排线越短越好。有时候也可能是显示屏有问题,最好可以备两个显示屏测试。
  •   从软件配置着手检查,查看LTDC涉及到的所有引脚是否配置,引脚时钟是否使能。有时候无法显示也有可能是板子硬件设计不规范导致干扰较大造成的,此时,可以降低LTDC所涉及到GPIO的速度等级。
  •   如果显示了,但是显示的位置不正确,可以重新调整时序参数即可。

4.4.5      第5步,LTDC图层配置

LTDC的图层配置就比较好理解了,下面是完整的驱动代码:

1.    /*
2.    ******************************************************************************************************
3.    *    函 数 名: LCDH7_ConfigLTDC
4.    *    功能说明: 配置LTDC
5.    *    形    参: 无
6.    *    返 回 值: 无
7.    ******************************************************************************************************
8.    */
9.    static void LCDH7_ConfigLTDC(void)
10.    {
11.         /* GPIO初始化部分省略未写 */
12.        
13.        /*##-2- LTDC初始化 #############################################################*/  
14.        {    
15.            LTDC_LayerCfgTypeDef      pLayerCfg;
16.            uint16_t Width, Height, HSYNC_W, HBP, HFP, VSYNC_W, VBP, VFP;
17.            RCC_PeriphCLKInitTypeDef  PeriphClkInitStruct;
18.    
19.            /* 支持6种面板 */
20.            switch (g_LcdType)
21.            {
22.                case LCD_35_480X320:    /* 3.5寸 480 * 320 */    
23.                    Width = 480;
24.                    Height = 272;
25.                    HSYNC_W = 10;
26.                    HBP = 20;
27.                    HFP = 20;
28.                    VSYNC_W = 20;
29.                    VBP = 20;
30.                    VFP = 20;
31.                    break;
32.                
33.                case LCD_43_480X272:        /* 4.3寸 480 * 272 */            
34.                    Width = 480;
35.                    Height = 272;
36.    
37.                    HSYNC_W = 40;
38.                    HBP = 2;
39.                    HFP = 2;
40.                    VSYNC_W = 9;
41.                    VBP = 2;
42.                    VFP = 2;
43.            
44.                    /* LCD 时钟配置 */
45.                    /* PLL3_VCO Input = HSE_VALUE/PLL3M = 25MHz/5 = 5MHz */
46.                    /* PLL3_VCO Output = PLL3_VCO Input * PLL3N = 5MHz * 48 = 240MHz */
47.                    /* PLLLCDCLK = PLL3_VCO Output/PLL3R = 240 / 10 = 24MHz */
48.                    /* LTDC clock frequency = PLLLCDCLK = 24MHz */
49.                    /*
50.                        刷新率 = 24MHz /((Width + HSYNC_W  + HBP  + HFP)*(Height + VSYNC_W +  VBP  + VFP))
51.                                  = 24000000/((480 + 40  + 2  + 2)*(272 + 9 +  2  + 2)) 
52.                                 = 24000000/(524*285)
53.                                   = 160Hz    
54.    
55.                        当前这个配置方便用户使用PLL3Q输出的48MHz时钟供USB使用。
56.                    */
57.                    PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
58.                    PeriphClkInitStruct.PLL3.PLL3M = 5;
59.                    PeriphClkInitStruct.PLL3.PLL3N = 48;
60.                    PeriphClkInitStruct.PLL3.PLL3P = 2;
61.                    PeriphClkInitStruct.PLL3.PLL3Q = 5;
62.                    PeriphClkInitStruct.PLL3.PLL3R = 10;                
63.                    HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);                 
64.                    break;
65.                
66.                case LCD_50_480X272:        /* 5.0寸 480 * 272 */
67.                    Width = 480;
68.                    Height = 272;
69.                
70.                    HSYNC_W = 40;
71.                    HBP = 2;
72.                    HFP = 2;
73.                    VSYNC_W = 9;
74.                    VBP = 2;
75.                    VFP = 2;            
76.                    break;
77.                
78.                case LCD_50_800X480:        /* 5.0寸 800 * 480 */
79.                case LCD_70_800X480:        /* 7.0寸 800 * 480 */                    
80.                    Width = 800;
81.                    Height = 480;
82.    
83.                    HSYNC_W = 96;    
84.                    HBP = 10;
85.                    HFP = 10;
86.                    VSYNC_W = 2;
87.                    VBP = 10;
88.                    VFP = 10;            
89.    
90.                    /* LCD 时钟配置 */
91.                    /* PLL3_VCO Input = HSE_VALUE/PLL3M = 25MHz/5 = 5MHz */
92.                    /* PLL3_VCO Output = PLL3_VCO Input * PLL3N = 5MHz * 48 = 240MHz */
93.                    /* PLLLCDCLK = PLL3_VCO Output/PLL3R = 240 / 10 = 24MHz */
94.                    /* LTDC clock frequency = PLLLCDCLK = 24MHz */
95.                    /*
96.                        刷新率 = 24MHz /((Width + HSYNC_W  + HBP  + HFP)*(Height + VSYNC_W +  VBP  + VFP))
97.                                 = 24000000/((800 + 96  + 10  + 10)*(480 + 2 +  10  + 10)) 
98.                                = 24000000/(916*502)
99.                                  = 52Hz    
100.                
101.                根据需要可以加大,100Hz刷新率完全没问题,设置PeriphClkInitStruct.PLL3.PLL3N = 100即可
102.                此时的LTDC时钟是50MHz
103.                刷新率 = 50MHz /((Width + HSYNC_W  + HBP  + HFP )*(Height + VSYNC_W +  VBP  +VFP  )) 
104.                       = 5000000/(916*502) 
105.                       = 108.7Hz
106.    
107.                        当前这个配置方便用户使用PLL3Q输出的48MHz时钟供USB使用。
108.                    */ 
109.                    PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
110.                    PeriphClkInitStruct.PLL3.PLL3M = 5;
111.                    PeriphClkInitStruct.PLL3.PLL3N = 48;
112.                    PeriphClkInitStruct.PLL3.PLL3P = 2;
113.                    PeriphClkInitStruct.PLL3.PLL3Q = 5;
114.                    PeriphClkInitStruct.PLL3.PLL3R = 10; 
115.                    HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);                 
116.                    break;
117.                
118.                case LCD_70_1024X600:        /* 7.0寸 1024 * 600 */
119.                    /* 实测像素时钟 = 53.7M */
120.                    Width = 1024;
121.                    Height = 600;
122.    
123.                    HSYNC_W = 2;    
124.                    HBP = 157;
125.                    HFP = 160;
126.                    VSYNC_W = 2;
127.                    VBP = 20;
128.                    VFP = 12;        
129.                
130.                    PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
131.                    PeriphClkInitStruct.PLL3.PLL3M = 5;
132.                    PeriphClkInitStruct.PLL3.PLL3N = 48;
133.                    PeriphClkInitStruct.PLL3.PLL3P = 2;
134.                    PeriphClkInitStruct.PLL3.PLL3Q = 5;
135.                    PeriphClkInitStruct.PLL3.PLL3R = 10;
136.                    HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);             
137.                    break;
138.                
139.                default:
140.                    Width = 800;
141.                    Height = 480;
142.    
143.                    HSYNC_W = 80;
144.                    HBP = 10;
145.                    HFP = 10;
146.                    VSYNC_W = 10;
147.                    VBP = 10;
148.                    VFP = 10;        
149.                
150.                    /* LCD 时钟配置 */
151.                    /* PLL3_VCO Input = HSE_VALUE/PLL3M = 25MHz/5 = 5MHz */
152.                    /* PLL3_VCO Output = PLL3_VCO Input * PLL3N = 5MHz * 48 = 240MHz */
153.                    /* PLLLCDCLK = PLL3_VCO Output/PLL3R = 240 / 10 = 24MHz */
154.                    /* LTDC clock frequency = PLLLCDCLK = 24MHz */
155.                    /*
156.                        刷新率 = 24MHz /((Width + HSYNC_W  + HBP  + HFP)*(Height + VSYNC_W +  VBP  + VFP))
157.                                  = 24000000/((800 + 96  + 10  + 10)*(480 + 2 +  10  + 10)) 
158.                                 = 24000000/(916*502)
159.                                   = 52Hz
160.    
161.                根据需要可以加大,100Hz刷新率完全没问题,设置PeriphClkInitStruct.PLL3.PLL3N = 100即可
162.                此时的LTDC时钟是50MHz
163.                刷新率 = 50MHz /((Width + HSYNC_W  + HBP  + HFP )*(Height + VSYNC_W +  VBP  +VFP  )) 
164.                      = 5000000/(916*502) 
165.                      = 108.7Hz
166.    
167.                        当前这个配置方便用户使用PLL3Q输出的48MHz时钟供USB使用。
168.                    */ 
169.                    PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
170.                    PeriphClkInitStruct.PLL3.PLL3M = 5;
171.                    PeriphClkInitStruct.PLL3.PLL3N = 48;
172.                    PeriphClkInitStruct.PLL3.PLL3P = 2;
173.                    PeriphClkInitStruct.PLL3.PLL3Q = 5;
174.                    PeriphClkInitStruct.PLL3.PLL3R = 10;  
175.                    HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);             
176.                    break;
177.            }        
178.    
179.            g_LcdHeight = Height;
180.            g_LcdWidth = Width;
181.            
182.            /* 配置信号极性 */    
183.            hltdc_F.Init.HSPolarity = LTDC_HSPOLARITY_AL;    /* HSYNC 低电平有效 */
184.            hltdc_F.Init.VSPolarity = LTDC_VSPOLARITY_AL;     /* VSYNC 低

以上是关于第3版emWin教程第4章 emWin上手之STM32H7 LTDC基础知识的主要内容,如果未能解决你的问题,请参考以下文章

第3版emWin教程第5章 emWin上手之电阻触摸和电容触摸

第3版emWin教程第5章 emWin上手之电阻触摸和电容触摸

第3版emWin教程第6章 emWin上手之STM32H7 DMA2D加速

第3版emWin教程第2章 初学emWin的准备工作及其快速上手

第3版emWin教程第42章 emWin6.x窗口管理器之回调消息类型

第3版emWin教程第8章 emWin6.x的带OS方式移植(STM32H7之RGB接口)