首页 > 其他分享 >《DFZU2EG_4EV MPSoc之FPGA开发指南》第十五章 RGB LCD彩条显示实验​

《DFZU2EG_4EV MPSoc之FPGA开发指南》第十五章 RGB LCD彩条显示实验​

时间:2022-12-10 10:00:28浏览次数:46  
标签:MPSoc FPGA DFZU2EG LCD lcd rgb RGB LVCMOS33 时钟

RGB LCD彩条显示实验​

TFT-LCD是一种液晶显示屏,它采用薄膜晶体管(TFT)技术提升图像质量,如提高图像亮度和对比度等。相比于传统的CRT显示器,TFT-LCD有着轻薄、功耗低、无辐射、图像质量好等诸多优点,因此广泛应用于电视机、电脑显示器、手机等各种显示设备中。​

本章包括以下几个部分:​

  1. RGB LCD简介​
  2. 实验任务​
  3. 硬件设计​
  4. 程序设计​
  5. 下载验证​


RGB LCD简介

TFT-LCD的全称是Thin Film Transistor-Liquid Crystal Display,即薄膜晶体管液晶显示屏,它显示的每个像素点都是由集成在液晶后面的薄膜晶体管独立驱动,因此TFT-LCD具有较高的响应速度以及较好的图像质量。正点原子推出的RGB LCD液晶屏较多,7寸RGB LCD屏的实物图如下图所示:​

《DFZU2EG_4EV MPSoc之FPGA开发指南》第十五章  RGB LCD彩条显示实验​_液晶屏


图15.1.1 ATK-7’RGB接口TFT液晶屏模块​

液晶显示器是现在最常用到的显示器,手机、电脑、各种人机交互设备等基本都用到了LCD,最常见的就是手机和电脑显示器了。由于笔者不是LCD从业人员,对于LCD的具体原理不了解,百度百科对于 LCD的原理解释如下:​

LCD的构造是在两片平行的玻璃基板当中放置液晶盒,下基板玻璃上设置 TFT(薄膜晶体管),上基板玻璃上设置彩色滤光片,通过TFT上的信号与电压改变来控制液晶分子的转动方向,从而达到控制每个像素点偏振光出射与否而达到显示目的。我们现在要在DFZU2EG/4EV MPSoC开发板上使用LCD,所以不需要去研究LCD 的具体实现原理,我们只需要从使用的角度去关注LCD的几个重要点:​

1、分辨率

提起LCD显示器,我们都会听到720P、1080P、2K或4K这样的字眼,这个就是LCD显示器分辨率。LCD示器都是由一个一个的像素点组成,像素点就类似一个灯(在OLED显示器中,像素点就是一个小灯),这个小灯是RGB灯,也就是由R(红色)、G(绿色)和B(蓝色)这三种颜色组成的,而RGB就是光的三原色。1080P的意思就是一个LCD屏幕上的像素数量是1920*1080个,也就是这个屏幕一列1080个像素点,一共1920列,如图15.1.2所示:​

《DFZU2EG_4EV MPSoc之FPGA开发指南》第十五章  RGB LCD彩条显示实验​_像素点_02


图15.1.2 像素点排布​

图15.1.2就是1080P显示器的像素示意图,X轴就是LCD显示器的横轴,Y轴就是显示器的竖轴。图中的小方块就是像素点,一共有1920*1080=2073600个像素点。左上角的A点是第一个像素点,右下角的C点就是最后一个像素点。2K就是2560*1440个像素点,4K是3840*2160个像素点。很明显,在LCD尺寸不变的情况下,分辨率越高越清晰。同样的,分辨率不变的情况下,LCD尺寸越小越清晰。比如我们常用的24寸显示器基本都是1080P的,而我们现在使用的5寸的手机基本也是1080P的,但是手机显示细腻程度就要比24寸的显示器要好很多!由此可见,LCD显示器的分辨率是一个很重要的参数,但是并不是分辨率越高的LCD就越好。衡量一款LCD的好坏,分辨率只是其中的一个参数,还有色彩还原程度、色彩偏离、亮度、可视角度、屏幕刷新率等其他参数。​

2、像素格式

上面讲了,一个像素点就相当于一个RGB小灯,通过控制R、G、B这三种颜色的亮度就可以显示出各种各样的色彩。那该如何控制R、G、B这三种颜色的显示亮度呢?一般一个R、G、B这三部分分别使用8bit的数据,那么一个像素点就是8bit*3=24bit,也就是说一个像素点3个字节,这种像素格式称为 RGB888。当然常用的像素点格式还有RGB565,只需要两个字节,但在色彩鲜艳度上较差一些。我们DFZU2EG/4EV MPSoC开发板上的RGB TFT-LCD接口采用的RGB888的像素格式,共需要24位,每一位对应RGB的颜色分量如下图所示:​

《DFZU2EG_4EV MPSoc之FPGA开发指南》第十五章  RGB LCD彩条显示实验​_液晶屏_03


图15.1.3 RGB888数据格式​

在图15.1.3中,一个像素点占用3个字节,其中bit23~bit16是RED通道,bit15~bit8是GREEN通道,bit7~bit0是BLUE通道。所以红色对应的值就是24’hFF0000,绿色对应的值就是24’h00FF00,蓝色对应的值为24’h0000FF。通过调节R、G、B的比例可以产生其它的颜色,比如24’hFFFF00就是黄色,24’h000000就是黑色,24’hFFFFFF就是白色。大家可以打开电脑的“画图”工具,在里面使用调色板即可获取到想要的颜色对应的数值,如图15.1.4所示:​

《DFZU2EG_4EV MPSoc之FPGA开发指南》第十五章  RGB LCD彩条显示实验​_液晶屏_04


图15.1.4 调色板颜色选取​

3、LCD屏幕接口

LCD屏幕或者说显示器有很多种接口,比如在显示器上常见的VGA、HDMI、DP等等,DFZU2EG/4EV MPSoC开发板支持RGB接口的LCD和HDMI接口的显示器。本章我们介绍的是RGB LCD接口,RGB LCD接口的信号线如下表所示:​

表15.1.1 RGB数据线​

信号线​

描述​

R[7:0]​

8根红色数据线​

G[7:0]​

8根绿色数据线​

B[7:0]​

8根蓝色数据线​

DE​

数据使能线​

VSYNC​

垂直同步信号线​

HSYNC​

水平同步信号线​

PCLK​

像素时钟信号线​

表15.1.1就是RGB LCD的信号线,R[7:0]、G[7:0]和B[7:0]是24位数据,DE、VSYNC、HSYNC和PCLK是四个控制信号。​

正点原子一共有五款RGB LCD屏幕,型号分别为ATK-4342(4.3寸,480*272)、ATK-4384(4.3寸,800*480)、ATK-7084(7寸,800*480)、ATK-7016(7寸,1024*600)和ATK-1018(10.1寸,1280*800)。这里以ATK-7016这款屏幕为例讲解,ATK-7016的屏幕接口原理图如所示:​

《DFZU2EG_4EV MPSoc之FPGA开发指南》第十五章  RGB LCD彩条显示实验​_数据_05


图15.1.5 RGB LCD液晶屏幕接口​

