硬汉嵌入式论坛

 找回密码
 立即注册
查看: 7797|回复: 5
收起左侧

STM32F429之LTDC驱动图解

[复制链接]

3

主题

14

回帖

23

积分

新手上路

积分
23
发表于 2015-3-2 01:02:16 | 显示全部楼层 |阅读模式
本文基于ST官方demo板STM32F429 Discovery硬件平台,以看图说话的形式给大家讲解LTDC的主要参数配置。关于本文提到的代码部分均摘自本人另一片文章《STM32F429之LTDC代码模板》,LCD硬件为240x320,驱动IC为ili9341。本文目的意在让大家通过几张图就能掌握STM32F429 LTDC控制器的配置要领,而从干涩的文字中解脱出来,方便记忆。当然本文只是讲解了LTDC一些常用的设置,关于更多细节的操作还是得参照ST的官方datasheet。


一、关于LTDC外设的时钟配置,只需要记住下面这张图就可以了(图片来源于STM32CubeMX RCC时钟树):


该图所对应的代码如下:


[cpp] view plaincopy

    [li]/* Configure PLLSAI prescalers for LCD */  [/li][li]/* PLLSAI_VCO Input = HSE_VALUE/PLL_M = 1 Mhz */  [/li][li]/* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAI_N = 192 Mhz */  [/li][li]/* PLLLCDCLK = PLLSAI_VCO Output/PLLSAI_R = 192/3 = 64 Mhz */  [/li][li]/* LTDC clock frequency = PLLLCDCLK / RCC_PLLSAIDivR = 64/8 = 8 Mhz */  [/li][li]RCC_PLLSAIConfig(192, 7, 3);  [/li][li]RCC_LTDCCLKDivConfig(RCC_PLLSAIDivR_Div8);  [/li][li]  [/li][li]/* Enable PLLSAI Clock */  [/li][li]RCC_PLLSAICmd(ENABLE);  [/li][li]/* Wait for PLLSAI activation */  [/li][li]while(RCC_GetFlagStatus(RCC_FLAG_PLLSAIRDY) == RESET)  [/li][li]{  [/li][li]}  [/li]






二、关于LCD的信号时序配置参数,只需要记住下面这张图就可以了:


注意:这部分需要根据LCD Datasheet要求严格配置。

改图所对应的代码如下:


[cpp] view plaincopy

    [li]/* Initialize the horizontal synchronization polarity as active low*/  [/li][li]LTDC_InitStruct.LTDC_HSPolarity = LTDC_HSPolarity_AL;       [/li][li]/* Initialize the vertical synchronization polarity as active low */    [/li][li]LTDC_InitStruct.LTDC_VSPolarity = LTDC_VSPolarity_AL;       [/li][li]/* Initialize the data enable polarity as active low */   [/li][li]LTDC_InitStruct.LTDC_DEPolarity = LTDC_DEPolarity_AL;       [/li][li]/* Initialize the pixel clock polarity as input pixel clock */   [/li][li]LTDC_InitStruct.LTDC_PCPolarity = LTDC_PCPolarity_IPC;  [/li][li]  [/li][li]/* Timing configuration */  [/li][li]/* Configure horizontal synchronization width */       [/li][li]LTDC_InitStruct.LTDC_HorizontalSync = 9;  [/li][li]/* Configure vertical synchronization height */  [/li][li]LTDC_InitStruct.LTDC_VerticalSync = 1;  [/li][li]/* Configure accumulated horizontal back porch */  [/li][li]LTDC_InitStruct.LTDC_AccumulatedHBP = 29;   [/li][li]/* Configure accumulated vertical back porch */  [/li][li]LTDC_InitStruct.LTDC_AccumulatedVBP = 3;    [/li][li]/* Configure accumulated active width */    [/li][li]LTDC_InitStruct.LTDC_AccumulatedActiveW = 269;  [/li][li]/* Configure accumulated active height */  [/li][li]LTDC_InitStruct.LTDC_AccumulatedActiveH = 323;  [/li][li]/* Configure total width */  [/li][li]LTDC_InitStruct.LTDC_TotalWidth = 279;   [/li][li]/* Configure total height */  [/li][li]LTDC_InitStruct.LTDC_TotalHeigh = 327;  [/li]



三、LTDC的层——Layer
关于层的概念有以下几点:
1. STM32F429共有3个层,分别为Background、Layer1、Layer2,任何时候LCD显示的图像都是由层叠加后的最终结果;
2. Background层任何时候都有效,而Layer1、Layer2可以通过软件配置使能或禁止;
3. 这3个层的空间顺序,从下往上依次为Background、Layer1、Layer2,所以叠加的顺序如下图:


每个Layer支持窗口(Window)操作,所谓Window,就是指该层的图像只有在Window区域内有效,而Window区域外则用该层的DefaultColor填充。如下图:




关于Layer Window显示位置及大小的配置,记住下面这张图就可以了:


该图所对应的代码如下:


[cpp] view plaincopy

    [li]/* Windowing configuration */   [/li][li]/* In this case all the active display area is used to display a picture then: [/li][li]Horizontal start = horizontal synchronization + Horizontal back porch = 30 [/li][li]Horizontal stop = Horizontal start + window width -1 = 30 + 240 -1 [/li][li]Vertical start   = vertical synchronization + vertical back porch     = 4 [/li][li]Vertical stop   = Vertical start + window height -1  = 4 + 320 -1      */   [/li][li]LTDC_Layer_InitStruct.LTDC_HorizontalStart = 30;  [/li][li]LTDC_Layer_InitStruct.LTDC_HorizontalStop = (240 + 30 - 1);   [/li][li]LTDC_Layer_InitStruct.LTDC_VerticalStart = 4;  [/li][li]LTDC_Layer_InitStruct.LTDC_VerticalStop = 320 + 4 -1;   [/li]



