搜索
bottom↓
回复: 0

【正点原子FPGA连载】第二十一章RGB-LCD彩条显示实验

[复制链接]

出0入234汤圆

发表于 2021-1-29 10:57:20 | 显示全部楼层 |阅读模式
1)实验平台:正点原子超越者FPGA开发板
2)  章节摘自【正点原子】超越者之FPGA开发指南
3)购买链接:https://item.taobao.com/item.htm?&id=631660290421
4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/fpga/zdyz-chaoyuezhe.html
5)正点原子官方B站:https://space.bilibili.com/394620890
6)正点原子FPGA技术交流群:905624739
QQ群头像.png

100846rel79a9p4uelap24.jpg

100846f1ce1fg14zbg0va4.png

第二十一章RGB-LCD彩条显示实验


LCD是一种液晶显示屏,它采用薄膜晶体管(TFT)技术提升图像质量,如提高图像亮度和对比度等。相比于传统的CRT显示器,LCD有着轻薄、功耗低、无辐射、图像质量好等诸多优点,因此广泛应用于电视机、电脑显示器、手机等各种显示设备中。
本章包括以下几个部分:
2121.1  简介
21.2  实验任务
21.3  硬件设计
21.4  程序设计
21.5  下载验证


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

图 21.1.1 ATK-7’RGB接口液晶屏模块

液晶显示器是现在最常用到的显示器,手机、电脑、各种人机交互设备等基本都用到了LCD,最常见的就是手机和电脑显示器了。由于笔者不是LCD从业人员,对于LCD的具体原理不了解,百度百科对于 LCD的原理解释如下:
LCD的构造是在两片平行的玻璃基板当中放置液晶盒,下基板玻璃上设置 TFT(薄膜晶体管),上基板玻璃上设置彩色滤光片,通过TFT上的信号与电压改变来控制液晶分子的转动方向,从而达到控制每个像素点偏振光出射与否而达到显示目的。我们现在要在超越者开发板上使用LCD,所以不需要去研究LCD 的具体实现原理,我们只需要从使用的角度去关注 LCD 的几个重要点:
1、分辨率
提起LCD显示器,我们都会听到720P、1080P、2K或4K这样的字眼,这个就是LCD显示器分辨率。 LCD显示器都是由一个一个的像素点组成,像素点就类似一个灯(在OLED显示器中,像素点就是一个小灯),这个小灯是RGB灯,也就是由R(红色)、G(绿色)和B(蓝色)这三种颜色组成的,而RGB就是光的三原色。 1080P的意思就是一个LCD屏幕上的像素数量是1920*1080个,也就是这个屏幕一列1080个像素点,一共 1920列,如图 21.1.2所示:
21944.png

图 21.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,只需要两个字节,但在色彩鲜艳度上较差一些。我们超越者开发板上的RGB-LCD接口采用的RGB888的像素格式,共需要24位,每一位对应RGB的颜色分量如下图所示:
211636.png

图 21.1.3 RGB888数据格式

在图 21.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就是白色。大家可以打开电脑的“画图”工具,在里面使用调色板即可获取到想要的颜色对应的数值,如图 21.1.4所示:
212008.png

图 21.1.4 调色板颜色选取

3、LCD屏幕接口
LCD屏幕或者说显示器有很多种接口,比如在显示器上常见的VGA、HDMI、DP等等,超越者开发板支持RGB接口的LCD和HDMI接口的显示器。本章我们介绍的是RGB-LCD接口,RGB-LCD接口的信号线如下表所示:
表 21.1.1 RGB数据线
2111.png

表 21.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的屏幕接口原理图如下图所示:

212641.png

图 21.1.5 RGB-LCD液晶屏幕接口

图中RGB TFT LCD就是对外接口,是一个40PIN的FPC座(0.5mm间距),通过FPC线,可以连接到超越者开发板上面,从而实现和开发板的连接。该接口十分完善,采用RGB888格式,并支持触摸屏和背光控制。LCD_R7/G7/B7 则用来设置LCD的ID,由于RGB-LCD没有读写寄存器,也就没有所谓的ID,这里我们通过在模块上面,控制R7/G7/B7的上/下拉,来自定义LCD模块的ID,帮助FPGA判断当前LCD面板的分辨率和相关参数,以提高程序兼容性。这几个位的设置关系如表 21.1.2所示:
表 21.1.2 RGB-LCD模块和ID对应关系
2112.png