图中J1就是对外接口,是一个40PIN的FPC座(0.5mm间距),通过FPC线,可以连接到DFZU2EG/4EV MPSoCZYNQ开发板上面,从而实现和开发板的连接。该接口十分完善,采用RGB888格式,并支持触摸屏和背光控制。右侧的几个电阻,并不是都焊接的,而是可以用户自己选择。默认情况,R1和R6 焊接,设置LCD_LR和LCD_UD,控制LCD的扫描方向,是从左到右,从上到下(横屏看)。而LCD_R7/G7/B7 则用来设置LCD的ID,由于RGBLCD没有读写寄存器,也就没有所谓的ID,这里我们通过在模块上面,控制R7/G7/B7的上/下拉,来自定义LCD模块的ID,帮助MCU判断当前LCD面板的分辨率和相关参数,以提高程序兼容性。这几个位的设置关系如表15.1.2所示:​

表15.1.2 RGB LCD模块和ID对应关系​

M2​

LCD_B7​

M1​

LCD_G7​

M0​

LCD_R7​

LCD ID​

说明​

0​

0​

0​

4342​

ATK-4342 RGB LCD模块,分辨率:480*272​

0​

0​

1​

7084​

ATK-7084 RGB LCD模块,分辨率:800*480​

0​

1​

0​

7016​

ATK-7016 RGB LCD模块,分辨率:1024*600​

1​

0​

0​

4384​

ATK-4384 RGB LCD模块,分辨率:800*480​

1​

0​

1​

1018​

ATK-1018 RGB LCD模块,分辨率:1280*800​

X​

X​

X​

NC​

暂时未用到​

ATK-7016模块,就设置M2:M0 = 010即可。这样,我们在程序里面,读取LCD_R7/G7/B7,得到M0:M2 的值,从而判断RGB LCD模块的型号,并执行不同的配置,即可实现不同LCD模块的兼容。​

4、LCD时间参数

如果将LCD显示一帧图像的过程想象成绘画,那么在显示的过程中就是用一根“笔”在不同的像素点画上不同的颜色。这根笔按照从左至右、从上到下的顺序扫描每个像素点,并且在像素画上对应的颜色,当画到最后一个像素点的时候一幅图像就绘制好了。假如一个LCD的分辨率为1024*600,那么其扫描如图15.1.6所示:​

《DFZU2EG_4EV MPSoc之FPGA开发指南》第十五章  RGB LCD彩条显示实验​_像素点_06


图15.1.6 LCD一帧图像扫描图​

结合图15.1.6我们来看一下LCD是怎么扫描显示一帧图像的。一帧图像也是由一行一行组成的。HSYNC是水平同步信号,也叫做行同步信号,当产生此信号的话就表示开始显示新的一行了,所以此信号都是在图15.1.6的最左边。VSYNC信号是垂直同步信号,也叫做帧同步信号,当产生此信号的话就表示开始显示新的一帧图像了,所以此信号在图15.1.6的左上角。​

在图15.1.6可以看到有一圈“黑边”,真正有效的显示区域是中间的白色部分。那这一圈“黑边”是什么东西呢?这就要从显示器的“祖先”CRT显示器开始说起了,CRT显示器就是以前很常见的那种大屁股显示器,在2019年应该很少见了,如果在农村应该还是可以见到的。CRT显示器屁股后面是个电子枪,这个电子枪就是我们上面说的“画笔”,电子枪打出的电子撞击到屏幕上的荧光物质使其发光。只要控制电子枪从左到右扫完一行(也就是扫描一行),然后从上到下扫描完所有行,这样一帧图像就显示出来了。也就是说,显示一帧图像电子枪是按照‘Z’形在运动,当扫描速度很快的时候看起来就是一幅完成的画面了。​

当显示完一行以后会发出HSYNC信号,此时电子枪就会关闭,然后迅速的移动到屏幕的左边,当 HSYNC信号结束以后就可以显示新的一行数据了,电子枪就会重新打开。在HSYNC信号结束到电子枪重新打开之间会插入一段延时,这段延时就是图15.1.6中的HBP。当显示完一行以后就会关闭电子枪等待 HSYNC信号产生,关闭电子枪到HSYNC信号产生之间会插入一段延时,这段延时就是图15.1.6中的HFP 信号。同理,当显示完一帧图像以后电子枪也会关闭,然后等到VSYNC信号产生,期间也会加入一段延时,这段延时就是图15.1.6中的VFP。VSYNC信号产生,电子枪移动到左上角,当VSYNC信号结束以后电子枪重新打开,中间也会加入一段延时,这段延时就是图15.1.6中的VBP。​

HBP、HFP、VBP和VFP就是导致图15.1.6中黑边的原因,但是这是CRT显示器存在黑边的原因,现在是LCD显示器,不需要电子枪了,那么为何还会有黑边呢?这是因为RGB LCD屏幕内部是有一个IC 的,发送一行或者一帧数据给IC,IC是需要反应时间的。通过这段反应时间可以让IC识别到一行数据扫描完了,要换行了,或者一帧图像扫描完了,要开始下一帧图像显示了。因此,在LCD屏幕中继续存在HBP、HFP、VPB和VFP这四个参数的主要目的是为了锁定有效的像素数据。​

5、RGB LCD屏幕时序

上面介绍了LCD的时间参数,我们接下来看一下行显示对应的时序图,如图15.1.7所示。​

《DFZU2EG_4EV MPSoc之FPGA开发指南》第十五章  RGB LCD彩条显示实验​_液晶屏_07


图15.1.7 LCD行显示时序​

图15.1.7就是RGB LCD的行显示时序,我们来分析一下其中重要的几个参数:​

HSYNC:行同步信号,当此信号有效的时候就表示开始显示新的一行数据,查阅所使用的LCD数据手册可以知道此信号是低电平有效还是高电平有效,图15.1.7为低电平有效。​

HSPW:行同步信号宽度,也就是HSYNC信号持续时间。HSYNC信号不是一个脉冲,而是需要持续一段时间才是有效的,单位为CLK。​

HBP:行显示后沿(或后肩),单位是CLK。​

HOZVAL:行有效显示区域,即显示一行数据所需的时间,假如屏幕分辨率为1024*600,那么HOZVAL 就是1024,单位为CLK。​

HFP:行显示前沿(或前肩),单位是CLK。​

当HSYNC信号发出以后,需要等待HSPW+HBP个CLK时间才会接收到真正有效的像素数据。当显示完一行数据以后需要等待HFP个CLK时间才能发出下一个HSYNC信号,所以显示一行所需要的时间就是:HSPW + HBP + HOZVAL + HFP。​

一帧图像就是由很多个行组成的,RGB LCD的帧显示时序如图15.1.8所示:​

《DFZU2EG_4EV MPSoc之FPGA开发指南》第十五章  RGB LCD彩条显示实验​_像素点_08


图15.1.8 LCD帧显示时序​

图15.1.8就是RGB LCD的帧显示时序,我们来分析一下其中重要的几个参数:​

VSYNC:帧(场)同步信号,当此信号有效的时候就表示开始显示新的一帧数据,查阅所使用的LCD数据手册可以知道此信号是低电平有效还是高电平有效,图15.1.8为低电平有效。​

VSPW:帧同步信号宽度,也就是VSYNC信号持续时间,单位为1行的时间。​

VBP:帧显示后沿(或后肩),单位为1行的时间。​

LINE:帧有效显示区域,即显示一帧数据所需的时间,假如屏幕分辨率为1024*600,那么LINE就是600行的时间。​

VFP:帧显示前沿(或前肩),单位为1行的时间。​

显示一帧所需要的时间就是:VSPW+VBP+LINE+VFP个行时间,最终的计算公式:​