每个Layer关联了一个显示缓冲区FrameBuffer,由于Background只能使用单色填充,所以它没有FrameBuffer。关于FrameBuffer有几个参数:Pixel Format、Buffer Address、Line Length、Number of lines、Buffer Pitch,这几个参数都是针对于Layer的Window而言的,它们的含义如下:
Pixel Format:不多说,RGB565、ARGB8888、ARGB1555等等;
Buffer Address:显示缓冲区的起始地址;
Line Length:window所对应的缓冲区宽度+3,以字节为单位;
Number of Lines:window所对应的缓冲区高度,以字节为单位;
Buffer Pitch:从这一行起始到下一行起始所经过的字节数,说白了就是换行时的一个行指针增量(也可以理解为整幅图像的宽度,以字节为单位);


假设Layer1的FrameBuffer如下图(RGB565):
                                       

设置window要显示的图像为下图粉色部分:


结合之前设置的Window的位置,最终显示的图像如下图(不考虑Layer2及透明色):


由此可以看到:
Start Address、Buffer Pitch决定了window在显存中每行的起始位置;
Line Length、Line Number决定了window在显存中的大小。
该部分所对应的代码如下:


[cpp] view plaincopy

    [li]/* Input Address configuration */      [/li][li]LTDC_Layer_InitStruct.LTDC_CFBStartAdress = (u32)FrameBuffer;  [/li][li]  [/li][li]/* the length of one line of pixels in bytes + 3 then : [/li][li]Line Lenth = Active high width x number of bytes per pixel + 3 [/li][li]Active high width         = 240 [/li][li]number of bytes per pixel = 2    (pixel_format : RGB565) [/li][li]*/  [/li][li]LTDC_Layer_InitStruct.LTDC_CFBLineLength = ((240 * 2) + 3);  [/li][li]  [/li][li]/*  the pitch is the increment from the start of one line of pixels to the [/li][li]start of the next line in bytes, then : [/li][li]Pitch = Active high width x number of bytes per pixel      [/li][li]*/  [/li][li]LTDC_Layer_InitStruct.LTDC_CFBPitch = (240 * 2);    [/li][li]  [/li][li]/* configure the number of lines */  [/li][li]LTDC_Layer_InitStruct.LTDC_CFBLineNumber = 320;  [/li]




需要注意的是,为了保证图像能正确显示,请务必确认显存中图像的大小与window显示的大小一致,即Line Length、Line Number要与(HStop-HStart)、(VStop-VStart)相一致,否则显示将不正确。
最后不要忘了设置完所有Layer的寄存器后,光调用LTDC_LayerCmd()还不够,还需要调用LTDC_ReloadConfig(ENABLE)函数才能使所有层的设置生效。


文章来源于本人博客:http://blog.csdn.net/hexiaolong2009/article/details/43988083
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106833
QQ
发表于 2015-3-2 09:04:12 | 显示全部楼层
谢谢楼主分享[s:151] [s:151]  继续加精
回复

使用道具 举报

3

主题

14

回帖

23

积分

新手上路

积分
23
 楼主| 发表于 2015-3-2 19:11:08 | 显示全部楼层

回 eric2013 的帖子

eric2013:谢谢楼主分享[s:151] [s:151]  继续加精 (2015-03-02 09:04) 
多谢站长支持!
回复

使用道具 举报

6

主题

390

回帖

408

积分

高级会员

积分
408
发表于 2015-5-3 16:26:43 | 显示全部楼层
谢谢楼主分享
回复

使用道具 举报

8

主题

33

回帖

7

积分

新手上路

积分
7
发表于 2015-6-16 21:47:48 | 显示全部楼层
/* Timing configuration */  
/* Configure horizontal synchronization width */      
LTDC_InitStruct.LTDC_HorizontalSync = 9;  
/* Configure vertical synchronization height */  
LTDC_InitStruct.LTDC_VerticalSync = 1;  
/* Configure accumulated horizontal back porch */  
LTDC_InitStruct.LTDC_AccumulatedHBP = 29;  
/* Configure accumulated vertical back porch */  
LTDC_InitStruct.LTDC_AccumulatedVBP = 3;   
/* Configure accumulated active width */   
LTDC_InitStruct.LTDC_AccumulatedActiveW = 269;  
/* Configure accumulated active height */  
LTDC_InitStruct.LTDC_AccumulatedActiveH = 323;  
/* Configure total width */  
LTDC_InitStruct.LTDC_TotalWidth = 279;  
/* Configure total height */  
LTDC_InitStruct.LTDC_TotalHeigh = 327;  

手册写的:
Total Width: The Total width is configured by programming the accumulated value
HSYNC Width + HBP + Active Width + HFP - 1 in the LTDC_TWCR register. The
HFP is the Horizontal front porch period.

这里的TotalHeigh与TotalWidth 不对吧
回复

使用道具 举报

8

主题

33

回帖

7

积分

新手上路

积分
7
发表于 2015-6-16 22:24:13 | 显示全部楼层
噢,噢,是我自己看错了,
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-6 20:23 , Processed in 0.167230 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表