这样,我们在程序里面,读取LCD_R7/G7/B7,得到M0:M2 的值,从而判断RGB-LCD模块的型号,并执行不同的配置,即可实现不同LCD模块的兼容。
4、LCD时间参数
如果将LCD显示一帧图像的过程想象成绘画,那么在显示的过程中就是用一根“笔”在不同的像素点画上不同的颜色。这根笔按照从左至右、从上到下的顺序扫描每个像素点,并且在像素画上对应的颜色,当画到最后一个像素点的时候一幅图像就绘制好了。假如一个LCD的分辨率为1024*600,那么其扫描如图 21.1.6所示:
213598.png

图 21.1.6 LCD时间参数

结合图 21.1.6我们来看一下LCD是怎么扫描显示一帧图像的。一帧图像也是由一行一行组成的。HSYNC是水平同步信号,也叫做行同步信号,当产生此信号的话就表示开始显示新的一行了,所以此信号都是在图 21.1.6的最左边。VSYNC信号是垂直同步信号,也叫做帧同步信号,当产生此信号的话就表示开始显示新的一帧图像了,所以此信号在图 21.1.6的左上角。
在图 21.1.6可以看到有一圈“黑边”,真正有效的显示区域是中间的白色部分。那这一圈“黑边”是什么东西呢?这就要从显示器的“祖先”CRT显示器开始说起了,CRT显示器就是以前很常见的那种大屁股显示器,在2019年应该很少见了,如果在农村应该还是可以见到的。CRT显示器屁股后面是个电子枪,这个电子枪就是我们上面说的“画笔”,电子枪打出的电子撞击到屏幕上的荧光物质使其发光。只要控制电子枪从左到右扫完一行(也就是扫描一行),然后从上到下扫描完所有行,这样一帧图像就显示出来了。也就是说,显示一帧图像电子枪是按照‘Z’形在运动,当扫描速度很快的时候看起来就是一幅完成的画面了。
当显示完一行以后会发出HSYNC信号,此时电子枪就会关闭,然后迅速的移动到屏幕的左边,当 HSYNC信号结束以后就可以显示新的一行数据了,电子枪就会重新打开。在HSYNC信号结束到电子枪重新打开之间会插入一段延时,这段延时就是图 21.1.6中的HBP。当显示完一行以后就会关闭电子枪等待 HSYNC信号产生,关闭电子枪到HSYNC信号产生之间会插入一段延时,这段延时就是图 21.1.6中的HFP 信号。同理,当显示完一帧图像以后电子枪也会关闭,然后等到VSYNC信号产生,期间也会加入一段延时,这段延时就是图 21.1.6中的VFP。VSYNC信号产生,电子枪移动到左上角,当VSYNC信号结束以后电子枪重新打开,中间也会加入一段延时,这段延时就是图 21.1.6中的VBP。
HBP、HFP、VBP和VFP就是导致图 21.1.6中黑边的原因,但是这是CRT显示器存在黑边的原因,现在是LCD显示器,不需要电子枪了,那么为何还会有黑边呢?这是因为RGB-LCD屏幕内部是有一个IC 的,发送一行或者一帧数据给IC,IC是需要反应时间的。通过这段反应时间可以让IC识别到一行数据扫描完了,要换行了,或者一帧图像扫描完了,要开始下一帧图像显示了。因此,在LCD屏幕中继续存在HBP、HFP、VPB和VFP这四个参数的主要目的是为了锁定有效的像素数据。
5、RGB-LCD屏幕时序
上面介绍了LCD的时间参数,我们接下来看一下行显示对应的时序图,如图 21.1.7所示。
215002.png

图 21.1.7 LCD行显示时序

图 21.1.7就是RGB-LCD的行显示时序,我们来分析一下其中重要的几个参数:
HSYNC:行同步信号,当此信号有效的时候就表示开始显示新的一行数据,查阅所使用的LCD数据手册可以知道此信号是低电平有效还是高电平有效,图 21.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的帧显示时序如图 21.1.8所示:
215612.png

图 21.1.8 LCD帧显示时序