T = (VSPW+VBP+LINE+VFP) * (HSPW + HBP + HOZVAL + HFP)​

因此我们在配置一款RGB LCD屏的时候需要知道这几个参数:HSPW(行同步)、HBP(行显示后沿)、HOZVAL(行有效显示区域)、HFP(行显示前沿)、VSPW(场同步)、VBP(场显示后沿)、LINE(场有效显示区域)和VFP(场显示后沿)。​

RGB LCD液晶屏一般有两种数据同步方式,一种是行场同步模式(HV Mode),另一种是数据使能同步模式(DE Mode)。当选择行场同步模式时,LCD接口的时序与VGA接口的时序图非常相似,只是参数不同,如图 16.1.9和图 16.1.8中的行同步信号(HSYNC)和场同步信号(VSYNC)作为数据的同步信号,此时数据使能信号(DE)必须为低电平。​

当选择DE同步模式时,LCD的DE信号作为数据的有效信号,,如图 16.1.10和图 16.1.8中的DE信号所示。只有同时扫描到帧有效显示区域和行有效显示区域时,DE信号才有效(高电平)。当选择DE同步模式时,此时行场同步信号VS和HS必须为高电平。​

由于RGB LCD液晶屏一般都支持DE模式,不是所有的RGB LCD液晶屏都支持HV模式,因此本章我们采用DE同步的方式驱动LCD液晶屏。​

6、像素时钟

像素时钟就是RGB LCD的时钟信号,以ATK7016这款屏幕为例,显示一帧图像所需要的时钟数就是:​

N(CLK)= (VSPW+VBP+LINE+VFP) * (HSPW + HBP + HOZVAL + HFP)​

= (3 + 20 + 600 + 12) * (20 + 140 + 1024 + 160) = 635 * 1344 = 853440​

显示一帧图像需要853440个时钟数,那么显示60帧就是:853440 * 60 = 51206400≈51.2M,所以像素时钟就是51.2MHz。​

当然我们在为RGB LCD屏提供驱动时钟的时候,也可以不用严格按照60帧来进行计算。为了方便操作,我们可以给ATK7016模块输出一个50MHz的时钟,其刷新率是接近于60Hz的,同时也非常方便我们来编写代码。​

为了方便大家查找LCD屏的时序参数,这里整理了不同分辨率的时序参数,如表所示:​

表15.1.3 不同分辨率的LCD时序参数​

显示分辨率​

时钟(Mhz)​

行时序(像素数)​

帧时序(行数)​

行同步​

显示后沿​

显示 区域​

显示前沿​

显示 周期​

场同步​

显示后沿​

显示区域​

显示前沿​

显示 周期​

480*272​

9​

41​

2​

480​

2​

525​

10​

2​

272​

2​

286​

800*480​

33.3​

128​

88​

800​

40​

1056​

2​

33​

480​

10​

525​

1024*600​

50​

20​

140​

1024​

160​

1344​

3​

20​

600​

12​

635​

1280*800​

70​

10​

80​

1280​

70​

1440​

3​

10​

800​

10​

823​

实验任务

本节的实验任务是使用正点原子DFZU2EG/4EV MPSoC开发板上的RGB TFT-LCD接口,驱动RGB LCD液晶屏(支持目前推出的所有RGB LCD屏),并显示出彩条。​

硬件设计

DFZU2EG/4EV MPSoC开发板上RGB TFT-LCD接口部分的原理图如下图所示。​

《DFZU2EG_4EV MPSoc之FPGA开发指南》第十五章  RGB LCD彩条显示实验​_数据_09


图15.3.1 RGB TFTLCD接口原理图​

从上图中可以看到,FPGA管脚输出的颜色数据位宽为24bit,数据格式为RGB888,即数据高8位表示红色,中间8位表示绿色,低8位表示蓝色。由于这24位数据不仅仅作为输出给LCD屏的颜色数据,同时LCD_R7、LCD_G7和LCD_B7也用来获取LCD屏的ID,因此这24位颜色数据对ZYNQ开发板来说,是一个双向的引脚。​

另外,RGBLCD模块支持触摸功能,图中T_PEN、T_MISO、T_CS、IIC2_SDA和IIC2_SCL等总共五个信号是与模块上的触摸芯片相连接。由于本次实验不涉及触摸功能的实现,因此这些信号并未用到。​

需要说明的是,LCD液晶屏有一个复位信号(LCD_RST),当LCD_RST为低电平时,可对LCD屏进行复位。​

本实验中,各端口信号的管脚分配如下表所示:​

表15.3.1彩条实验管脚分配​

信号名​

方向​

管脚​

端口说明​

电平标准​

sys_clk_p​

input​

AE5​

系统差分输入时钟​

DIFF_HSTL_I_12​

sys_clk_n​

input​

AF5​

系统差分输入时钟​

DIFF_HSTL_I_12​

sys_rst_n​

input​

AH11​

系统复位,低有效​

LVCMOS33​

lcd_rgb[0]​

inout​

W14​

RGB LCD蓝色(最低位)​

LVCMOS33​

lcd_rgb[1]​

inout​

Y14​

RGB LCD蓝色​

LVCMOS33​

lcd_rgb[2]​

inout​

W13​

RGB LCD蓝色​

LVCMOS33​

lcd_rgb[3]​

inout​

Y13​

RGB LCD蓝色​

LVCMOS33​

lcd_rgb[4]​

inout​

W12​

RGB LCD蓝色​

LVCMOS33​

lcd_rgb[5]​

inout​

Y12​

RGB LCD蓝色​

LVCMOS33​

lcd_rgb[6]​

inout​

W11​

RGB LCD蓝色​

LVCMOS33​

lcd_rgb[7]​

inout​

AA12​

RGB LCD蓝色(最高位)​

LVCMOS33​

lcd_rgb[8]​

inout​

AC14​

RGB LCD绿色(最低位)​

LVCMOS33​

lcd_rgb[9]​

inout​

AD15​

RGB LCD绿色​

LVCMOS33​

lcd_rgb[10]​

inout​

AC13​

RGB LCD绿色​

LVCMOS33​

lcd_rgb[11]​

inout​

AD14​

RGB LCD绿色​

LVCMOS33​

lcd_rgb[12]​

inout​

AE15​

RGB LCD绿色​

LVCMOS33​

lcd_rgb[13]​

inout​

AA13​

RGB LCD绿色​

LVCMOS33​

lcd_rgb[14]​

inout​

AE14​

RGB LCD绿色​

LVCMOS33​

lcd_rgb[15]​

inout​

AB13​

RGB LCD绿色(最高位)​

LVCMOS33​

lcd_rgb[16]​

inout​

AG14​

RGB LCD红色(最低位)​

LVCMOS33​

lcd_rgb[17]​

inout​

AB15​

RGB LCD红色​

LVCMOS33​

lcd_rgb[18]​

inout​

AH14​

RGB LCD红色​

LVCMOS33​

lcd_rgb[19]​

inout​

AB14​

RGB LCD红色​

LVCMOS33​

lcd_rgb[20]​

inout​

AG13​

RGB LCD红色​

LVCMOS33​

lcd_rgb[21]​

inout​

AE13​

RGB LCD红色​

LVCMOS33​

lcd_rgb[22]​

inout​

AH13​

RGB LCD红色​

LVCMOS33​

lcd_rgb[23]​

inout​

AF13​

RGB LCD红色(最高位)​

LVCMOS33​

lcd_hs​

output​

J11​

RGB LCD行同步​

