你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32MP1嵌入式Linux驱动开发指南V1.7-RGB LCD彩条显示实验

[复制链接]
STMCU小助手 发布时间:2022-9-27 16:40
RGB LCD彩条显示实验
2 d  ~. t: X8 p+ LTFT-LCD是一种液晶显示屏,它采用薄膜晶体管(TFT)技术提升图像质量,如提高图像亮度和对比度等。相比于传统的CRT显示器,TFT-LCD有着轻薄、功耗低、无辐射、图像质量好等诸多优点,因此广泛应用于电视机、电脑显示器、手机等各种显示设备中。! n  _# S/ y9 C. e" N" j* i

2 G# J- a- R. o% j- e1.1 RGB LCD简介% g3 R5 M) I+ R% \( E& U
TFT-LCD的全称是Thin Film Transistor-Liquid Crystal Display,即薄膜晶体管液晶显示屏,它显示的每个像素点都是由集成在液晶后面的薄膜晶体管独立驱动,因此TFT-LCD具有较高的响应速度以及较好的图像质量。正点原子推出的RGB LCD液晶屏较多,7寸RGB LCD屏的实物图如下图所示:
! }- z0 W9 |+ S
, _2 E+ e) m6 K# z3 T" H& `2 K 9cec3f2301154d778d2642a9c44f99f2.png 3 h' V7 m7 {4 \7 s/ x% v) M9 M

* }) F- i" P2 W. P; M图 7.5.13.1 ATK-7’RGB接口TFT液晶屏模块+ g: x4 E; n' \- H/ a& H6 \
液晶显示器是现在最常用到的显示器,手机、电脑、各种人机交互设备等基本都用到了LCD,最常见的就是手机和电脑显示器了。由于笔者不是LCD从业人员,对于LCD的具体原理不了解,百度百科对于 LCD的原理解释如下:* D3 x  x2 a) S+ v
LCD的构造是在两片平行的玻璃基板当中放置液晶盒,下基板玻璃上设置 TFT(薄膜晶体管),上基板玻璃上设置彩色滤光片,通过TFT上的信号与电压改变来控制液晶分子的转动方向,从而达到控制每个像素点偏振光出射与否而达到显示目的。我们现在要在领航者开发板上使用LCD,所以不需要去研究LCD 的具体实现原理,我们只需要从使用的角度去关注 LCD 的几个重要点:
! ?1 i* z' R# j+ j1、分辨率
3 p6 g5 m6 ]  z0 d: T2 ]提起LCD显示器,我们都会听到720P、1080P、2K或4K这样的字眼,这个就是LCD显示器分辨率。 LCD显示器都是由一个一个的像素点组成,像素点就类似一个灯(在OLED显示器中,像素点就是一个小灯),这个小灯是RGB灯,也就是由R(红色)、G(绿色)和B(蓝色)这三种颜色组成的,而RGB就是光的三原色。 1080P的意思就是一个LCD屏幕上的像素数量是1920*1080个,也就是这个屏幕一列1080个像素点,一共 1920列,如图 7.5.13.2所示:
+ e2 l# X( F. N; z; u4 d! [" ?2 F, M& k4 |
dcbc7c4114924508b614e32e61e311e4.png # n8 _) W( j1 v# ^6 l& v
. m9 x7 G! L0 L4 d9 g8 _
图 7.5.13.2 像素点排布+ S5 P& X* |* b1 ^
图 7.5.13.2就是1080P显示器的像素示意图,X轴就是LCD显示器的横轴,Y轴就是显示器的竖轴。图中的小方块就是像素点,一共有19201080=2073600个像素点。左上角的A点是第一个像素点,右下角的C点就是最后一个像素点。2K就是25601440个像素点,4K是38402160个像素点。很明显,在LCD尺寸不变的情况下,分辨率越高越清晰。同样的,分辨率不变的情况下,LCD尺寸越小越清晰。比如我们常用的24寸显示器基本都是1080P的,而我们现在使用的5寸的手机基本也是1080P的,但是手机显示细腻程度就要比24寸的显示器要好很多!由此可见,LCD显示器的分辨率是一个很重要的参数,但是并不是分辨率越高的LCD就越好。衡量一款LCD的好坏,分辨率只是其中的一个参数,还有色彩还原程度、色彩偏离、亮度、可视角度、屏幕刷新率等其他参数。
' K" @- X7 v: }0 H" Y: B2、像素格式
. m2 G: ^+ n5 C' x: F9 W上面讲了,一个像素点就相当于一个RGB小灯,通过控制R、G、B这三种颜色的亮度就可以显示出各种各样的色彩。那该如何控制R、G、B这三种颜色的显示亮度呢?一般一个R、G、B这三部分分别使用8bit的数据,那么一个像素点就是8bit3=24bit,也就是说一个像素点3个字节,这种像素格式称为 RGB888。当然常用的像素点格式还有RGB565,只需要两个字节,但在色彩鲜艳度上较差一些。我们领航者开发板上的RGB TFT-LCD接口采用的RGB888的像素格式,共需要24位,每一位对应RGB的颜色分量如下图所示:% K# }+ R; q. ]3 d/ ~! i

! a! _/ U% ?; D) s 4ad337de970343da9d388bafbfef393f.png
3 J# A, h# B/ p% \* |, _* ]9 V- \8 l
图 7.5.13.3 RGB888数据格式& e. S4 C" @2 M7 R/ ]7 D% I5 ~
在图 7.5.13.3中,一个像素点占用3个字节,其中bit23bit16是RED通道,bit15bit8是GREEN通道,bit7~bit0是BLUE通道。所以红色对应的值就是24’hFF0000,绿色对应的值就是24’h00FF00,蓝色对应的值为24’h0000FF。通过调节R、G、B的比例可以产生其它的颜色,比如24’hFFFF00就是黄色,24’h000000就是黑色,24’hFFFFFF就是白色。大家可以打开电脑的“画图”工具,在里面使用调色板即可获取到想要的颜色对应的数值,如图 7.5.13.4所示:
7 ^! |% k4 i* R  X1 `
; r' z1 A4 J; C* T) ~6 a( U  k 04708a6705ab4fd994a7eefc643b607e.png
4 {4 [  n, z3 m( k+ W, x5 O3 ?" B, |  i1 c  k
图 7.5.13.4 调色板颜色选取2 c4 k" Y& r1 w% @/ d# X
3、LCD屏幕接口
8 G* D8 K6 l* i; |; dLCD屏幕或者说显示器有很多种接口,比如在显示器上常见的VGA、HDMI、DP等等,领航者开发板支持RGB接口的LCD和HDMI接口的显示器。本章我们介绍的是RGB LCD接口,RGB LCD接口的信号线如下表所示:
( B7 V& q9 g! A3 a表 18.1.1 RGB数据线
# S0 \# a( L, Q/ o信号线 描述  A* S! G3 v& ~8 q) a7 n6 |+ s
R[7:0] 8根红色数据线
, ?5 @( T  `3 U/ J) x4 a# c8 h- EG[7:0] 8根绿色数据线
- K8 I- |# S+ x: L" s$ {2 x& q+ W- hB[7:0] 8根蓝色数据线
7 M+ L1 [& B: Q" W, q! ~+ ADE 数据使能线7 j6 M/ j1 [4 e+ P
VSYNC 垂直同步信号线
$ i7 f/ j: o- G# _) DHSYNC 水平同步信号线
1 |  L2 Y! X9 p! [PCLK 像素时钟信号线& Q; @9 J& a2 |  ]- O
表 18.1.1就是RGB LCD的信号线,R[7:0]、G[7:0]和B[7:0]是24位数据,DE、VSYNC、HSYNC和PCLK是四个控制信号。
/ Q" y6 s! S8 X5 \# H4 d正点原子一共有五款RGB LCD屏幕,型号分别为ATK-4342(4.3寸,480272)、ATK-4384(4.3寸,800480)、ATK-7084(7寸,800480)、ATK-7016(7寸,1024600)和ATK-1018(10.1寸,1280*800)。这里以ATK-7016这款屏幕为例讲解,ATK-7016的屏幕接口原理图如所示:
! ?+ i' b% w$ M! h  x
$ T+ F/ f4 u6 @/ e) j ef2be8c1514b43e884df773a03a5ec9c.png ) n& a8 a. A: o. w

  Z" Z! F; `3 `) O7 u" R图 7.5.13.5 RGB LCD液晶屏幕接口
  i* B$ E) T2 }图中J1就是对外接口,是一个40PIN的FPC座(0.5mm间距),通过FPC线,可以连接到领航者ZYNQ开发板上面,从而实现和开发板的连接。该接口十分完善,采用RGB888格式,并支持触摸屏和背光控制。右侧的几个电阻,并不是都焊接的,而是可以用户自己选择。默认情况,R1和R6 焊接,设置LCD_LR和LCD_UD,控制LCD的扫描方向,是从左到右,从上到下(横屏看)。而LCD_R7/G7/B7 则用来设置LCD的ID,由于RGBLCD没有读写寄存器,也就没有所谓的ID,这里我们通过在模块上面,控制R7/G7/B7的上/下拉,来自定义LCD模块的ID,帮助MCU判断当前LCD面板的分辨率和相关参数,以提高程序兼容性。这几个位的设置关系如表 18.1.2所示:- z. @1 a0 c+ Z! E* g, E+ g