图 21.1.8就是RGB-LCD的帧显示时序,我们来分析一下其中重要的几个参数:
VSYNC:帧(场)同步信号,当此信号有效的时候就表示开始显示新的一帧数据,查阅所使用的LCD数据手册可以知道此信号是低电平有效还是高电平有效,图 21.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接口的时序图非常相似,只是参数不同,如图 21.1.7和图 21.1.8中的行同步信号(HSYNC)和场同步信号(VSYNC)作为数据的同步信号,此时数据使能信号(DE)必须为低电平。
当选择DE同步模式时,LCD的DE信号作为数据的有效信号,如图 21.1.7和图 21.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屏的时序参数,这里整理了不同分辨率的时序参数,如表 21.1.3所示:
表 21.1.3 不同分辨率的LCD时序参数
2113.png

21.2实验任务
本节的实验任务是使用超越者开发板上的RGB-LCD接口,驱动RGB-LCD液晶屏(支持目前推出的所有RGB-LCD屏),并显示出彩条。
21.3硬件设计
超越者开发板上RGB-LCD接口部分的原理图如下图所示。
217611.png

图 21.3.1 RGB TFTLCD接口原理图

从上图中可以看到,FPGA管脚输出的颜色数据位宽为24bit,数据格式为RGB888,即数据高8位表示红色,中间8位表示绿色,低8位表示蓝色。由于这24位数据不仅仅作为输出给LCD屏的颜色数据,同时LCD_R7、LCD_G7和LCD_B7也用来获取LCD屏的ID,因此这24位颜色数据对超越者开发板来说,是一个双向的引脚。
另外,RGB-LCD模块支持触摸功能,图中以字母T开头的5个信号(T_PEN、T_SCK等)与模块上的触摸芯片相连接。由于本次实验不涉及触摸功能的实现,因此这些信号并未用到。
本实验中,各端口信号的管脚分配如下表所示:
表 21.3.1 RGB-LCD彩条实验管脚分配
2131.png

对应的UCF约束语句如下所示:
  1. NET "lcd_rgb[23]" LOC = A7 | IOSTANDARD = "LVCMOS33";
  2. NET "lcd_rgb[22]" LOC = B6 | IOSTANDARD = "LVCMOS33";
  3. NET "lcd_rgb[21]" LOC = A6 | IOSTANDARD = "LVCMOS33";
  4. NET "lcd_rgb[20]" LOC = B5 | IOSTANDARD = "LVCMOS33";
  5. NET "lcd_rgb[19]" LOC = A5 | IOSTANDARD = "LVCMOS33";
  6. NET "lcd_rgb[18]" LOC = C4 | IOSTANDARD = "LVCMOS33";
  7. NET "lcd_rgb[17]" LOC = A4 | IOSTANDARD = "LVCMOS33";
  8. NET "lcd_rgb[16]" LOC = C5 | IOSTANDARD = "LVCMOS33";
  9. NET "lcd_rgb[15]" LOC = A11 | IOSTANDARD = "LVCMOS33";
  10. NET "lcd_rgb[14]" LOC = B10 | IOSTANDARD = "LVCMOS33";
  11. NET "lcd_rgb[13]" LOC = A10 | IOSTANDARD = "LVCMOS33";
  12. NET "lcd_rgb[12]" LOC = C9 | IOSTANDARD = "LVCMOS33";
  13. NET "lcd_rgb[11]" LOC = A9 | IOSTANDARD = "LVCMOS33";
  14. NET "lcd_rgb[10]" LOC = B8 | IOSTANDARD = "LVCMOS33";
  15. NET "lcd_rgb[9]" LOC = A8 | IOSTANDARD = "LVCMOS33";
  16. NET "lcd_rgb[8]" LOC = C7 | IOSTANDARD = "LVCMOS33";
  17. NET "lcd_rgb[7]" LOC = F14 | IOSTANDARD = "LVCMOS33";
  18. NET "lcd_rgb[6]" LOC = B14 | IOSTANDARD = "LVCMOS33";
  19. NET "lcd_rgb[5]" LOC = A14 | IOSTANDARD = "LVCMOS33";
  20. NET "lcd_rgb[4]" LOC = C13 | IOSTANDARD = "LVCMOS33";
  21. NET "lcd_rgb[3]" LOC = A13 | IOSTANDARD = "LVCMOS33";
  22. NET "lcd_rgb[2]" LOC = B12 | IOSTANDARD = "LVCMOS33";
  23. NET "lcd_rgb[1]" LOC = A12 | IOSTANDARD = "LVCMOS33";
  24. NET "lcd_rgb[0]" LOC = C11 | IOSTANDARD = "LVCMOS33";
  25. NET "lcd_bl" LOC = D16 | IOSTANDARD = "LVCMOS33";
  26. NET "lcd_clk" LOC = B15 | IOSTANDARD = "LVCMOS33";
  27. NET "lcd_de" LOC = C15 | IOSTANDARD = "LVCMOS33";
  28. NET "lcd_hs" LOC = B16 | IOSTANDARD = "LVCMOS33";
  29. NET "lcd_vs" LOC = C16 | IOSTANDARD = "LVCMOS33";
  30. NET "sys_clk" LOC = N8 | IOSTANDARD = "LVCMOS33";
  31. NET "sys_rst_n" LOC = G16 | IOSTANDARD = "LVCMOS33";