LVCMOS33​

lcd_vs​

output​

K12​

RGB LCD场同步​

LVCMOS33​

lcd_de​

output​

J10​

RGB LCD数据使能​

LVCMOS33​

lcd_bl​

output​

J12​

RGB LCD背光控制​

LVCMOS33​

lcd_clk​

output​

K13​

RGB LCD像素时钟​

LVCMOS33​

lcd_rst​

output​

F10​

RGB LCD复位信号​

LVCMOS33​

对应的XDC约束语句如下所示:​

#IO管脚约束​
#时钟周期约束​
create_clock -name sys_clk_p -period 10.000 [get_ports sys_clk_p]​
#时钟​
set_property IOSTANDARD DIFF_HSTL_I_12 [get_ports sys_clk_p]​
set_property IOSTANDARD DIFF_HSTL_I_12 [get_ports sys_clk_n]​
set_property PACKAGE_PIN AE5 [get_ports sys_clk_p]​
set_property PACKAGE_PIN AF5 [get_ports sys_clk_n]​
#复位​
set_property -dict {PACKAGE_PIN AH11 IOSTANDARD LVCMOS33} [get_ports sys_rst_n]​
#LCD接口​
set_property -dict {PACKAGE_PIN W14 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[0]}]​
set_property -dict {PACKAGE_PIN Y14 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[1]}]​
set_property -dict {PACKAGE_PIN W13 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[2]}]​
set_property -dict {PACKAGE_PIN Y13 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[3]}]​
set_property -dict {PACKAGE_PIN W12 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[4]}]​
set_property -dict {PACKAGE_PIN Y12 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[5]}]​
set_property -dict {PACKAGE_PIN W11 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[6]}]​
set_property -dict {PACKAGE_PIN AA12 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[7]}]​
set_property -dict {PACKAGE_PIN AC14 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[8]}]​
set_property -dict {PACKAGE_PIN AD15 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[9]}]​
set_property -dict {PACKAGE_PIN AC13 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[10]}]​
set_property -dict {PACKAGE_PIN AD14 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[11]}]​
set_property -dict {PACKAGE_PIN AE15 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[12]}]​
set_property -dict {PACKAGE_PIN AA13 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[13]}]​
set_property -dict {PACKAGE_PIN AE14 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[14]}]​
set_property -dict {PACKAGE_PIN AB13 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[15]}]​
set_property -dict {PACKAGE_PIN AG14 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[16]}]​
set_property -dict {PACKAGE_PIN AB15 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[17]}]​
set_property -dict {PACKAGE_PIN AH14 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[18]}]​
set_property -dict {PACKAGE_PIN AB14 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[19]}]​
set_property -dict {PACKAGE_PIN AG13 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[20]}]​
set_property -dict {PACKAGE_PIN AE13 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[21]}]​
set_property -dict {PACKAGE_PIN AH13 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[22]}]​
set_property -dict {PACKAGE_PIN AF13 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[23]}]​

set_property -dict {PACKAGE_PIN J11 IOSTANDARD LVCMOS33} [get_ports lcd_hs]​
set_property -dict {PACKAGE_PIN K12 IOSTANDARD LVCMOS33} [get_ports lcd_vs]​
set_property -dict {PACKAGE_PIN J10 IOSTANDARD LVCMOS33} [get_ports lcd_de]​
set_property -dict {PACKAGE_PIN J12 IOSTANDARD LVCMOS33} [get_ports lcd_bl]​
set_property -dict {PACKAGE_PIN K13 IOSTANDARD LVCMOS33} [get_ports lcd_clk]​
set_property -dict {PACKAGE_PIN F10 IOSTANDARD LVCMOS33} [get_ports lcd_rst]

程序设计

RGB TFT-LCD输入时序包含三个要素:像素时钟、同步信号、以及图像数据,由此我们可以大致规划出系统结构如下图所示。其中,读取ID模块用于获取LCD屏的ID;由于不同分辨率的屏幕需要不同的驱动时钟,因此时钟分频模块根据LCD ID来输出不同频率的像素时钟;LCD显示模块负责产生液晶屏上显示的数据,即彩条数据;LCD驱动模块根据LCD屏的ID,输出不同参数的时序,来驱动LCD屏,并将输入的彩条数据显示到LCD屏上。​

《DFZU2EG_4EV MPSoc之FPGA开发指南》第十五章  RGB LCD彩条显示实验​_像素点_10


图15.4.1 RGB TFT-LCD彩条显示系统框图​

由系统框图可知,FPGA部分包括五个模块,顶层模块(lcd_rgb_colorbar)、读取ID模块(rd_id)、时钟分频模块(clk_div)、LCD显示模块(lcd_display)以及LCD驱动模块(lcd_driver)。其中在顶层模块中完成对其余模块的例化。​

各模块端口及信号连接如下图所示:​

《DFZU2EG_4EV MPSoc之FPGA开发指南》第十五章  RGB LCD彩条显示实验​_数据_11


图15.4.2 顶层模块原理图​

读取ID模块(rd_id)在上电时将RGB双向数据总线设置为输入,来读取LCD屏的ID;时钟分频模块(clk_div)根据读取的ID来配置LCD的像素时钟;LCD驱动模块(lcd_driver)在像素时钟的驱动下输出数据使能信号用于数据同步,同时还输出像素点的纵横坐标,供LCD显示模块(lcd_display)调用,以绘制彩条图案。​

顶层模块lcd_rgb_colorbar的代码如下:​