表 18.1.2 RGB LCD模块和ID对应关系
) t0 u5 P: R! L8 T. r# n* Z, V, D! wM27 t7 c" g8 E& a
LCD_B7 M1
0 J# a/ C9 C: l- N) q8 LLCD_G7 M0, j, ]' ?8 x6 o1 M) b
LCD_R7 LCD ID 说明% T+ Y2 \: T+ Z8 F" N
0 0 0 4342 ATK-4342 RGB LCD模块,分辨率:480272
$ o4 p7 `( s9 i6 O( o0 0 1 7084 ATK-7084 RGB LCD模块,分辨率:800480
7 l; r" b5 }6 J6 n" N0 1 0 7016 ATK-7016 RGB LCD模块,分辨率:1024600& g$ K4 F& Z* W3 `  ]8 a7 v3 \
1 0 0 4384 ATK-4384 RGB LCD模块,分辨率:8004806 |1 x7 M' T* r  h
1 0 1 1018 ATK-1018 RGB LCD模块,分辨率:1280800
4 X! E. |* v, A' ~X X X NC 暂时未用到
& `4 {( f1 x3 EATK-7016模块,就设置M2:M0 = 010即可。这样,我们在程序里面,读取LCD_R7/G7/B7,得到M0:M2 的值,从而判断RGB LCD模块的型号,并执行不同的配置,即可实现不同LCD模块的兼容。( e# L( z; C0 B
4、LCD时间参数
% Y# ^& y/ `( b& d( K/ K如果将LCD显示一帧图像的过程想象成绘画,那么在显示的过程中就是用一根“笔”在不同的像素点画上不同的颜色。这根笔按照从左至右、从上到下的顺序扫描每个像素点,并且在像素画上对应的颜色,当画到最后一个像素点的时候一幅图像就绘制好了。假如一个LCD的分辨率为1024600,那么其扫描如图 7.5.13.6所示:
5 C  d& K- a' ]$ m, A) |) p( I
/ R4 g0 J" ~" j+ P e926df9679954fa69e46c1d297b3a279.png
! M0 H+ Q9 l. k9 e3 N; Z$ k; L; c1 h7 H+ i/ S2 S) W* S
图 7.5.13.6 LCD一帧图像扫描图( ^" P4 U! b+ y$ Y! L1 _
结合图 7.5.13.6我们来看一下LCD是怎么扫描显示一帧图像的。一帧图像也是由一行一行组成的。HSYNC是水平同步信号,也叫做行同步信号,当产生此信号的话就表示开始显示新的一行了,所以此信号都是在图 7.5.13.6的最左边。VSYNC信号是垂直同步信号,也叫做帧同步信号,当产生此信号的话就表示开始显示新的一帧图像了,所以此信号在图 7.5.13.6的左上角。
# h: _- Q! O8 N在图 7.5.13.6可以看到有一圈“黑边”,真正有效的显示区域是中间的白色部分。那这一圈“黑边”是什么东西呢?这就要从显示器的“祖先”CRT显示器开始说起了,CRT显示器就是以前很常见的那种大屁股显示器,在2019年应该很少见了,如果在农村应该还是可以见到的。CRT显示器屁股后面是个电子枪,这个电子枪就是我们上面说的“画笔”,电子枪打出的电子撞击到屏幕上的荧光物质使其发光。只要控制电子枪从左到右扫完一行(也就是扫描一行),然后从上到下扫描完所有行,这样一帧图像就显示出来了。也就是说,显示一帧图像电子枪是按照‘Z’形在运动,当扫描速度很快的时候看起来就是一幅完成的画面了。, t  s; V5 z+ m3 S+ Y
当显示完一行以后会发出HSYNC信号,此时电子枪就会关闭,然后迅速的移动到屏幕的左边,当 HSYNC信号结束以后就可以显示新的一行数据了,电子枪就会重新打开。在HSYNC信号结束到电子枪重新打开之间会插入一段延时,这段延时就是图 7.5.13.6中的HBP。当显示完一行以后就会关闭电子枪等待 HSYNC信号产生,关闭电子枪到HSYNC信号产生之间会插入一段延时,这段延时就是图 7.5.13.6中的HFP 信号。同理,当显示完一帧图像以后电子枪也会关闭,然后等到VSYNC信号产生,期间也会加入一段延时,这段延时就是图 7.5.13.6中的VFP。VSYNC信号产生,电子枪移动到左上角,当VSYNC信号结束以后电子枪重新打开,中间也会加入一段延时,这段延时就是图 7.5.13.6中的VBP。4 ^# B2 G) F% m# R8 M7 r7 U6 s- Y
HBP、HFP、VBP和VFP就是导致图 7.5.13.6中黑边的原因,但是这是CRT显示器存在黑边的原因,现在是LCD显示器,不需要电子枪了,那么为何还会有黑边呢?这是因为RGB LCD屏幕内部是有一个IC 的,发送一行或者一帧数据给IC,IC是需要反应时间的。通过这段反应时间可以让IC识别到一行数据扫描完了,要换行了,或者一帧图像扫描完了,要开始下一帧图像显示了。因此,在LCD屏幕中继续存在HBP、HFP、VPB和VFP这四个参数的主要目的是为了锁定有效的像素数据。
$ k7 E6 @$ }3 M. k+ d5、RGB LCD屏幕时序
' [. a5 L5 X- o4 Z) U上面介绍了LCD的时间参数,我们接下来看一下行显示对应的时序图,如图 7.5.13.7所示。+ v' J7 {( h, {, n# _
+ o( u/ u7 w. E+ t
cb904a588e924d158974f9b302818aef.png
0 V) L; U9 d6 S! w& h# s
  }3 d( Y2 ?4 t6 K0 n# G图 7.5.13.7 LCD行显示时序5 L! Y" U0 u  k) l$ z
图 7.5.13.7就是RGB LCD的行显示时序,我们来分析一下其中重要的几个参数:' a. R9 b, a5 H7 W& p+ j& ^$ ~
HSYNC:行同步信号,当此信号有效的时候就表示开始显示新的一行数据,查阅所使用的LCD数据手册可以知道此信号是低电平有效还是高电平有效,图 7.5.13.7为低电平有效。
' o2 x. z7 P7 ^& AHSPW:行同步信号宽度,也就是HSYNC信号持续时间。HSYNC信号不是一个脉冲,而是需要持续一段时间才是有效的,单位为CLK。
7 z: M4 [* m  ~  u4 m0 WHBP:行显示后沿(或后肩),单位是CLK。0 a: ?& \' j. _
HOZVAL:行有效显示区域,即显示一行数据所需的时间,假如屏幕分辨率为1024*600,那么HOZVAL 就是1024,单位为CLK。
% `- Q# \+ P. f) c8 c+ B. H6 qHFP:行显示前沿(或前肩),单位是CLK。
  Q% w4 a1 d% ?当HSYNC信号发出以后,需要等待HSPW+HBP个CLK时间才会接收到真正有效的像素数据。当显示完一行数据以后需要等待HFP个CLK时间才能发出下一个HSYNC信号,所以显示一行所需要的时间就是:HSPW + HBP + HOZVAL + HFP。
% p8 X- Y7 m- s  t9 ~一帧图像就是由很多个行组成的,RGB LCD的帧显示时序如图 7.5.13.8所示:$ Z. j0 J0 |5 Y2 N) b% r/ z
# {; O! }) |" e: Q
9a2fd17dde2e45d3b4adf6cbabc8db19.png + w7 w$ f, C' j! O

* Y- Z; E/ l3 O: ^* d图 7.5.13.8 LCD帧显示时序. q. i$ m! f  c. `9 y
图 7.5.13.8就是RGB LCD的帧显示时序,我们来分析一下其中重要的几个参数:
$ k# ^( T/ u- i- U; _VSYNC:帧(场)同步信号,当此信号有效的时候就表示开始显示新的一帧数据,查阅所使用的LCD数据手册可以知道此信号是低电平有效还是高电平有效,图 7.5.13.8为低电平有效。" o5 v" z) \. \3 k8 J- n# ]
VSPW:帧同步信号宽度,也就是VSYNC信号持续时间,单位为1行的时间。
. V/ t4 I0 r6 m2 `/ QVBP:帧显示后沿(或后肩),单位为1行的时间。
- G8 u3 b" N  l  A) _9 BLINE:帧有效显示区域,即显示一帧数据所需的时间,假如屏幕分辨率为1024600,那么LINE就是600行的时间。
/ H& ?& y4 N: u! g! qVFP:帧显示前沿(或前肩),单位为1行的时间。
- G9 {. N2 I4 U) ^  A3 ~- B显示一帧所需要的时间就是:VSPW+VBP+LINE+VFP个行时间,最终的计算公式:
% e( b/ U% P; J0 D7 R% d9 `T = (VSPW+VBP+LINE+VFP) * (HSPW + HBP + HOZVAL + HFP)
* w, C' F  }* n) ]因此我们在配置一款RGB LCD屏的时候需要知道这几个参数:HSPW(行同步)、HBP(行显示后沿)、HOZVAL(行有效显示区域)、HFP(行显示前沿)、VSPW(场同步)、VBP(场显示后沿)、LINE(场有效显示区域)和VFP(场显示后沿)。
! I. u5 ], o% O2 B, w% zRGB LCD液晶屏一般有两种数据同步方式,一种是行场同步模式(HV Mode),另一种是数据使能同步模式(DE Mode)。当选择行场同步模式时,LCD接口的时序与VGA接口的时序图非常相似,只是参数不同,如图 16.1.9和图 16.1.8中的行同步信号(HSYNC)和场同步信号(VSYNC)作为数据的同步信号,此时数据使能信号(DE)必须为低电平。
/ y- U+ @, E+ O1 B& r. }当选择DE同步模式时,LCD的DE信号作为数据的有效信号,,如图 16.1.10和图 16.1.8中的DE信号所示。只有同时扫描到帧有效显示区域和行有效显示区域时,DE信号才有效(高电平)。当选择DE同步模式时,此时行场同步信号VS和HS必须为高电平。4 }/ M$ T5 A# P+ L" A, z
由于RGB LCD液晶屏一般都支持DE模式,不是所有的RGB LCD液晶屏都支持HV模式,因此本章我们采用DE同步的方式驱动LCD液晶屏。$ {; W: x& f: q9 y) k: ?7 A5 {
6、像素时钟2 D, m$ ~8 [2 T4 r. W
像素时钟就是RGB LCD的时钟信号,以ATK7016这款屏幕为例,显示一帧图像所需要的时钟数就是:& I/ o* Y: O. J2 i/ T8 u' t
N(CLK)= (VSPW+VBP+LINE+VFP) * (HSPW + HBP + HOZVAL + HFP). F3 X. `) Y% F0 l
= (3 + 20 + 600 + 12) * (20 + 140 + 1024 + 160) = 635 * 1344 = 853440
. `/ O4 b$ `" H显示一帧图像需要853440个时钟数,那么显示60帧就是:853440 * 60 = 51206400≈51.2M,所以像素时钟就是51.2MHz。
3 X* {5 ]; C9 U, x. T! N( a0 l当然我们在为RGB LCD屏提供驱动时钟的时候,也可以不用严格按照60帧来进行计算。为了方便操作,我们可以给ATK7016模块输出一个50MHz的时钟,其刷新率是接近于60Hz的,同时也非常方便我们来编写代码。
# F: T9 w' X) c# e. B/ N. Y" c' t1 C为了方便大家查找LCD屏的时序参数,这里整理了不同分辨率的时序参数,如表 18.1.3所示:3 g3 p! G3 C) K& W5 ?
表 18.1.3 不同分辨率的LCD时序参数
7 s1 Z6 F4 j$ `6 l& h显示分辨率 时钟(Mhz) 行时序(像素数) 帧时序(行数)
% f: e; {8 J+ }% d3 L7 Q行同步 显示后沿 显示 区域 显示前沿 显示 周期 场同步 显示后沿 显示区域 显示前沿 显示 周期
1 t9 V% u2 k. q1 |! P480272 9 41 2 480 2 525 10 2 272 2 286
/ D& ~0 @( j7 A* k$ Z800480 33.3 128 88 800 40 1056 2 33 480 10 525, W" v% W: z3 {
1024600 50 20 140 1024 160 1344 3 20 600 12 635! s- m) @8 H. Y" u, s# R
1280*800 70 10 80 1280 70 1440 3 10 800 10 823
& ^: v% {( r) A' h* ]1.2 实验任务7 z; T! H+ ]( v# B. {& g
本节的实验任务是使用正点原子ZYNQ开发板上的RGB TFT-LCD接口,驱动RGB LCD液晶屏(支持目前推出的所有RGB LCD屏),并显示出彩条。* `' b: u4 X2 D7 N, N( i
1.3 硬件设计
. n8 U3 A5 E' j' M" V领航者开发板上RGB TFT-LCD接口部分的原理图如下图所示。
: e; B, }7 k5 A' ]+ s: }, w( L0 d- i8 a/ X" l5 T: s* R
c042b91f794044858b4aa57a4dca7b0e.png , R1 J& _8 R5 h! ]$ u" ]# u

+ B. |5 z5 v  w2 ]3 W" C图 7.5.13.1 RGB TFTLCD接口原理图$ }5 o6 t! v. d
从上图中可以看到,FPGA管脚输出的颜色数据位宽为24bit,数据格式为RGB888,即数据高8位表示红色,中间8位表示绿色,低8位表示蓝色。由于这24位数据不仅仅作为输出给LCD屏的颜色数据,同时LCD_R7、LCD_G7和LCD_B7也用来获取LCD屏的ID,因此这24位颜色数据对ZYNQ开发板来说,是一个双向的引脚。' q+ R# l" _% b5 P/ l; C' Z
另外,RGBLCD模块支持触摸功能,图中以字母T开头的5个信号(T_PEN、T_SCK等)与模块上的触摸芯片相连接。由于本次实验不涉及触摸功能的实现,因此这些信号并未用到。$ d5 m0 o& S4 |2 e& l( I3 B
需要说明的是,LCD液晶屏有一个复位信号(LCD_RST),当LCD_RST为低电平时,可对LCD屏进行复位。6 o6 b1 q2 w7 R# n# D' V0 r
本实验中,各端口信号的管脚分配如下表所示:! o6 J; m, F& W8 b
表 18.3.1 RGB TFT-LCD彩条实验管脚分配
6 a- ~6 m3 D, }1 O: }/ U2 I( Y) s$ w信号名 方向 管脚 端口说明 电平标准; m) u9 ?/ H$ j: A
sys_clk input U18 系统时钟,50M LVCMOS33
# ?" N: U1 {& \8 k7 Fsys_rst_n input N16 系统复位,低有效 LVCMOS336 Z& b0 J0 x9 @8 j
lcd_rgb[0] inout W18 RGB LCD蓝色(最低位) LVCMOS33
7 L. E( k: Y0 y# zlcd_rgb[1] inout W19 RGB LCD蓝色 LVCMOS337 _) I- ?3 \/ l" Q* |" Z8 i( Z
lcd_rgb[2] inout R16 RGB LCD蓝色 LVCMOS33% H( n# l7 Q6 J  X0 ?8 a
lcd_rgb[3] inout R17 RGB LCD蓝色 LVCMOS33/ n6 q' d/ b0 f  R1 o1 N8 z' K
lcd_rgb[4] inout W20 RGB LCD蓝色 LVCMOS33, w2 u7 H6 Y! R/ J( [4 U
lcd_rgb[5] inout V20 RGB LCD蓝色 LVCMOS33
( l. F1 s3 O; q- Z  n! p+ Qlcd_rgb[6] inout P18 RGB LCD蓝色 LVCMOS33
% B' ~6 J$ |' Z, ^) w2 X& ~. Clcd_rgb[7] inout N17 RGB LCD蓝色(最高位) LVCMOS33# `( n: D" t1 V/ o
lcd_rgb[8] inout V17 RGB LCD绿色(最低位) LVCMOS33- @4 R4 Z) Y1 g* H
lcd_rgb[9] inout V18 RGB LCD绿色 LVCMOS33$ b) M2 c7 F) `9 j0 ]; W
lcd_rgb[10] inout T17 RGB LCD绿色 LVCMOS332 A4 ^& M7 Q/ i( B/ Z/ O! n
lcd_rgb[11] inout R18 RGB LCD绿色 LVCMOS33) T& }6 P. ?( M# p# F* ?
lcd_rgb[12] inout Y18 RGB LCD绿色 LVCMOS33
3 E0 M  e$ a  e- y4 L8 Wlcd_rgb[13] inout Y19 RGB LCD绿色 LVCMOS339 \: V4 L% V3 Z# Y  Y( x' b+ ^* T
lcd_rgb[14] inout P15 RGB LCD绿色 LVCMOS33
- z0 g2 W( W* ^lcd_rgb[15] inout P16 RGB LCD绿色(最高位) LVCMOS33
' {6 n8 Y2 z* Y9 a3 K! a! rlcd_rgb[16] inout V16 RGB LCD红色(最低位) LVCMOS33
. U' ?. m) o/ W9 rlcd_rgb[17] inout W16 RGB LCD红色 LVCMOS33
2 U$ B7 E) C) b7 J( z2 {! s4 Ylcd_rgb[18] inout T14 RGB LCD红色 LVCMOS33
3 M, G" u0 J; H0 T5 I! O8 W; G" Llcd_rgb[19] inout T15 RGB LCD红色 LVCMOS330 _$ p$ |' \: n; p2 b! j
lcd_rgb[20] inout Y17 RGB LCD红色 LVCMOS33
3 Z  c! r3 a! r  Z' X3 \lcd_rgb[21] inout Y16 RGB LCD红色 LVCMOS33% x/ h+ r) r9 Q) U* E. \1 m
lcd_rgb[22] inout T16 RGB LCD红色 LVCMOS33+ X$ R; X% W, z+ [2 D3 x
lcd_rgb[23] inout U17 RGB LCD红色(最高位) LVCMOS33
/ a7 T. h7 v  hlcd_hs output N18 RGB LCD行同步 LVCMOS338 n( J' a: q5 p6 z5 F
lcd_vs output T20 RGB LCD场同步 LVCMOS33
2 l9 h7 |# o' y! S6 S2 f% alcd_de output U20 RGB LCD数据使能 LVCMOS33
# e/ i/ ^1 F9 n. C' |lcd_bl output M20 RGB LCD背光控制 LVCMOS334 \( w6 Z! I' q' c5 B0 |3 J
lcd_clk output P19 RGB LCD像素时钟 LVCMOS33! ^* T0 F* S" K) D7 {
lcd_rst output L17 RGB LCD复位信号 LVCMOS33, P' A# i) D! h  s: C7 w+ [
对应的XDC约束语句如下所示:
5 L. K6 c& u; d8 p3 j: h# ^6 J/ n$ ?& B6 K
  1. set_property -dict {PACKAGE_PIN U18 IOSTANDARD LVCMOS33} [get_ports sys_clk]* J5 d5 T/ M& t+ y; ^3 ~. |9 n
  2. set_property -dict {PACKAGE_PIN N16 IOSTANDARD LVCMOS33} [get_ports sys_rst_n]
    ! m' d! A# E& c
  3. : r. q9 y/ h, L
  4. set_property -dict {PACKAGE_PIN W18 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[0]}]
    " M" Y/ u5 x  \. X. R3 q
  5. set_property -dict {PACKAGE_PIN W19 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[1]}]- W9 }3 g$ D% X, R" M
  6. set_property -dict {PACKAGE_PIN R16 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[2]}]
    : j) a" Q8 |, k1 v% _. S
  7. set_property -dict {PACKAGE_PIN R17 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[3]}]' w  r1 E: q) N( E
  8. set_property -dict {PACKAGE_PIN W20 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[4]}]
    4 G  Q! a( ]3 A; p- m' Z# }. [
  9. set_property -dict {PACKAGE_PIN V20 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[5]}]
    ) w$ ]% v, K1 p) c% k' s
  10. set_property -dict {PACKAGE_PIN P18 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[6]}]
    , V, y- Q" c1 E+ m5 w
  11. set_property -dict {PACKAGE_PIN N17 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[7]}]& V+ {+ `2 @! B
  12. set_property -dict {PACKAGE_PIN V17 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[8]}]
    * J# b9 F3 _( [! }
  13. set_property -dict {PACKAGE_PIN V18 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[9]}]: J6 ?7 m$ M2 C6 M2 f* s
  14. set_property -dict {PACKAGE_PIN T17 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[10]}]7 d$ m3 e; l& J% v- E- ?
  15. set_property -dict {PACKAGE_PIN R18 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[11]}]. H& h# j6 Y" a1 W/ ]" L4 o1 ~
  16. set_property -dict {PACKAGE_PIN Y18 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[12]}]
    6 f1 d3 T& F' T
  17. set_property -dict {PACKAGE_PIN Y19 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[13]}]
    * F6 n$ v% l1 q2 G
  18. set_property -dict {PACKAGE_PIN P15 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[14]}]8 O! x* F9 y& a  M
  19. set_property -dict {PACKAGE_PIN P16 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[15]}]
    ! V% h: M. e: p. C1 I
  20. set_property -dict {PACKAGE_PIN V16 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[16]}]
    : v1 X$ l" \' b. u) p; a+ F
  21. set_property -dict {PACKAGE_PIN W16 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[17]}]) T5 i2 r" `; K; D
  22. set_property -dict {PACKAGE_PIN T14 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[18]}]/ V6 X, C( x0 `9 a7 g" \7 f
  23. set_property -dict {PACKAGE_PIN T15 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[19]}]+ d5 {- a, B; `3 `. O/ E0 _
  24. set_property -dict {PACKAGE_PIN Y17 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[20]}]% J, `# k1 C% |
  25. set_property -dict {PACKAGE_PIN Y16 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[21]}]1 y; d0 j5 ]6 h+ f
  26. set_property -dict {PACKAGE_PIN T16 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[22]}]/ O; f) I1 P8 ~
  27. set_property -dict {PACKAGE_PIN U17 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[23]}]) b4 R% X) e) \# w" [! A3 z

  28. ! T6 J* X5 f+ u. M  J& K$ V; X
  29. set_property -dict {PACKAGE_PIN N18 IOSTANDARD LVCMOS33} [get_ports lcd_hs]
    9 D" G: k% ?3 t6 s# B" P/ o
  30. set_property -dict {PACKAGE_PIN T20 IOSTANDARD LVCMOS33} [get_ports lcd_vs]" H& h( n8 V9 R$ ~! a/ S
  31. set_property -dict {PACKAGE_PIN U20 IOSTANDARD LVCMOS33} [get_ports lcd_de]
    4 Q# v: W& Y5 D/ h7 H5 W  Q' _. j
  32. set_property -dict {PACKAGE_PIN M20 IOSTANDARD LVCMOS33} [get_ports lcd_bl]6 Q7 L0 H# u, P* X3 n' }6 [+ T6 R
  33. set_property -dict {PACKAGE_PIN P19 IOSTANDARD LVCMOS33} [get_ports lcd_clk]" p. b' e( P. I, R4 O
  34. set_property -dict {PACKAGE_PIN L17 IOSTANDARD LVCMOS33} [get_ports lcd_rst]