复制代码

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

图 21.4.1 系统框图

由系统框图可知,FPGA部分包括五个模块,顶层模块(lcd_rgb_colorbar)、读取ID模块(rd_id)、时钟分频模块(clk_div)、LCD显示模块(lcd_display)以及LCD驱动模块(lcd_driver)。其中在顶层模块中完成对其余模块的例化。
读取ID模块(rd_id)在上电时将RGB双向数据总线设置为输入,来读取LCD屏的ID;时钟分频模块(clk_div)根据读取的ID来配置LCD的像素时钟;LCD驱动模块(lcd_driver)在像素时钟的驱动下输出数据使能信号用于数据同步,同时还输出像素点的纵横坐标,供LCD显示模块(lcd_display)调用,以绘制彩条图案。
顶层模块的代码如下:
  1. 1  module lcd_rgb_colorbar(
  2. 2      input                sys_clk,     //系统时钟
  3. 3      input                sys_rst_n,   //系统复位
  4. 4  
  5. 5      //RGB LCD接口
  6. 6      output               lcd_de,      //LCD 数据使能信号
  7. 7      output               lcd_hs,      //LCD 行同步信号
  8. 8      output               lcd_vs,      //LCD 场同步信号
  9. 9      output               lcd_clk,     //LCD 像素时钟
  10. 10     inout        [23:0]  lcd_rgb,     //LCD RGB888颜色数据
  11. 11     output               lcd_bl
  12. 12     
  13. 13     );                                                      
  14. 14
  15. 15 wire  [15:0]  lcd_id    ;    //LCD屏ID
  16. 16 wire          lcd_pclk  ;    //LCD像素时钟              
  17. 17 wire  [10:0]  pixel_xpos;    //当前像素点横坐标
  18. 18 wire  [10:0]  pixel_ypos;    //当前像素点纵坐标
  19. 19 wire  [10:0]  h_disp    ;    //LCD屏水平分辨率
  20. 20 wire  [10:0]  v_disp    ;    //LCD屏垂直分辨率
  21. 21 wire  [23:0]  pixel_data;    //像素数据
  22. 22 wire  [23:0]  lcd_rgb_o ;    //输出的像素数据
  23. 23 wire  [23:0]  lcd_rgb_i ;    //输入的像素数据
  24. 24
  25. 25 //*****************************************************
  26. 26 //**                    main code
  27. 27 //*****************************************************
  28. 28
  29. 29 //像素数据方向切换
  30. 30 assign lcd_rgb = lcd_de ?  lcd_rgb_o :  {24{1'bz}};
  31. 31 assign lcd_rgb_i = lcd_rgb;
  32. 32
  33. 33 //pll模块
  34. 34 pll u_pll
  35. 35     (// Clock in ports
  36. 36     .CLK_IN1      (sys_clk),      // IN
  37. 37     // Clock out ports
  38. 38     .CLK_OUT1     (clk_100m));  
  39. 39
  40. 40 //读LCD ID模块
  41. 41 rd_id u_rd_id(
  42. 42     .clk          (clk_100m  ),
  43. 43     .rst_n        (sys_rst_n),
  44. 44     .lcd_rgb      (lcd_rgb_i),
  45. 45     .lcd_id       (lcd_id   )
  46. 46     );   
  47. 47
  48. 48 //时钟分频模块   
  49. 49 clk_div u_clk_div(
  50. 50     .clk           (clk_100m  ),
  51. 51     .rst_n         (sys_rst_n),
  52. 52     .lcd_id        (lcd_id   ),
  53. 53     .lcd_pclk      (lcd_pclk )
  54. 54     );   
  55. 55
  56. 56 //LCD显示模块   
  57. 57 lcd_display u_lcd_display(
  58. 58     .lcd_pclk       (lcd_pclk  ),
  59. 59     .rst_n          (sys_rst_n ),
  60. 60     .pixel_xpos     (pixel_xpos),
  61. 61     .pixel_ypos     (pixel_ypos),
  62. 62     .h_disp         (h_disp    ),
  63. 63     .v_disp         (v_disp    ),
  64. 64     .pixel_data     (pixel_data)
  65. 65     );   
  66. 66
  67. 67 //LCD驱动模块
  68. 68 lcd_driver u_lcd_driver(
  69. 69     .lcd_pclk      (lcd_pclk  ),
  70. 70     .rst_n         (sys_rst_n ),
  71. 71     .lcd_id        (lcd_id    ),
  72. 72     .pixel_data    (pixel_data),
  73. 73     .pixel_xpos    (pixel_xpos),
  74. 74     .pixel_ypos    (pixel_ypos),
  75. 75     .h_disp        (h_disp    ),
  76. 76     .v_disp        (v_disp    ),
  77. 77
  78. 78     .lcd_de        (lcd_de    ),
  79. 79     .lcd_hs        (lcd_hs    ),
  80. 80     .lcd_vs        (lcd_vs    ),   
  81. 81     .lcd_clk       (lcd_clk   ),
  82. 82     .lcd_rgb       (lcd_rgb_o ),
  83. 83     .lcd_rst       (lcd_rst   ),
  84. 84     .lcd_bl        (lcd_bl)
  85. 85     );
  86. 86
  87. 87 endmodule
复制代码

顶层模块主要完成对其他模块的例化。这里需要重点注意第30行代码,由于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。
读取ID模块的代码如下:
  1. 1  module rd_id(
  2. 2      input                   clk    ,    //时钟
  3. 3      input                   rst_n  ,    //复位,低电平有效
  4. 4      input           [23:0]  lcd_rgb,    //RGB LCD像素数据,用于读取ID
  5. 5      output   reg    [15:0]  lcd_id      //LCD屏ID
  6. 6      );
  7. 7  
  8. 8  //reg define
  9. 9  reg     [7:0]       rd_flag;  //读ID标志
  10. 10 //*****************************************************
  11. 11 //**                    main code
  12. 12 //*****************************************************
  13. 13
  14. 14 //获取LCD ID   M2:B7  M1:G7  M0:R7
  15. 15 always @(posedge clk or negedge rst_n) begin
  16. 16     if(!rst_n) begin
  17. 17         rd_flag <= 8'b0;
  18. 18         lcd_id <= 16'd0;
  19. 19     end   
  20. 20     else begin
  21. 21      rd_flag <= {rd_flag[6:0],1'b1};
  22. 22         if(rd_flag == 8'h3f) begin
  23. 23             case({lcd_rgb[7],lcd_rgb[15],lcd_rgb[23]})
  24. 24                 3'b000 : lcd_id <= 16'h4342;    //4.3' RGB LCD  RES:480x272
  25. 25                 3'b001 : lcd_id <= 16'h7084;    //7'   RGB LCD  RES:800x480
  26. 26                 3'b010 : lcd_id <= 16'h7016;    //7'   RGB LCD  RES:1024x600
  27. 27                 3'b100 : lcd_id <= 16'h4384;    //4.3' RGB LCD  RES:800x480
  28. 28                 3'b101 : lcd_id <= 16'h1018;    //10'  RGB LCD  RES:1280x800
  29. 29                 default : lcd_id <= 16'h4342;
  30. 30             endcase   
  31. 31         end
  32. 32     end   
  33. 33 end
  34. 34
  35. 35 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等于8’h3f时,获取一次ID而当rd_flag等于其他值时,不再获取LCD屏的ID。
除此之外,为了方便将LCD的ID和分辨率对应起来,这里对M2、M1和M0的值做了一个译码,如3’b000译码成16’h4342,表示当前连接的是4.3寸屏,分辨率为480*272。其它ID的译码请参考注释。
分频模块的代码如下:
  1. 1  module clk_div(
  2. 2      input               clk,          //100Mhz
  3. 3      input               rst_n,
  4. 4      input       [15:0]  lcd_id,
  5. 5      output  reg         lcd_pclk
  6. 6      );
  7. 7  
  8. 8  //reg define
  9. 9  reg          clk_50m;
  10. 10 reg          clk_25m;
  11. 11 reg          clk_12_5m;
  12. 12 reg          div_4_cnt;
  13. 13 reg   [1:0]  div_8_cnt;
  14. 14
  15. 15 //*****************************************************
  16. 16 //**                    main code
  17. 17 //*****************************************************
  18. 18
  19. 19 //时钟2分频 输出50MHz时钟
  20. 20 always @(posedge clk or negedge rst_n) begin
  21. 21     if(!rst_n)
  22. 22         clk_50m <= 1'b0;
  23. 23     else
  24. 24         clk_50m <= ~clk_50m;
  25. 25 end
  26. 26
  27. 27 //时钟4分频 输出25MHz时钟
  28. 28 always @(posedge clk or negedge rst_n) begin
  29. 29     if(!rst_n) begin
  30. 30         div_4_cnt <= 1'b0;
  31. 31         clk_25m <= 1'b0;
  32. 32     end   
  33. 33     else begin
  34. 34         div_4_cnt <= div_4_cnt + 1'b1;
  35. 35         if(div_4_cnt == 1'b1)
  36. 36             clk_25m <= ~clk_25m;
  37. 37     end        
  38. 38 end
  39. 39
  40. 40 //时钟8分频 输出12.5MHz时钟
  41. 41 always @(posedge clk or negedge rst_n) begin
  42. 42     if(!rst_n) begin
  43. 43         div_8_cnt <= 1'b0;
  44. 44         clk_12_5m <= 1'b0;
  45. 45     end   
  46. 46     else begin
  47. 47         div_8_cnt <= div_8_cnt + 1'b1;
  48. 48         if(div_8_cnt == 2'd3)
  49. 49             clk_12_5m <= ~clk_12_5m;
  50. 50     end        
  51. 51 end
  52. 52
  53. 53 always @(*) begin
  54. 54     case(lcd_id)
  55. 55         16'h4342 : lcd_pclk = clk_12_5m;
  56. 56         16'h7084 : lcd_pclk = clk_25m;      
  57. 57         16'h7016 : lcd_pclk = clk_50m;
  58. 58         16'h4384 : lcd_pclk = clk_25m;
  59. 59         16'h1018 : lcd_pclk = clk_50m;
  60. 60         default :  lcd_pclk = 1'b0;
  61. 61     endcase      
  62. 62 end
  63. 63
  64. 64 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的像素时钟。
分频模块通过3个always语句,分别进行2分频、4分频和8分频,得到一个50Mhz的时钟、25Mhz的时钟和一个12.5Mhz的时钟,如代码中第19行至第51行代码所示。下面我们介绍下如何对输入的时钟进行四分频,也就是100Mhz的时钟四分频后,得到一个25Mhz的时钟,其实只需要分频后时钟的周期时原时钟的四倍即可,用modelsim仿真得到的四分频的波形图如下图所示(tb文件在lcd_rgb_colorbar/sim/tb文件夹下):
2118493.png

图 21.4.2 时钟四分频

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

由本章简介部分可知,在DE模式下,液晶显示屏的同步信号DE对应的是帧和行同时有效的区域段。程序第21行至第85行代码,根据不同分辨率的屏幕做了不同参数的定义,参数的值参考了本章的表 21.1.3。程序第130至194行则根据LCD屏的ID选择不同的时序参数。
程序第105至111行是LCD驱动模块输出的液晶屏控制信号。其中lcd_bl为液晶屏背光控制端口,可以利用该端口输出一个频率在200Hz~1kHz范围之内的PWM(脉冲宽度调制)信号,通过调整PWM信号的占空比来调节液晶屏的显示亮度。分频模块输出的lcd_pclk直接赋值给LCD屏的lcd_clk(像素时钟)引脚,为RGB-LCD屏提供驱动时钟。另外由于我们采用DE同步模式驱动RGB-LCD屏,输出给LCD的数据使能信号lcd_de在图像数据有效时拉高,因此可以将模块内部的lcd_en信号直接赋值给lcd_de。另外在DE模式下,需要将输出给LCD的行场同步信号lcd_hs、lcd_vs拉高。
程序第196至206行通过行计数器h_cnt对像素时钟计数,计满一个行扫描周期后清零并重新开始计数。 程序第208至220行通过场计数器v_cnt对行进行计数,即扫描完一行后v_cnt加1,计满一个场扫描周期后清零并重新开始计数。
将行场计数器的值与LCD时序中的参数作比较,我们就可以判断DE信号何时有效,以及何时输出RGB888格式的图像数据(第113~116行和第128行)。程序第118至125行输出当前像素点的横纵坐标值,由于坐标输出后下一个时钟周期才能接收到像素点的颜色数据,因此数据请求信号data_req比数据输出使能信号lcd_en提前一个时钟周期。
LCD显示模块的代码如下:
  1. 1  module lcd_display(
  2. 2      input                lcd_pclk,    //时钟
  3. 3      input                rst_n,       //复位,低电平有效
  4. 4      input        [10:0]  pixel_xpos,  //当前像素点横坐标
  5. 5      input        [10:0]  pixel_ypos,  //当前像素点纵坐标  
  6. 6      input        [10:0]  h_disp,      //LCD屏水平分辨率
  7. 7      input        [10:0]  v_disp,      //LCD屏垂直分辨率      
  8. 8      output  reg  [23:0]  pixel_data   //像素数据
  9. 9      );
  10. 10
  11. 11 //parameter define  
  12. 12 parameter WHITE = 24'hFFFFFF;  //白色
  13. 13 parameter BLACK = 24'h000000;  //黑色
  14. 14 parameter RED   = 24'hFF0000;  //红色
  15. 15 parameter GREEN = 24'h00FF00;  //绿色
  16. 16 parameter BLUE  = 24'h0000FF;  //蓝色
  17. 17
  18. 18 //根据当前像素点坐标指定当前像素点颜色数据,在屏幕上显示彩条
  19. 19 always @(posedge lcd_pclk or negedge rst_n) begin
  20. 20     if(!rst_n)
  21. 21         pixel_data <= BLACK;
  22. 22     else begin
  23. 23         if((pixel_xpos >= 11'd0) && (pixel_xpos < h_disp/5*1))
  24. 24             pixel_data <= WHITE;
  25. 25         else if((pixel_xpos >= h_disp/5*1) && (pixel_xpos < h_disp/5*2))   
  26. 26             pixel_data <= BLACK;
  27. 27         else if((pixel_xpos >= h_disp/5*2) && (pixel_xpos < h_disp/5*3))   
  28. 28             pixel_data <= RED;   
  29. 29         else if((pixel_xpos >= h_disp/5*3) && (pixel_xpos < h_disp/5*4))   
  30. 30             pixel_data <= GREEN;               
  31. 31         else
  32. 32             pixel_data <= BLUE;      
  33. 33     end   
  34. 34 end
  35. 35   
  36. 36 endmodule
复制代码

LCD显示模块将屏幕显示区域按照横坐标划分为五列等宽的区域,通过判断像素点的横坐标所在的区域,给像素点赋以不同的颜色值,从而实现彩条显示。
下图为RGB-LCD彩条程序显示一行图像时仿真抓取的波形图,图中包含了一个完整的行扫描周期,其中的有效图像区域被划分为五个不同的区域,不同区域的像素点颜色各不相同。用modelsim仿真得到的波形图如下图所示(tb文件在lcd_rgb_colorbar/sim/tb文件夹下):
2129519.png

图 21.4.3 仿真波形图


21.5下载验证
首先将FPC排线一端与RGB-LCD连接,另一端与超越者开发板上的RGB -LCD接口连接。连接时,先掀开FPC连接器上的黑色翻盖,将FPC排线蓝色面朝上插入连接器,最后将黑色翻盖压下以固定FPC排线,如图 21.5.1和图 21.5.2所示。
2129788.png

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

2129861.png

图 21.5.2 超越者开发板连接RGB-LCD液晶屏

接下来分别连接JTAG接口和电源线,最后将下载器一端连电脑,另一端与开发板上的JTAG端口连接,连接电源线并打开电源开关。
接下来我们下载程序,验证RGB-LCD彩条显示功能。下载完成后观察RGB-LCD模块显示的图案如下图所示,说明RGB-LCD彩条显示程序下载验证成功。
2130072.png

图 21.5.3 RGB-LCD彩条显示


阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-25 21:43

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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