1 module lcd_rgb_colorbar(​
2 input sys_clk_p , //系统差分输入时钟​
3 input sys_clk_n , //系统差分输入时钟​
4 input sys_rst_n , //系统复位​
5 ​
6 //RGB LCD接口​
7 output lcd_de, //LCD 数据使能信号​
8 output lcd_hs, //LCD 行同步信号​
9 output lcd_vs, //LCD 场同步信号​
10 output lcd_bl, //LCD 背光控制信号​
11 output lcd_clk, //LCD 像素时钟​
12 output lcd_rst, //LCD 复位​
13 inout [23:0] lcd_rgb //LCD RGB888颜色数据​
14 ); ​
15 ​
16 //wire define ​
17 wire [15:0] lcd_id ; //LCD屏ID​
18 wire lcd_pclk ; //LCD像素时钟​
19 wire lcd_clk_180 ; //LCD像素时钟​
20 ​
21 wire [10:0] pixel_xpos ; //当前像素点横坐标​
22 wire [10:0] pixel_ypos ; //当前像素点纵坐标​
23 wire [10:0] h_disp ; //LCD屏水平分辨率​
24 wire [10:0] v_disp ; //LCD屏垂直分辨率​
25 wire [23:0] pixel_data ; //像素数据​
26 wire [23:0] lcd_rgb_o ; //输出的像素数据​
27 wire [23:0] lcd_rgb_i ; //输入的像素数据​
28 ​
29 //*****************************************************​
30 //** main code​
31 //*****************************************************​
32 //识别到ID为1018即10寸屏幕时,LCD 像素时钟取反​
33 assign lcd_clk = (lcd_id == 16'h1018) ? ~lcd_clk_180 : lcd_clk_180;​
34 ​
35 //转换差分信号​
36 IBUFDS diff_clock​
37 (​
38 .I (sys_clk_p), //系统差分输入时钟​
39 .IB(sys_clk_n), //系统差分输入时钟​
40 .O (sys_clk) //输出系统时钟​
41 ); ​
42 ​
43 //像素数据方向切换​
44 assign lcd_rgb = lcd_de ? lcd_rgb_o : {24{1'bz}};​
45 assign lcd_rgb_i = lcd_rgb;​
46 ​
47 //读LCD ID模块​
48 rd_id u_rd_id(​
49 .clk (sys_clk ),​
50 .rst_n (sys_rst_n),​
51 .lcd_rgb (lcd_rgb_i),​
52 .lcd_id (lcd_id )​
53 ); ​
54 ​
55 //时钟分频模块 ​
56 clk_div u_clk_div(​
57 .clk (sys_clk ),​
58 .rst_n (sys_rst_n),​
59 .lcd_id (lcd_id ),​
60 .lcd_pclk (lcd_pclk )​
61 ); ​
62 ​
63 //LCD显示模块 ​
64 lcd_display u_lcd_display(​
65 .lcd_pclk (lcd_pclk ),​
66 .rst_n (sys_rst_n ),​
67 .pixel_xpos (pixel_xpos),​
68 .pixel_ypos (pixel_ypos),​
69 .h_disp (h_disp ),​
70 .v_disp (v_disp ),​
71 .pixel_data (pixel_data)​
72 ); ​
73 ​
74 //LCD驱动模块​
75 lcd_driver u_lcd_driver(​
76 .lcd_pclk (lcd_pclk ),​
77 .rst_n (sys_rst_n ),​
78 .lcd_id (lcd_id ),​
79 .pixel_data (pixel_data ),​
80 .pixel_xpos (pixel_xpos ),​
81 .pixel_ypos (pixel_ypos ),​
82 .h_disp (h_disp ),​
83 .v_disp (v_disp ),​
84 ​
85 .lcd_de (lcd_de ),​
86 .lcd_hs (lcd_hs ),​
87 .lcd_vs (lcd_vs ),​
88 .lcd_bl (lcd_bl ),​
89 .lcd_clk (lcd_clk_180),​
90 .lcd_rst (lcd_rst ),​
91 .lcd_rgb (lcd_rgb_o )​
92 );​
93 ​
94 endmodule

顶层模块主要完成对其他模块的例化。这里需要重点注意第44行代码,由于lcd_rgb是24位的双向引脚,所以这里对双向引脚的方向做一个切换。当lcd_de信号为高电平时,此时输出的像素数据有效,将lcd_rgb的引脚方向切换成输出,并将LCD驱动模块输出的lcd_rgb_o(像素数据)连接至lcd_rgb引脚;当lcd_de信号为低电平时,此时输出的像素数据无效,将lcd_rgb的引脚方向切换成输入。代码中将高阻状态“Z”赋值给lcd_rgb的引脚,表示此时lcd_rgb的引脚电平由外围电路决定,此时可以读取lcd_rgb的引脚电平,从而获取到LCD屏的ID。​

在代码第33行中对10寸屏的驱动时钟进行了取反,这里给大家解释一下为什么?因为10寸屏采用的是IPS面板,IPS面板相较于普通的液晶屏它改变了液晶分子颗粒排列方式,由原来的垂直排列变为水平排列。正是因为这种水平转换技术使得IPS屏幕具有更快的响应速度(液晶分子偏转速度)和更细腻的图像显示,并且它清晰流畅的视觉效果还可以降低对眼睛的刺激。但是由于响应速度的加快使得10寸屏对时序要求更高,这里对屏幕驱动时钟取反相当于时钟和数据相位相差180度,可以让10寸屏的时序更好,而其他尺寸屏幕响应的速度没那么快不需要对时钟进行取反,取反反而影响显示效果。​

读取ID模块的代码如下:​

1 module rd_id(​
2 input clk , //时钟​
3 input rst_n , //复位,低电平有效​
4 input [23:0] lcd_rgb, //RGB LCD像素数据,用于读取ID​
5 output reg [15:0] lcd_id //LCD屏ID​
6 );​
7 ​
8 //reg define​
9 reg rd_flag; //读ID标志​
10 ​
11 //*****************************************************​
12 //** main code​
13 //*****************************************************​
14 ​
15 //获取LCD ID M2:B7 M1:G7 M0:R7​
16 always @(posedge clk or negedge rst_n) begin​
17 if(!rst_n) begin​
18 rd_flag <= 1'b0;​
19 lcd_id <= 16'd0;​
20 end ​
21 else begin​
22 if(rd_flag == 1'b0) begin​
23 rd_flag <= 1'b1; ​
24 case({lcd_rgb[7],lcd_rgb[15],lcd_rgb[23]})​
25 3'b000 : lcd_id <= 16'h4342; //4.3' RGB LCD RES:480x272​
26 3'b001 : lcd_id <= 16'h7084; //7' RGB LCD RES:800x480​
27 3'b010 : lcd_id <= 16'h7016; //7' RGB LCD RES:1024x600​
28 3'b100 : lcd_id <= 16'h4384; //4.3' RGB LCD RES:800x480​
29 3'b101 : lcd_id <= 16'h1018; //10' RGB LCD RES:1280x800​
30 default : lcd_id <= 16'd0;​
31 endcase ​
32 end​
33 end ​
34 end​
35 ​
36 endmodule

读取ID模块根据输入的lcd_rgb值来寄存LCD屏的ID。lcd_rgb[7](B7)、lcd_rgb[15](G7)和lcd_rgb[23](R7)分别对应M2、M1和M0。尽管在顶层模块中,双向引脚lcd_rgb会根据lcd_de信号的高低电平来频繁的切换方向,但本模块实际上只在上电后获取了一次ID,通过rd_flag作为标志。当rd_flag等于0时,获取一次ID,并将rd_flag赋值为1;而当rd_flag等于1时,不再获取LCD屏的ID。​

除此之外,为了方便将LCD的ID和分辨率对应起来,这里对M2、M1和M0的值做了一个译码,如3’b000译码成16’h4342,表示当前连接的是4.3寸屏,分辨率为480*272。其它ID的译码请参考注释。​

分频模块的代码如下:​

1 module clk_div(​
2 input clk, //50Mhz​
3 input rst_n,​
4 input [15:0] lcd_id,​
5 output reg lcd_pclk​
6 );​
7 ​
8 reg clk_50m;​
9 reg clk_25m;​
10 reg clk_12_5m;​
11 reg div_4_cnt;​
12 reg [1:0] div_8_cnt;​
13 ​
14 //时钟2分频 输出50MHz时钟 ​
15 always @(posedge clk or negedge rst_n) begin​
16 if(!rst_n)​
17 clk_50m <= 1'b0;​
18 else ​
19 clk_50m <= ~clk_50m;​
20 end​
21 ​
22 //时钟4分频 输出25MHz时钟 ​
23 always @(posedge clk or negedge rst_n) begin​
24 if(!rst_n) begin​
25 div_4_cnt <= 1'b0;​
26 clk_25m <= 1'b0;​
27 end ​
28 else begin​
29 div_4_cnt <= div_4_cnt + 1'b1;​
30 if(div_4_cnt == 1'b1)​
31 clk_25m <= ~clk_25m;​
32 end ​
33 end​
34 ​
35 //时钟8分频 输出12.5MHz时钟 ​
36 always @(posedge clk or negedge rst_n) begin​
37 if(!rst_n) begin​
38 div_8_cnt <= 2'b0;​
39 clk_12_5m <= 1'b0;​
40 end ​
41 else begin​
42 div_8_cnt <= div_8_cnt + 2'b01;​
43 if(div_8_cnt == 2'b11)​
44 clk_12_5m <= ~clk_12_5m;​
45 end ​
46 end​
47 ​
48 always @(*) begin​
49 case(lcd_id)​
50 16'h4342 : lcd_pclk = clk_12_5m;​
51 16'h7084 : lcd_pclk = clk_25m; ​
52 16'h7016 : lcd_pclk = clk_50m;​
53 16'h4384 : lcd_pclk = clk_25m;​
54 16'h1018 : lcd_pclk = clk_50m;​
55 default : lcd_pclk = 1'b0;​
56 endcase ​
57 end​
58 ​
59 endmodule

分频模块根据输入的LCD ID对100Mhz时钟进行分频。由于不同分辨率的LCD屏需要的像素时钟频率不一样,因此分频模块根据输入的LCD ID,来输出不同频率的像素时钟lcd_pclk。需要说明的是,我们在本章简介部分向大家列出了一张表,表格里记录了不同分辨率的屏幕所需的像素时钟频率,为了方便编写分频的代码,我们这里没有严格按照表格里所要求的时钟频率进行输出,而是输出接近于表格所要求的时钟频率。例如10.1寸屏,分辨率1280*800,如果刷新率为60Hz的话,需要输出70Mhz的像素时钟,这个时钟频率是无法通过编写代码的方式来得到,而是必须使例化时钟模块MMCM/PLL IP核来得到。因此,对于分辨率为1280*800的10.1寸屏幕来说,我们输出的是50Mhz的像素时钟,当然大家使用的是10.1寸屏幕,也可以通过例化时钟模块的方式,来输出一个70Mhz的像素时钟。​

分频模块通过三个always语句,分别进行2分频、4分频和8分频,得到一个50Mhz的时钟、一个25Mhz的时钟和一个12.5Mhz的时钟,如代码中第14行至第46行代码所示。下面我们介绍下如何对输入的时钟进行四分频,也就是100Mhz的时钟四分频后,得到一个25Mhz的时钟,其实只需要分频后时钟的周期时原时钟的四倍即可,四分频的波形图如下图所示:​

《DFZU2EG_4EV MPSoc之FPGA开发指南》第十五章  RGB LCD彩条显示实验​_数据_12


图15.4.3 时钟四分频​

上图中的div_4_cnt用于对系统时钟进行计数,四分频计数器只需要一位位宽,即0和1之间跳变。clk_25m高电平和低电平分别占用了两个时钟周期,共占用四个时钟周期,sys_clk的时钟频率为100Mhz,周期为10ns,因此clk_25m的时钟周期为40ns,时钟频率为25Mhz。​

在代码的第48行至第57行,通过组合逻辑根据LCD屏的ID选择输出不同频率的像素时钟。​

LCD驱动模块的代码如下:​

1 module lcd_driver(​
2 input lcd_pclk, //时钟​
3 input rst_n, //复位,低电平有效​
4 input [15:0] lcd_id, //LCD屏ID​
5 input [23:0] pixel_data, //像素数据​
6 output [10:0] pixel_xpos, //当前像素点横坐标​
7 output [10:0] pixel_ypos, //当前像素点纵坐标 ​
8 output reg [10:0] h_disp, //LCD屏水平分辨率​
9 output reg [10:0] v_disp, //LCD屏垂直分辨率 ​
10 //RGB LCD接口​
11 output lcd_de, //LCD 数据使能信号​
12 output lcd_hs, //LCD 行同步信号​
13 output lcd_vs, //LCD 场同步信号​
14 output lcd_bl, //LCD 背光控制信号​
15 output lcd_clk, //LCD 像素时钟​
16 output lcd_rst, //LCD复位​
17 output [23:0] lcd_rgb //LCD RGB888颜色数据​
18 );​
19 ​
20 //parameter define ​
21 // 4.3' 480*272​
22 parameter H_SYNC_4342 = 11'd41; //行同步​
23 parameter H_BACK_4342 = 11'd2; //行显示后沿​
24 parameter H_DISP_4342 = 11'd480; //行有效数据​
25 parameter H_FRONT_4342 = 11'd2; //行显示前沿​
26 parameter H_TOTAL_4342 = 11'd525; //行扫描周期​
27 ​
28 parameter V_SYNC_4342 = 11'd10; //场同步​
29 parameter V_BACK_4342 = 11'd2; //场显示后沿​
30 parameter V_DISP_4342 = 11'd272; //场有效数据​
31 parameter V_FRONT_4342 = 11'd2; //场显示前沿​
32 parameter V_TOTAL_4342 = 11'd286; //场扫描周期​
33 ​
34 // 7' 800*480 ​
35 parameter H_SYNC_7084 = 11'd128; //行同步​
36 parameter H_BACK_7084 = 11'd88; //行显示后沿​
37 parameter H_DISP_7084 = 11'd800; //行有效数据​
38 parameter H_FRONT_7084 = 11'd40; //行显示前沿​
39 parameter H_TOTAL_7084 = 11'd1056; //行扫描周期​
40 ​
41 parameter V_SYNC_7084 = 11'd2; //场同步​
42 parameter V_BACK_7084 = 11'd33; //场显示后沿​
43 parameter V_DISP_7084 = 11'd480; //场有效数据​
44 parameter V_FRONT_7084 = 11'd10; //场显示前沿​
45 parameter V_TOTAL_7084 = 11'd525; //场扫描周期 ​
46 ​
47 // 7' 1024*600 ​
48 parameter H_SYNC_7016 = 11'd20; //行同步​
49 parameter H_BACK_7016 = 11'd140; //行显示后沿​
50 parameter H_DISP_7016 = 11'd1024; //行有效数据​
51 parameter H_FRONT_7016 = 11'd160; //行显示前沿​
52 parameter H_TOTAL_7016 = 11'd1344; //行扫描周期​
53 ​
54 parameter V_SYNC_7016 = 11'd3; //场同步​
55 parameter V_BACK_7016 = 11'd20; //场显示后沿​
56 parameter V_DISP_7016 = 11'd600; //场有效数据​
57 parameter V_FRONT_7016 = 11'd12; //场显示前沿​
58 parameter V_TOTAL_7016 = 11'd635; //场扫描周期​
59 ​
60 // 10.1' 1280*800 ​
61 parameter H_SYNC_1018 = 11'd10; //行同步​
62 parameter H_BACK_1018 = 11'd80; //行显示后沿​
63 parameter H_DISP_1018 = 11'd1280; //行有效数据​
64 parameter H_FRONT_1018 = 11'd70; //行显示前沿​
65 parameter H_TOTAL_1018 = 11'd1440; //行扫描周期​
66 ​
67 parameter V_SYNC_1018 = 11'd3; //场同步​
68 parameter V_BACK_1018 = 11'd10; //场显示后沿​
69 parameter V_DISP_1018 = 11'd800; //场有效数据​
70 parameter V_FRONT_1018 = 11'd10; //场显示前沿​
71 parameter V_TOTAL_1018 = 11'd823; //场扫描周期​
72 ​
73 // 4.3' 800*480 ​
74 parameter H_SYNC_4384 = 11'd128; //行同步​
75 parameter H_BACK_4384 = 11'd88; //行显示后沿​
76 parameter H_DISP_4384 = 11'd800; //行有效数据​
77 parameter H_FRONT_4384 = 11'd40; //行显示前沿​
78 parameter H_TOTAL_4384 = 11'd1056; //行扫描周期​
79 ​
80 parameter V_SYNC_4384 = 11'd2; //场同步​
81 parameter V_BACK_4384 = 11'd33; //场显示后沿​
82 parameter V_DISP_4384 = 11'd480; //场有效数据​
83 parameter V_FRONT_4384 = 11'd10; //场显示前沿​
84 parameter V_TOTAL_4384 = 11'd525; //场扫描周期 ​
代码较长,省略部分源代码……​
104 //RGB LCD 采用DE模式时,行场同步信号需要拉高​
105 assign lcd_hs = 1'b1; //LCD行同步信号​
106 assign lcd_vs = 1'b1; //LCD场同步信号​
107 ​
108 assign lcd_bl = 1'b1; //LCD背光控制信号 ​
109 assign lcd_rst= 1'b1; //LCD 复位​
110 assign lcd_clk = lcd_pclk; //LCD像素时钟​
111 assign lcd_de = lcd_en; //LCD数据有效信号​
112 ​
113 //使能RGB888数据输出​
114 assign lcd_en = ((h_cnt >= h_sync + h_back) ​
115 && (h_cnt < h_sync + h_back + h_disp)​
116 && (v_cnt >= v_sync + v_back) ​
117 && (v_cnt < v_sync + v_back + v_disp)) ? 1'b1 : 1'b0;​
118 ​
119 //请求像素点颜色数据输入 ​
120 assign data_req = ((h_cnt >= h_sync + h_back - 1'b1) ​
121 && (h_cnt < h_sync + h_back + h_disp - 1'b1)​
122 && (v_cnt >= v_sync + v_back) ​
123 && (v_cnt < v_sync + v_back + v_disp)) ? 1'b1 : 1'b0;​
124 ​
125 //像素点坐标 ​
126 assign pixel_xpos = data_req ? (h_cnt - (h_sync + h_back - 1'b1)) : 11'd0;​
127 assign pixel_ypos = data_req ? (v_cnt - (v_sync + v_back - 1'b1)) : 11'd0;​
128 ​
129 //RGB888数据输出​
130 assign lcd_rgb = lcd_en ? pixel_data : 24'd0;​
131 ​
132 //行场时序参数​
133 always @(*) begin​
134 case(lcd_id)​
135 16'h4342 : begin​
136 h_sync = H_SYNC_4342; ​
137 h_back = H_BACK_4342; ​
138 h_disp = H_DISP_4342; ​
139 h_total = H_TOTAL_4342;​
140 v_sync = V_SYNC_4342; ​
141 v_back = V_BACK_4342; ​
142 v_disp = V_DISP_4342; ​
143 v_total = V_TOTAL_4342; ​
144 end​
145 16'h7084 : begin​
146 h_sync = H_SYNC_7084; ​
147 h_back = H_BACK_7084; ​
148 h_disp = H_DISP_7084; ​
149 h_total = H_TOTAL_7084;​
150 v_sync = V_SYNC_7084; ​
151 v_back = V_BACK_7084; ​
152 v_disp = V_DISP_7084; ​
153 v_total = V_TOTAL_7084; ​
154 end​
155 16'h7016 : begin​
156 h_sync = H_SYNC_7016; ​
157 h_back = H_BACK_7016; ​
158 h_disp = H_DISP_7016; ​
159 h_total = H_TOTAL_7016;​
160 v_sync = V_SYNC_7016; ​
161 v_back = V_BACK_7016; ​
162 v_disp = V_DISP_7016; ​
163 v_total = V_TOTAL_7016; ​
164 end​
165 16'h4384 : begin​
166 h_sync = H_SYNC_4384; ​
167 h_back = H_BACK_4384; ​
168 h_disp = H_DISP_4384; ​
169 h_total = H_TOTAL_4384;​
170 v_sync = V_SYNC_4384; ​
171 v_back = V_BACK_4384; ​
172 v_disp = V_DISP_4384; ​
173 v_total = V_TOTAL_4384; ​
174 end ​
175 16'h1018 : begin​
176 h_sync = H_SYNC_1018; ​
177 h_back = H_BACK_1018; ​
178 h_disp = H_DISP_1018; ​
179 h_total = H_TOTAL_1018;​
180 v_sync = V_SYNC_1018; ​
181 v_back = V_BACK_1018; ​
182 v_disp = V_DISP_1018; ​
183 v_total = V_TOTAL_1018; ​
184 end​
185 default : begin​
186 h_sync = H_SYNC_4342; ​
187 h_back = H_BACK_4342; ​
188 h_disp = H_DISP_4342; ​
189 h_total = H_TOTAL_4342;​
190 v_sync = V_SYNC_4342; ​
191 v_back = V_BACK_4342; ​
192 v_disp = V_DISP_4342; ​
193 v_total = V_TOTAL_4342; ​
194 end​
195 endcase​
196 end​
197 ​
198 //行计数器对像素时钟计数​
199 always@ (posedge lcd_pclk or negedge rst_n) begin​
200 if(!rst_n) ​
201 h_cnt <= 11'd0;​
202 else begin​
203 if(h_cnt == h_total - 1'b1)​
204 h_cnt <= 11'd0;​
205 else​
206 h_cnt <= h_cnt + 1'b1; ​
207 end​
208 end​
209 ​
210 //场计数器对行计数​
211 always@ (posedge lcd_pclk or negedge rst_n) begin​
212 if(!rst_n) ​
213 v_cnt <= 11'd0;​
214 else begin​
215 if(h_cnt == h_total - 1'b1) begin​
216 if(v_cnt == v_total - 1'b1)​
217 v_cnt <= 11'd0;​
218 else​
219 v_cnt <= v_cnt + 1'b1; ​
220 end​
221 end ​
222 end​
223 ​
224 endmodule

由本章简介部分可知,在DE模式下,液晶显示屏的同步信号DE对应的是帧和行同时有效的区域段。程序第21行至第84行代码,根据不同分辨率的屏幕做了不同参数的定义,参数的值参考了本章的表。程序第132至196行则根据LCD屏的ID选择不同的时序参数。​

程序第105至111行是LCD驱动模块输出的液晶屏控制信号。其中lcd_bl为液晶屏背光控制端口,可以利用该端口输出一个频率在200Hz~1kHz范围之内的PWM(脉冲宽度调制)信号,通过调整PWM信号的占空比来调节液晶屏的显示亮度。这里我们对lcd_bl作简单处理,将其直接赋值为1,此时液晶屏亮度最高。分频模块输出的lcd_pclk直接赋值给LCD屏的lcd_clk(像素时钟)引脚,为RGB LCD屏提供驱动时钟。另外由于我们采用DE同步模式驱动RGB LCD屏,输出给LCD的数据使能信号lcd_de在图像数据有效时拉高,因此可以将模块内部的lcd_en信号直接赋值给lcd_de。另外在DE模式下,需要将输出给LCD的行场同步信号lcd_hs、lcd_vs拉高。​

程序第198至208行通过行计数器h_cnt对像素时钟计数,计满一个行扫描周期后清零并重新开始计数。程序第210至222行通过场计数器v_cnt对行进行计数,即扫描完一行后v_cnt加1,计满一个场扫描周期后清零并重新开始计数。​

将行场计数器的值与LCD时序中的参数作比较,我们就可以判断DE信号何时有效,以及何时输出RGB888格式的图像数据(第113~117行和第130行)。程序第119至127行输出当前像素点的横纵坐标值,由于坐标输出后下一个时钟周期才能接收到像素点的颜色数据,因此数据请求信号data_req比数据输出使能信号lcd_en提前一个时钟周期。​

LCD显示模块的代码如下:​

1 module lcd_display(​
2 input lcd_pclk, //时钟​
3 input rst_n, //复位,低电平有效​
4 input [10:0] pixel_xpos, //当前像素点横坐标​
5 input [10:0] pixel_ypos, //当前像素点纵坐标 ​
6 input [10:0] h_disp, //LCD屏水平分辨率​
7 input [10:0] v_disp, //LCD屏垂直分辨率 ​
8 output reg [23:0] pixel_data //像素数据​
9 );​
10 ​
11 //parameter define ​
12 parameter WHITE = 24'hFFFFFF; //白色​
13 parameter BLACK = 24'h000000; //黑色​
14 parameter RED = 24'hFF0000; //红色​
15 parameter GREEN = 24'h00FF00; //绿色​
16 parameter BLUE = 24'h0000FF; //蓝色​
17 ​
18 //根据当前像素点坐标指定当前像素点颜色数据,在屏幕上显示彩条​
19 always @(posedge lcd_pclk or negedge rst_n) begin​
20 if(!rst_n)​
21 pixel_data <= BLACK;​
22 else begin​
23 if((pixel_xpos >= 11'd0) && (pixel_xpos < h_disp/5*1))​
24 pixel_data <= WHITE;​
25 else if((pixel_xpos >= h_disp/5*1) && (pixel_xpos < h_disp/5*2)) ​
26 pixel_data <= BLACK;​
27 else if((pixel_xpos >= h_disp/5*2) && (pixel_xpos < h_disp/5*3)) ​
28 pixel_data <= RED; ​
29 else if((pixel_xpos >= h_disp/5*3) && (pixel_xpos < h_disp/5*4)) ​
30 pixel_data <= GREEN; ​
31 else ​
32 pixel_data <= BLUE; ​
33 end ​
34 end​
35 ​
36 endmodule

LCD显示模块将屏幕显示区域按照横坐标划分为五列等宽的区域,通过判断像素点的横坐标所在的区域,给像素点赋以不同的颜色值,从而实现彩条显示。​

下图为RGB TFT-LCD彩条程序显示一行图像时仿真抓取的波形图,图中包含了一个完整的行扫描周期,其中的有效图像区域被划分为五个不同的区域,不同区域的像素点颜色各不相同。​

《DFZU2EG_4EV MPSoc之FPGA开发指南》第十五章  RGB LCD彩条显示实验​_液晶屏_13


图15.4.4 仿真波形图​

下载验证

首先将FPC排线一端与RGB LCD模块上的RGB接口连接,另一端与DFZU2EG/4EV MPSoC开发板上的RGB TFTLCD接口连接。与RGB LCD模块连接时,先掀开FPC连接器上的黑色翻盖,将FPC排线蓝色面朝上插入连接器,最后将黑色翻盖压下以固定FPC排线,如图15.5.1所示。​

《DFZU2EG_4EV MPSoc之FPGA开发指南》第十五章  RGB LCD彩条显示实验​_数据_14


图15.5.1 正点原子RGBLCD模块FPC连接器​

与DFZU2EG/4EV MPSoC开发板上的RGB TFTLCD接口连接时,先掀起开发板上的棕色的翻盖到垂直开发板方向,将FPC排线蓝色面朝棕色翻盖垂直插入连接器,最后将棕色的翻盖下按至水平方向,如图15.5.2所示。​

《DFZU2EG_4EV MPSoc之FPGA开发指南》第十五章  RGB LCD彩条显示实验​_像素点_15


图15.5.2 DFZU2EG/4EV MPSoC开发板连接RGB LCD液晶屏​

最后将下载器一端连电脑,另一端与开发板上的JTAG端口连接,最后拨动开关按键给开发板上电。​

接下来我们下载程序,验证RGB TFT-LCD彩条显示功能。下载完成后观察RGB LCD模块显示的图案如下图所示,说明RGB TFT-LCD彩条显示程序下载验证成功。​

《DFZU2EG_4EV MPSoc之FPGA开发指南》第十五章  RGB LCD彩条显示实验​_数据_16


图15.5.3 RGB TFT-LCD彩条显示​


标签:MPSoc,FPGA,DFZU2EG,LCD,lcd,rgb,RGB,LVCMOS33,时钟
From: https://blog.51cto.com/u_15046463/5927290

相关文章

  • 高云FPGA系列教程(1):FPGA和ARM开发环境搭建
    文章目录​​@[toc]​​​​1.获取安装包​​​​2.申请License​​​​3.安装高云FPGA开发环境​​​​4.安装高云MCU开发环境​​​​5.替换TangNano4K专用下载软件......
  • Linux下学习FPGA
    声明(叠甲):鄙人水平有限,本文章仅供参考。1.环境推荐使用Ubuntu20.04这是我使用多个版本中最好用的一个,相关安装教程可以自行上网搜索这不再赘述,但要补充的一点的是......
  • 《DFZU2EG_4EV MPSoc之FPGA开发指南》第十一章 IP核之MMCM/PLL实验​
    IP核之MMCM/PLL实验​PLL的英文全称是PhaseLockedLoop,即锁相环,是一种反馈控制电路。PLL对时钟网络进行系统级的时钟管理和偏移控制,具有时钟倍频、分频、相位偏移和可编程......
  • 《DFZU2EG_4EV MPSoc之FPGA开发指南》第十二章 IP核之RAM实验
    IP核之RAM实验RAM的英文全称是RandomAccessMemory,即随机存取存储器,它可以随时把数据写入任一指定地址的存储单元,也可以随时从任一指定地址中读出数据,其读写速度是由时钟频......
  • FPGA时序入门(新手必看)
    1.FPGA时序的基本概念FPGA器件的需求取决于系统和上下游(upstreamanddownstrem)设备。我们的设计需要和其他的devices进行数据的交互,其他的devices可能是FPGA外部的芯片,可......
  • 明德扬专业定制FPGA开发板
    *产品定制提供软硬件定制服务:FPGA板卡定制;核心板模块定制;FMC等子板模块定制;FPGA全栈设计服务:FPGA系统设计从高速硬件或HDL固件,从技术参数和实现到原型和量产;信号测量......
  • Xilinx FPGA的4G通信网数据分析系统的设计
    XilinxFPGA的4G通信网数据分析系统的设计https://wenku.baidu.com/view/8200e4106bd97f192279e910.html?_wkts_=1670372707464&bdQuery=Xilinx4g+lte......
  • 【杂记】04:FPGA
    【如何才算学会了FPGA?】https://www.bilibili.com/video/BV1KP411M7CU如何才算是学会了?独立、不参考书本代码的情况下,完成所有实例,才算是入门FPGA。学FPGA需要有电路基础,模......
  • 基于Xilinx FPGA的以太网接口的链接状态获取方法
    链接状态:pg138-axi-ethernet.pdf  《AXI1G/2.5GEthernetSubsystemv7.2》Figure2-38:PCSPMATEMACStatusRegister(0x0000_0030)比特位:PhyLinkStatuspg051-tri-......
  • 学习FPGA,就业范围有哪些方面?
    部分FPGA学习爱好者在转入这一行业之前,都会发出这么一个疑问,学习FPGA,就业如何,就业的范围和前景如何?有没更具体一点的分享和讲述?其实,想要一个更具体的岗位描述,有个简单快捷的......