复制代码
( g) X- {1 f' z" ]  K+ T8 Y& B
1.4 程序设计
; h' [% u1 d" g0 u- zRGB TFT-LCD输入时序包含三个要素:像素时钟、同步信号、以及图像数据,由此我们可以大致规划出系统结构如下图所示。其中,读取ID模块用于获取LCD屏的ID;由于不同分辨率的屏幕需要不同的驱动时钟,因此时钟分频模块根据LCD ID来输出不同频率的像素时钟;LCD显示模块负责产生液晶屏上显示的数据,即彩条数据;LCD驱动模块根据LCD屏的ID,输出不同参数的时序,来驱动LCD屏,并将输入的彩条数据显示到LCD屏上。: s1 ]9 X0 }4 t+ X; K) }& v
, ^: W* [  s3 N1 o9 |, C' m: \
4d52e2ab6772454a8e57c62016a23c76.png
5 F- q3 i: @- K3 \
+ _; [7 m9 ?  Z8 H, C图 7.5.13.1 RGB TFT-LCD彩条显示系统框图
3 c0 x3 T" D0 M% ]: ~) Z由系统框图可知,FPGA部分包括五个模块,顶层模块(lcd_rgb_colorbar)、读取ID模块(rd_id)、时钟分频模块(clk_div)、LCD显示模块(lcd_display)以及LCD驱动模块(lcd_driver)。其中在顶层模块中完成对其余模块的例化。
& @; i( [& j' B各模块端口及信号连接如下图所示:8 i+ @9 M! ?% Q$ C

4 }6 I% z# P8 }; K 89989b8a7dac4467be85eefd31839940.png
; d6 H$ v0 v& p- n
" i, Z: e  o; c9 w: n图 7.5.13.2 顶层模块原理图* T" w  p& }5 m. v0 v
读取ID模块(rd_id)在上电时将RGB双向数据总线设置为输入,来读取LCD屏的ID;时钟分频模块(clk_div)根据读取的ID来配置LCD的像素时钟;LCD驱动模块(lcd_driver)在像素时钟的驱动下输出数据使能信号用于数据同步,同时还输出像素点的纵横坐标,供LCD显示模块(lcd_display)调用,以绘制彩条图案。( c6 r& e3 s/ _1 S& H/ m9 R9 {
顶层模块lcd_rgb_colorbar的代码如下:
: E, F$ A2 K6 ^% n" w! ~* K0 A+ G* |6 l9 ^
  1. 1  module lcd_rgb_colorbar(
    2 A4 |0 V+ }# I9 ^" t! k6 h
  2. 2      input                sys_clk,     //系统时钟. f. A4 P3 b8 p" W. ]
  3. 3      input                sys_rst_n,   //系统复位
    1 g' R8 N: d! V5 \
  4. 4  
    ; M  n* G3 @( J+ B1 W# l. s
  5. 5      //RGB LCD接口
    ( L; f1 o" X# e0 G1 @
  6. 6      output               lcd_de,      //LCD 数据使能信号
    3 [( X; p, z4 [4 C, G9 F5 _0 P
  7. 7      output               lcd_hs,      //LCD 行同步信号
    5 j: m4 J8 Z4 y
  8. 8      output               lcd_vs,      //LCD 场同步信号( L& n3 n+ j  G* N7 B  n; k7 W
  9. 9      output               lcd_bl,      //LCD 背光控制信号6 m  Y0 c1 k& s( b" \$ {# Z
  10. 10     output               lcd_clk,     //LCD 像素时钟+ M8 g; c) C9 j) _) ^1 i
  11. 11     output               lcd_rst,     //LCD 复位
    & \) x! |& B7 T/ J& ?
  12. 12     inout        [23:0]  lcd_rgb      //LCD RGB888颜色数据( j* z6 N5 \% v" m3 H
  13. 13     );                                                      ! Z) u& A, G8 m/ ^
  14. 14     
    / u/ F+ w* o# T  g4 g9 B. `
  15. 15 //wire define   
    / j: T7 u8 c0 h; \4 T7 c6 o
  16. 16 wire  [15:0]  lcd_id    ;    //LCD屏ID. U) |+ }' H; F& g5 t5 y+ V
  17. 17 wire          lcd_pclk  ;    //LCD像素时钟
    9 z0 y1 k' L* }
  18. 18               . Y3 `% q2 C+ X, ^: ^9 l
  19. 19 wire  [10:0]  pixel_xpos;    //当前像素点横坐标
    $ P+ a1 g7 x4 T+ p& \( h
  20. 20 wire  [10:0]  pixel_ypos;    //当前像素点纵坐标
    - k9 h5 T! y0 H' g" F$ M
  21. 21 wire  [10:0]  h_disp    ;    //LCD屏水平分辨率
    ( t2 E: ], Z( V3 c7 }
  22. 22 wire  [10:0]  v_disp    ;    //LCD屏垂直分辨率
    . n# L' s2 h$ }
  23. 23 wire  [23:0]  pixel_data;    //像素数据0 K8 K9 a( f2 \+ Z
  24. 24 wire  [23:0]  lcd_rgb_o ;    //输出的像素数据
    ; @4 p2 m$ \3 b5 F4 h9 y0 n
  25. 25 wire  [23:0]  lcd_rgb_i ;    //输入的像素数据0 a, a, x" y# Z+ b
  26. 26
    # F$ F+ j$ x' _0 K2 l9 y
  27. 27 //*****************************************************- ?  F. Z3 j$ A# l$ L7 `
  28. 28 //**                    main code) h3 M( }- o3 v! J+ d* x. G
  29. 29 //*****************************************************, F: k  R" d# a+ e0 _0 V
  30. 30 * o8 T9 n! ]7 a. p' ?
  31. 31 //像素数据方向切换: [% d2 C5 C7 N4 i( U
  32. 32 assign lcd_rgb = lcd_de ?  lcd_rgb_o :  {24{1'bz}};
    2 S4 A' y+ y* a
  33. 33 assign lcd_rgb_i = lcd_rgb;9 s  z  t8 B' ~0 a+ q0 h
  34. 34
    ! ?& B: ~# T3 j  B
  35. 35 //读LCD ID模块9 r( {% e. D& s
  36. 36 rd_id u_rd_id(
    + }4 r  G5 @4 A9 u& ?( `: |$ k5 m+ e
  37. 37     .clk          (sys_clk  ),6 t0 m' o2 M# Q$ x0 J3 c
  38. 38     .rst_n        (sys_rst_n),
    3 U* ^; y1 `: F* \  v- K
  39. 39     .lcd_rgb      (lcd_rgb_i),, |1 R, i, l2 }2 O6 p
  40. 40     .lcd_id       (lcd_id   )" V& l2 H; e5 {5 j' K% U4 l
  41. 41     );   
    4 ~0 T/ g8 H' [; T2 E
  42. 42 / e  e. I6 D! J4 L7 u7 s8 Z  l' b
  43. 43 //时钟分频模块   
    & Z8 k. A& R/ a% o
  44. 44 clk_div u_clk_div(
    / Z- p2 K8 O6 i8 k( Q  x% u5 A
  45. 45     .clk           (sys_clk  ),1 o- Y& s: r; `# w. e
  46. 46     .rst_n         (sys_rst_n),7 b. h; K3 B  e! X! Y
  47. 47     .lcd_id        (lcd_id   ),  m4 m0 \$ I+ {  ^: O# s& ]% R! p
  48. 48     .lcd_pclk      (lcd_pclk )
    8 ~9 M/ @* V7 R0 N9 I
  49. 49     );    + }% D5 g) T) w9 N5 P$ X) [! _
  50. 50 6 O$ Y- N6 J+ P! K. H( \7 G
  51. 51 //LCD显示模块   
    * D; r6 C4 Q; ^, {# N+ M5 a! l
  52. 52 lcd_display u_lcd_display(
    ) n4 q% b" f2 F
  53. 53     .lcd_pclk       (lcd_pclk  ),
    / R% t. P8 A- B8 O
  54. 54     .rst_n          (sys_rst_n ),
    $ ?" ?7 c8 U3 _( @
  55. 55     .pixel_xpos     (pixel_xpos),
    , l6 i9 T) c8 m/ m& {" G) `# {2 C0 l
  56. 56     .pixel_ypos     (pixel_ypos),
    + w  O2 j, z0 z2 K
  57. 57     .h_disp         (h_disp    ),
    - z% S# Y" S" ?- p3 }9 f
  58. 58     .v_disp         (v_disp    ),
    9 ~, \: G& h) s( V( t. c& o5 r& V9 ~
  59. 59     .pixel_data     (pixel_data)5 G0 D, x, L! I
  60. 60     );    ( c/ G3 z/ G6 [. {0 n
  61. 61
    9 u3 ]  V7 r) M/ a4 ?% P
  62. 62 //LCD驱动模块! Y3 @: i7 T% S+ B- c
  63. 63 lcd_driver u_lcd_driver(9 ^0 [. B4 _" _7 K
  64. 64     .lcd_pclk      (lcd_pclk  )," p, h' C; ~3 Z$ K. y( A
  65. 65     .rst_n         (sys_rst_n ),
    3 k+ h' l: f* U. ^( V
  66. 66     .lcd_id        (lcd_id    ),7 F1 S8 n4 s( B
  67. 67     .pixel_data    (pixel_data),0 @% H7 E( j$ m; _6 }1 N4 X
  68. 68     .pixel_xpos    (pixel_xpos),
    - V0 r/ J+ x  h' Y9 `1 i; d! i! X' e  r
  69. 69     .pixel_ypos    (pixel_ypos),
    : e2 Y  P2 I, m7 _# f( M
  70. 70     .h_disp        (h_disp    ),
    1 |0 E) U- Z6 t9 f; `9 z" J& U
  71. 71     .v_disp        (v_disp    ),
    % Q! ]1 x) ]+ D/ a$ [) A
  72. 72
    6 k6 k- C* {: C3 e
  73. 73     .lcd_de        (lcd_de    ),: @% {, T3 b5 o3 f; _) o( u& M, {
  74. 74     .lcd_hs        (lcd_hs    ),
    ) m, j5 D4 P+ b& A' v
  75. 75     .lcd_vs        (lcd_vs    ),
    3 ~  e) K% T! c
  76. 76     .lcd_bl        (lcd_bl    ),
    & w. H: n- ]7 q+ s3 X
  77. 77     .lcd_clk       (lcd_clk   ),5 m3 p& R* T5 h0 ^7 ^: T" M
  78. 78     .lcd_rst       (lcd_rst   ),! n& g6 G& o+ p+ p
  79. 79     .lcd_rgb       (lcd_rgb_o )
    5 q& A4 E% m4 S% q0 g$ I
  80. 80     );6 b" p% u3 _* |
  81. 81 3 R3 w- x/ Q7 |
  82. 82 endmodule, |8 f" Q/ Y6 i4 w& [
复制代码
9 O. |+ b1 k6 K' C1 |0 ~' e: V! V
顶层模块主要完成对其他模块的例化。这里需要重点注意第32行代码,由于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。; u9 ?1 `# R/ c$ V; R4 ^& H8 R( k
读取ID模块的代码如下:
" p' L/ `( Z5 U" r, L0 p. Q5 k, T  Y! C5 S5 E
  1. 1   module rd_id(3 S) A! m' S8 L" p" X7 B6 i' Y+ U0 F; x. T
  2. 2       input                   clk    ,    //时钟
    5 O! t. h0 a$ @+ D  q
  3. 3       input                   rst_n  ,    //复位,低电平有效! a  E$ M+ I! s1 [7 e& t/ w
  4. 4       input           [23:0]  lcd_rgb,    //RGB LCD像素数据,用于读取ID
    % [, _" A# m& v4 Q7 F; m
  5. 5       output   reg    [15:0]  lcd_id      //LCD屏ID
    ) ^+ T4 e9 ^* g* M0 P# i
  6. 6       );
    # i. B9 T, w& }1 R$ g: Z* V- @! F4 T
  7. 7   
      f$ y0 F# a8 |/ _0 Y
  8. 8   //reg define
    ! b$ @" F: V4 ^
  9. 9   reg            rd_flag;                 //读ID标志# ^% |! ~' c/ a0 q# b% k/ m4 j
  10. 10  6 S9 ]) V! i2 x+ s, q
  11. 11  //*****************************************************
    5 u  ^* f/ }& O9 ~2 M* @' f
  12. 12  //**                    main code5 [9 @& q* E' K& M# H
  13. 13  //*****************************************************1 H/ E1 ]7 g" |, U% A
  14. 14  
    3 m' f, h4 {: P3 g
  15. 15  //获取LCD ID   M2:B7  M1:G7  M0:R7- U# ]2 k3 X1 [+ V/ l# Z  F
  16. 16  always @(posedge clk or negedge rst_n) begin
    5 b( R; r3 b- Z# Z6 E: `
  17. 17      if(!rst_n) begin
    3 ^5 N- C- i2 ^) ^4 O* ?
  18. 18          rd_flag <= 1'b0;) P. E  {- [$ Q0 c9 {6 m
  19. 19          lcd_id <= 16'd0;
    ! a* W% w: k+ i8 l. R
  20. 20      end    3 J7 B# M! `$ Y7 j% ?+ p. L0 z, z
  21. 21      else begin" Y+ O$ N, r$ k4 n. Q2 u# k
  22. 22          if(rd_flag == 1'b0) begin
    1 Y! ?, L0 s7 \: `4 X3 f1 f
  23. 23              rd_flag <= 1'b1; % f) `/ {4 o/ z3 N  v3 e
  24. 24              case({lcd_rgb[7],lcd_rgb[15],lcd_rgb[23]})
    # L5 S. H5 u5 w+ B' O! a
  25. 25                  3'b000 : lcd_id <= 16'h4342;    //4.3' RGB LCD  RES:480x272
    , a: M; Q: f0 S" e
  26. 26                  3'b001 : lcd_id <= 16'h7084;    //7'   RGB LCD  RES:800x480
    , @& {' ?: [; q) V9 x! c
  27. 27                  3'b010 : lcd_id <= 16'h7016;    //7'   RGB LCD  RES:1024x600
      t+ J5 M+ h$ J3 k3 |4 X* m
  28. 28                  3'b100 : lcd_id <= 16'h4384;    //4.3' RGB LCD  RES:800x480
    : |6 m2 t: c1 v; d* f
  29. 29                  3'b101 : lcd_id <= 16'h1018;    //10'  RGB LCD  RES:1280x800% H. z- c+ H& B& A6 N5 b
  30. 30                  default : lcd_id <= 16'd0;
    5 Q& E' ?4 B, N8 g: w0 V
  31. 31              endcase   
    0 c' g  e4 \' P$ U
  32. 32          end
    ! U! U, s3 n& r6 h
  33. 33      end    - t% Y1 g( \6 w
  34. 34  end" {% V, l! U# V$ ~5 d! p! L
  35. 35  - g9 I7 M2 Y7 |* @$ Q
  36. 36  endmodule
复制代码
. E% P# N; S8 I2 K+ p! Y' r
读取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。
( V# W, n/ x/ Q除此之外,为了方便将LCD的ID和分辨率对应起来,这里对M2、M1和M0的值做了一个译码,如3’b000译码成16’h4342,表示当前连接的是4.3寸屏,分辨率为480*272。其它ID的译码请参考注释。0 g7 w, S. }" ]5 I" x
分频模块的代码如下:1 U+ W, \+ E( L  K6 J: n
& s1 E! S/ {" r- I' K1 T
  1. 1   module clk_div(
    : H3 p+ X, l( J, B9 e5 R
  2. 2       input               clk,          //50Mhz
    . W: p4 j4 ?4 `; s
  3. 3       input               rst_n,
    / p9 M4 h8 X0 S0 b9 b, H
  4. 4       input       [15:0]  lcd_id,( }4 D# {9 n. P  |( D: K. V- v7 K
  5. 5       output  reg         lcd_pclk
    * w  _: d/ k, x! d/ L
  6. 6       );
    ' _- S" k4 v9 e5 ^! Q
  7. 7   
    # F% `- n3 k  j/ ]; o5 D
  8. 8   reg          clk_25m;
    3 ]) u7 }+ l1 P* F& H9 u4 }' R+ ~$ ]
  9. 9   reg          clk_12_5m;
    + K. a9 H7 W$ E$ H
  10. 10  reg          div_4_cnt;
    0 Q* J$ \% ]. m- s' a
  11. 11  
    # G" \5 g9 Y8 |+ @) P% I7 Y
  12. 12  //时钟2分频 输出25MHz时钟
    * V  P3 z! h3 e
  13. 13  always @(posedge clk or negedge rst_n) begin' O9 N; I% L3 Y# v: }0 t; G
  14. 14      if(!rst_n)
    & a0 `1 P1 N- z
  15. 15          clk_25m <= 1'b0;9 ]5 w* I" q4 q& e+ e, o" p/ k
  16. 16      else
    , B. Y, f) C) ~' P& J5 D
  17. 17          clk_25m <= ~clk_25m;1 ?0 }- j. d/ R) n# t
  18. 18  end
    7 c4 h* Z! v5 j- M
  19. 19  
    1 J5 Z) s9 x, R* I
  20. 20  //时钟4分频 输出12.5MHz时钟 9 S9 ]1 E+ H, j# {* Z& P
  21. 21  always @(posedge clk or negedge rst_n) begin
    1 A' D- W8 [* P
  22. 22      if(!rst_n) begin
    4 P( ~" G8 J, R( G+ m9 [
  23. 23          div_4_cnt <= 1'b0;
    2 Q, a# s, J; P/ H- W8 W
  24. 24          clk_12_5m <= 1'b0;
    4 k) {2 H0 v, }- U$ n; V
  25. 25      end   
    - a1 x( H1 e$ u6 f
  26. 26      else begin1 H1 Z0 Y: n. X
  27. 27          div_4_cnt <= div_4_cnt + 1'b1;
    9 U2 {  `# N- i: H  b1 v" y- a
  28. 28          if(div_4_cnt == 1'b1)0 `6 \5 A6 x9 X, M5 J4 H
  29. 29              clk_12_5m <= ~clk_12_5m;
    $ P9 z0 E- x) |, f
  30. 30      end        
    & L4 i& `* ], A0 f, x
  31. 31  end" k% d0 n8 p3 Q2 e
  32. 32  1 J9 d2 z/ R, Y* c  \0 _; f
  33. 33  always @(*) begin
    5 A4 {! J, j: c  L0 G4 {
  34. 34      case(lcd_id)* R, n# E( U8 j! g
  35. 35          16'h4342 : lcd_pclk = clk_12_5m;" r2 G4 y8 `. {. @- K) m3 R
  36. 36          16'h7084 : lcd_pclk = clk_25m;      
    - O- Q) b" m; o  i- _2 z* V
  37. 37          16'h7016 : lcd_pclk = clk;+ t) X, I* m7 P
  38. 38          16'h4384 : lcd_pclk = clk_25m;
    1 \+ I6 r) p6 Q9 F, c) r
  39. 39          16'h1018 : lcd_pclk = clk;9 {* {3 Y1 ]  y5 U( m7 @
  40. 40          default :  lcd_pclk = 1'b0;
    $ M- i" \( V" k, o
  41. 41      endcase      * H; [6 y3 u7 h
  42. 42  end
    ( i. l2 |, i- Q' A* f6 t) a
  43. 43  
    + @) o" X; c& l5 j
  44. 44  endmodule
复制代码
: [* G8 z9 P& ^- N7 w
分频模块根据输入的LCD ID对50Mhz时钟进行分频。由于不同分辨率的LCD屏需要的像素时钟频率不一样,因此分频模块根据输入的LCD ID,来输出不同频率的像素时钟lcd_pclk。需要说明的是,我们在本章简介部分向大家列出了一张表,表格里记录了不同分辨率的屏幕所需的像素时钟频率,为了方便编写分频的代码,我们这里没有严格按照表格里所要求的时钟频率进行输出,而是输出接近于表格所要求的时钟频率。例如10.1寸屏,分辨率1280800,如果刷新率为60Hz的话,需要输出70Mhz的像素时钟,这个时钟频率是无法通过编写代码的方式来得到,而是必须使例化时钟模块MMCM/PLL IP核来得到。因此,对于分辨率为1280800的10.1寸屏幕来说,我们输出的是50Mhz的像素时钟,当然大家使用的是10.1寸屏幕,也可以通过例化时钟模块的方式,来输出一个70Mhz的像素时钟。7 c% \( @' O) j0 o
分频模块通过两个always语句,分别进行2分频和4分频,得到一个25Mhz的时钟和一个12.5Mhz的时钟,如代码中第12行至第31行代码所示。下面我们介绍下如何对输入的时钟进行四分频,也就是50Mhz的时钟四分频后,得到一个12.5Mhz的时钟,其实只需要分频后时钟的周期时原时钟的四倍即可,四分频的波形图如下图所示:* T6 ~0 w& v9 A1 |( B( l3 o
# z9 b7 n. K8 M" V- K" i
80e7c29019b64c13a24c5220355066d2.png
0 B) q& F: Y, [# V: L4 c4 z4 L  [7 I/ [. t6 |3 _/ S; a
图 7.5.13.3 时钟四分频
+ X, u0 t, a3 N( r' g9 ^) L1 r$ }$ K5 C上图中的div_4_cnt用于对系统时钟进行计数,四分频计数器只需要一位位宽,即0和1之间跳变。clk_12_5m高电平和低电平分别占用了两个时钟周期,共占用四个时钟周期,sys_clk的时钟频率为50Mhz,周期为20ns,因此clk_12_5m的时钟周期为80ns,时钟频率为12.5Mhz。' l5 ]5 z& P  K" U' X
在代码的第33行至第42行,通过组合逻辑根据LCD屏的ID选择输出不同频率的像素时钟。2 b) w3 H% S* f8 z
LCD驱动模块的代码如下:9 p% G, Q+ b2 K+ t- m

% V. o5 V" k; h) k" Z7 O1 r
  1. 1   module lcd_driver(" I* K( @$ T; l# l- u
  2. 2       input                lcd_pclk,    //时钟6 }, r& t  S  p
  3. 3       input                rst_n,       //复位,低电平有效
    4 Y% T9 x5 p$ ~; d! |
  4. 4       input        [15:0]  lcd_id,      //LCD屏ID( |# _: k7 ^! R) `
  5. 5       input        [23:0]  pixel_data,  //像素数据
    # ]8 l( c* ]' r/ X! O$ p: t
  6. 6       output       [10:0]  pixel_xpos,  //当前像素点横坐标
    6 B/ F$ Q% _' D7 \+ y
  7. 7       output       [10:0]  pixel_ypos,  //当前像素点纵坐标   6 S, }) S5 Y$ m
  8. 8       output  reg  [10:0]  h_disp,      //LCD屏水平分辨率: d; R7 T. o/ a, j7 v, z
  9. 9       output  reg  [10:0]  v_disp,      //LCD屏垂直分辨率   
    # f  ?8 |. _5 v) a+ t7 |$ @& k) l
  10. 10      //RGB LCD接口
    7 d1 n* d/ X; G4 l9 s" {8 P& N6 N; F
  11. 11      output               lcd_de,      //LCD 数据使能信号" H' V2 {8 n3 z1 A" q. J
  12. 12      output               lcd_hs,      //LCD 行同步信号4 O) |( }2 R8 \0 Y1 D: P; x9 J
  13. 13      output               lcd_vs,      //LCD 场同步信号
    2 P  \6 e" C- y( N5 ~# A" ]
  14. 14      output               lcd_bl,      //LCD 背光控制信号) Z" j! Y2 Q, p* i( j6 L  p1 _
  15. 15      output               lcd_clk,     //LCD 像素时钟1 v) U' I% Q  m( x' R
  16. 16      output               lcd_rst,     //LCD复位
    0 e) D/ Q- H& e; G
  17. 17      output       [23:0]  lcd_rgb      //LCD RGB888颜色数据7 d& C8 T: v! ?( c! _
  18. 18      );$ G/ \; E$ O2 R9 P' f" C# l1 |
  19. 19  
    + C/ k& Q% D  r/ \
  20. 20  //parameter define  : J8 D) J, i* z
  21. 21  // 4.3' 480*272) w  e- |: e$ K# W4 M3 T
  22. 22  parameter  H_SYNC_4342   =  11'd41;     //行同步
    . Y3 S9 I2 z: p
  23. 23  parameter  H_BACK_4342   =  11'd2;      //行显示后沿/ f) V( e8 l2 _% ]  t0 _
  24. 24  parameter  H_DISP_4342   =  11'd480;    //行有效数据6 y' m0 Y+ @" s  X$ c; P
  25. 25  parameter  H_FRONT_4342  =  11'd2;      //行显示前沿
    . e& C2 H2 o! d2 h$ P) d0 Z' S
  26. 26  parameter  H_TOTAL_4342  =  11'd525;    //行扫描周期
    ' R! f" V' h& d( o% [, S* I
  27. 27     % @& W' ^) u" p. `) ], E
  28. 28  parameter  V_SYNC_4342   =  11'd10;     //场同步$ |/ Y7 [3 d/ ]3 G: j
  29. 29  parameter  V_BACK_4342   =  11'd2;      //场显示后沿3 J) Q% ^, D% h4 b
  30. 30  parameter  V_DISP_4342   =  11'd272;    //场有效数据
    3 f3 W: n/ I2 t6 z5 ~- N  N
  31. 31  parameter  V_FRONT_4342  =  11'd2;      //场显示前沿
    , q; X: n0 W0 ?' Q
  32. 32  parameter  V_TOTAL_4342  =  11'd286;    //场扫描周期
    0 K: w. P+ c5 ~4 O0 j5 E( B+ t, x
  33. 代码较长,省略部分源代码……" f0 W1 q/ t) g& w+ r9 u
  34. 86  //reg define! o# |& G/ M$ r2 I$ [! }
  35. 87  reg  [10:0] h_sync ;4 T1 A% v+ |5 }% @: }# l1 o0 v+ m& E4 a
  36. 88  reg  [10:0] h_back ;* G% H( U: Y- x7 X
  37. 89  reg  [10:0] h_total;
    / g5 b5 r) @2 u0 a, Z" `0 f( G. L
  38. 90  reg  [10:0] v_sync ;9 n. N, n% ]- f+ @# c8 N; t
  39. 91  reg  [10:0] v_back ;  k+ S1 G! m3 a( D. Q: r3 Q$ d
  40. 92  reg  [10:0] v_total;! M% n' W$ B! C) {
  41. 93  reg  [10:0] h_cnt  ;
    & R8 n8 O. u. q" _* ~" d. ?
  42. 94  reg  [10:0] v_cnt  ;
    ' i  G% D/ Z4 f8 V/ a1 ]+ _
  43. 95  
    $ r3 b) H7 y8 i% I
  44. 96  //wire define   
    ! N9 l" ^) ~) F+ Z' z& q( ?9 g
  45. 97  wire        lcd_en;
    0 g4 ]- |1 f# T; e  {* o
  46. 98  wire        data_req;
    1 n3 Z+ A2 i! q% ~0 V, x
  47. 99  7 ~2 G( }* s+ u+ g8 S+ u# C9 V
  48. 100 //*****************************************************
    5 ^  H5 M5 e7 e, @
  49. 101 //**                    main code
    , R1 \; U/ _  g1 ]3 P6 \
  50. 102 //****************************************************** K0 e; _2 r) F0 W( Y+ _$ O; e( ]6 N
  51. 103 ! o# O- e- {" x' O6 o' n3 z1 e
  52. 104 //RGB LCD 采用DE模式时,行场同步信号需要拉高
    7 G2 J& n6 U3 G% o2 x
  53. 105 assign  lcd_hs = 1'b1;        //LCD行同步信号$ o2 G5 Q! V& t6 j
  54. 106 assign  lcd_vs = 1'b1;        //LCD场同步信号
    ) S7 D- T, t5 r( U- I0 G" N
  55. 107
    % D6 X! J) v/ K  V( H& Y( Q
  56. 108 assign  lcd_bl = 1'b1;        //LCD背光控制信号  - @9 t" J0 @0 G5 x& Z+ c9 }. U+ i
  57. 109 assign  lcd_clk = lcd_pclk;   //LCD像素时钟3 r$ h- O2 b8 q; i; D# V5 W# R
  58. 110 assign  lcd_rst= 1'b1;        //LCD复位2 _5 v# m' S8 V& Q+ W
  59. 111 assign  lcd_de = lcd_en;      //LCD数据有效信号( u" f: S8 f3 \! i
  60. 112 , |2 S6 m$ L, y% ^# ]
  61. 113 //使能RGB888数据输出
    ! D* O* ^) }: ?: g: F. w* t; s
  62. 114 assign  lcd_en = ((h_cnt >= h_sync + h_back) && (h_cnt < h_sync + h_back + h_disp)
    2 X6 |6 ^3 A; \" n+ i* D1 U$ E
  63. 115                   && (v_cnt >= v_sync + v_back) && (v_cnt < v_sync + v_back + v_disp))
    " F' u$ h8 L" P8 X
  64. 116                   ? 1'b1 : 1'b0;$ D$ t- Y8 L; F; ^9 `5 r5 [
  65. 117 3 f3 c& E; M2 D: d% d+ L+ u4 }
  66. 118 //请求像素点颜色数据输入    ^, R, j$ O4 O$ U! d" @
  67. 119 assign data_req = ((h_cnt >= h_sync + h_back - 1'b1) && (h_cnt < h_sync + h_back + h_disp - 1'b1)
    0 `+ Y  x* X, u; P* S) Y
  68. 120                   && (v_cnt >= v_sync + v_back) && (v_cnt < v_sync + v_back + v_disp))
    7 e1 c$ E6 [" y8 w0 y
  69. 121                   ? 1'b1 : 1'b0;
    9 s: h5 m% D( g0 x
  70. 122 + p7 l1 ]9 C9 ?, ^  [9 k4 n
  71. 123 //像素点坐标  
    2 T* ^( d4 v. A* N) h% w; ^
  72. 124 assign pixel_xpos = data_req ? (h_cnt - (h_sync + h_back - 1'b1)) : 11'd0;
    ! m, S6 w. i' W- s. t! Z
  73. 125 assign pixel_ypos = data_req ? (v_cnt - (v_sync + v_back - 1'b1)) : 11'd0;: |# G( S; N3 t  M
  74. 126 / ?8 e( D8 R2 i3 O
  75. 127 //RGB888数据输出& h- V# m5 f: O" S" P" S% t. ^
  76. 128 assign lcd_rgb = lcd_en ? pixel_data : 24'd0;$ _8 @/ ]6 O  ^: }7 k% O+ h: g
  77. 129 , ]4 X" z; C5 Q
  78. 130 //行场时序参数
    6 t! C5 M8 r# V+ X# A
  79. 131 always @(*) begin% I& y/ H' }% q- e- @
  80. 132     case(lcd_id)
    - j# p3 e# R0 u- J( u
  81. 133         16'h4342 : begin
    0 \) p5 W7 c8 Y% M* F2 f
  82. 134             h_sync  = H_SYNC_4342;
    2 g! H) Y7 W% |* R% j0 N
  83. 135             h_back  = H_BACK_4342; 4 z8 w9 A  K2 h$ H
  84. 136             h_disp  = H_DISP_4342;
    , o7 F4 c' o0 R) W% p- O6 Q- @' [
  85. 137             h_total = H_TOTAL_4342;
    8 T4 C* i; c2 o
  86. 138             v_sync  = V_SYNC_4342; $ I. C% ]/ ^- E4 d; s
  87. 139             v_back  = V_BACK_4342;   q! w/ e8 S" I# m2 {$ D
  88. 140             v_disp  = V_DISP_4342; $ I" W. m* `  ^0 C+ L/ D
  89. 141             v_total = V_TOTAL_4342;            5 b9 G! W$ n- n4 o0 x' W# b
  90. 142         end
复制代码

! q" d  \% B3 G) y5 O) M! f代码较长,省略部分源代码……0 S0 j. e0 `. F8 R$ }5 {$ z/ Z

0 c6 x% P$ j& }7 j+ {9 C0 t3 {* U
  1. 196 //行计数器对像素时钟计数
    1 o. P1 y; B" |. O
  2. 197 always@ (posedge lcd_pclk or negedge rst_n) begin4 w9 A; j6 K" ]
  3. 198     if(!rst_n)
    ! e) M; m6 v, x8 l& r
  4. 199         h_cnt <= 11'd0;
    . c3 q9 c# X/ o: W
  5. 200     else begin2 p: r1 v1 \4 f; g4 a
  6. 201         if(h_cnt == h_total - 1'b1)* M* N! D% H. i; O. }" {: x5 Q
  7. 202             h_cnt <= 11'd0;9 o: X- C$ k/ q% ]' Q. }& L# i4 y, \) M$ ^
  8. 203         else$ M, c* {9 u7 D& E! t
  9. 204             h_cnt <= h_cnt + 1'b1;           
    8 [$ i7 X4 S( G2 M7 z
  10. 205     end+ x# }! Y0 B4 v9 I& H; h4 O
  11. 206 end
    . \( l& e; P( d1 x; L" n# z
  12. 207 5 t- M- ^- A" _) }
  13. 208 //场计数器对行计数
    ' V; o! P% N0 K) S) e/ Q, f9 M4 r! H
  14. 209 always@ (posedge lcd_pclk or negedge rst_n) begin* J9 l$ N) Q( y( T4 K
  15. 210     if(!rst_n)
    6 {3 ?7 t. f; Y# G
  16. 211         v_cnt <= 11'd0;
    - t8 ?4 m# Z; A$ E8 [: x
  17. 212     else begin
    $ s  g1 ~3 n5 L' r; v% h
  18. 213         if(h_cnt == h_total - 1'b1) begin9 {; T3 K+ m  V9 ]6 I
  19. 214             if(v_cnt == v_total - 1'b1). Z  ~/ D8 ^% r/ u, [2 H
  20. 215                 v_cnt <= 11'd0;
    # F0 T4 r% P! G! J1 @& y% o! [
  21. 216             else
    ' X6 P; M4 J0 Q* G. u6 }
  22. 217                 v_cnt <= v_cnt + 1'b1;   
    9 u4 C% b# }, w. A' C& E6 g
  23. 218         end: }* I/ r2 J& D9 m; Z  r+ h( m7 w
  24. 219     end   
      b) t. I5 s  y' y7 W& h; k
  25. 220 end
    1 O6 m: I  C1 @- q# E* J6 i
  26. 221 & y5 Y. D% d* O! f
  27. 222 endmodule
复制代码

# e/ r4 K( y5 b! T- p+ c4 u1 @由本章简介部分可知,在DE模式下,液晶显示屏的同步信号DE对应的是帧和行同时有效的区域段。程序第21行至第84行代码,根据不同分辨率的屏幕做了不同参数的定义,参数的值参考了本章的表 18.1.3。程序第130至194行则根据LCD屏的ID选择不同的时序参数。! g# Z* S2 f$ J" `& i" ?$ o
程序第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拉高。
7 W8 s, ~) t6 b- u: m$ D6 Y. P程序第196至206行通过行计数器h_cnt对像素时钟计数,计满一个行扫描周期后清零并重新开始计数。 程序第208至220行通过场计数器v_cnt对行进行计数,即扫描完一行后v_cnt加1,计满一个场扫描周期后清零并重新开始计数。( A4 c/ y- p& S/ Y& L
将行场计数器的值与LCD时序中的参数作比较,我们就可以判断DE信号何时有效,以及何时输出RGB888格式的图像数据(第113~116行和第128行)。程序第118至125行输出当前像素点的横纵坐标值,由于坐标输出后下一个时钟周期才能接收到像素点的颜色数据,因此数据请求信号data_req比数据输出使能信号lcd_en提前一个时钟周期。# R$ {5 l4 J" M& X
LCD显示模块的代码如下:
4 N9 h. J6 l8 t! |( ?) ?6 l
, O& K0 B: @% q+ p1 R; Z
  1. 1   module lcd_display(! R# o+ `. A1 k; l/ [7 o6 s' t
  2. 2       input                lcd_pclk,    //时钟
    - `9 G( ^2 D1 I5 }) {/ T" A
  3. 3       input                rst_n,       //复位,低电平有效- y; z9 s: }2 J$ D' C( ~1 n
  4. 4       input        [10:0]  pixel_xpos,  //当前像素点横坐标7 V5 w; T3 n; @9 Z3 I; o
  5. 5       input        [10:0]  pixel_ypos,  //当前像素点纵坐标  
    & L) Y4 Q2 r9 @9 y
  6. 6       input        [10:0]  h_disp,      //LCD屏水平分辨率
    ) @( Z' W4 ]. C+ _
  7. 7       input        [10:0]  v_disp,      //LCD屏垂直分辨率       / D" q' W9 C  q8 g3 q% n
  8. 8       output  reg  [23:0]  pixel_data   //像素数据
    ; F) H8 Y4 g7 i" S2 Q
  9. 9       );
    7 G0 h0 s0 W8 d  \; g; D+ H5 {
  10. 10  * K: l; [% m6 @2 j8 Q* T
  11. 11  //parameter define  
    5 V5 G2 w% I$ G: s- r" ^2 S
  12. 12  parameter WHITE = 24'hFFFFFF;  //白色
    2 L$ F: ]0 @0 P( ~
  13. 13  parameter BLACK = 24'h000000;  //黑色
    ' H0 a1 ~$ |6 b2 x% N" d& s
  14. 14  parameter RED   = 24'hFF0000;  //红色
    3 |" u! g$ `# n% i( |; D
  15. 15  parameter GREEN = 24'h00FF00;  //绿色. j. z! a' t" a% I3 f" F
  16. 16  parameter BLUE  = 24'h0000FF;  //蓝色
      `2 j. e0 _# B+ {) V) U- ~8 Y
  17. 17  4 R% d0 H/ I* R; a7 k9 m
  18. 18  //根据当前像素点坐标指定当前像素点颜色数据,在屏幕上显示彩条0 L4 ~$ o  a# V) H: `; T) |
  19. 19  always @(posedge lcd_pclk or negedge rst_n) begin
    ' Z+ H6 ~; t8 S1 Z
  20. 20      if(!rst_n)! V2 T/ e3 h- N
  21. 21          pixel_data <= BLACK;# n( \# f  E& s  z% V  y4 N: T* E
  22. 22      else begin4 h2 G9 b  ~* h* M2 ?
  23. 23          if((pixel_xpos >= 11'd0) && (pixel_xpos < h_disp/5*1))8 ^0 G, Z* l' e) }
  24. 24              pixel_data <= WHITE;; n3 l8 j$ |( z
  25. 25          else if((pixel_xpos >= h_disp/5*1) && (pixel_xpos < h_disp/5*2))   
    . M. \) x0 H9 i+ R' _
  26. 26              pixel_data <= BLACK;( o6 `% B7 d4 V+ ]
  27. 27          else if((pixel_xpos >= h_disp/5*2) && (pixel_xpos < h_disp/5*3))    & `- E, ?% F% e/ M/ P4 E; E9 e0 y8 Q# [
  28. 28              pixel_data <= RED;   
    5 P5 J; ^% ^( E# U. {" q0 K" [- i
  29. 29          else if((pixel_xpos >= h_disp/5*3) && (pixel_xpos < h_disp/5*4))    # w" D5 h) V3 ?4 q9 i
  30. 30              pixel_data <= GREEN;                . H$ g4 O% f5 ^: w2 k5 P+ \
  31. 31          else 0 U/ k+ C  M- ~2 o, ^3 b
  32. 32              pixel_data <= BLUE;      
      d2 `# S$ l. W7 `
  33. 33      end    : _* W3 |! m0 o& }: I: \
  34. 34  end! [& E' b" F- B" j( ^
  35. 35    3 }" l4 R# I/ S
  36. 36  endmodule
复制代码
, X5 k( f- b/ ?6 A" Q/ {2 \
LCD显示模块将屏幕显示区域按照横坐标划分为五列等宽的区域,通过判断像素点的横坐标所在的区域,给像素点赋以不同的颜色值,从而实现彩条显示。
, N/ z; U9 n* }下图为RGB TFT-LCD彩条程序显示一行图像时仿真抓取的波形图,图中包含了一个完整的行扫描周期,其中的有效图像区域被划分为五个不同的区域,不同区域的像素点颜色各不相同。
, c# l0 W3 V; m5 k; s- W
5 I! D& x1 I5 d9 V6 K e866ac56e6994b65874902c16c4ccf5a.png
- m9 v# T$ v& g! F2 s, j* O( i+ ?+ d% w/ m, P
图 7.5.13.4 仿真波形图- s* F) x0 ?8 a; C8 ~1 q
1.5 下载验证' H$ f; i  r7 K' d: I
首先将FPC排线一端与RGB LCD模块上的J1接口连接,另一端与领航者开发板上的RGB TFTLCD接口连接。连接时,先掀开FPC连接器上的黑色翻盖,将FPC排线蓝色面朝上插入连接器,最后将黑色翻盖压下以固定FPC排线,如图 7.5.13.1和图 7.5.13.2所示。
9 l% t) {- }3 d5 y) d# H/ f5 `( q/ y- N/ }$ s# d: n/ _% e! M
37e77994b64e43f19e4c32c7e61207d6.png
2 ]# U! m7 g/ j' k1 T% Q7 P
4 g1 g1 Q2 j( `3 x% y0 J4 n0 D/ R图 7.5.13.1 正点原子RGBLCD模块FPC连接器
" h: W' Z+ a' a8 h" U+ r% ?/ ~. u; P# T
970b8ab3d4c5440e9b26b6a15eaaa2b6.png
0 y8 E8 l0 d; O3 j3 |' d! J: p
0 l; [0 f' i5 f' v1 F( d+ E图 7.5.13.2 领航者开发板连接RGB LCD液晶屏3 C# ^6 K1 ~" r& \3 v
最后将下载器一端连电脑,另一端与开发板上的JTAG端口连接,连接电源线并打开电源开关。3 e6 r9 q9 i" G- @' W1 n- L
接下来我们下载程序,验证RGB TFT-LCD彩条显示功能。下载完成后观察RGB LCD模块显示的图案如下图所示,说明RGB TFT-LCD彩条显示程序下载验证成功。
* f* \' o" n) Q+ L2 F% x
2 }% y# I( L' B: {4 N" L' d. p 16ae23e5613641699b472e95b0910409.png ; @3 ^! Y( }" f. [. Y3 c  E0 ~

7 ?' A" }  N6 }3 i# z  ~图 7.5.13.3 RGB TFT-LCD彩条显示6 X1 `. c% Z- o4 u/ o
————————————————2 X, B7 K' i# V- y7 C& w
版权声明:正点原子
0 C+ j1 M. D+ ^# F. O
# n# @4 @$ Z. V0 m; H5 W
收藏 评论0 发布时间:2022-9-27 16:40

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版