1)实验平台:正点原子新起点V2开发板 2)平台采购地址:https://detail.tmall.com/item.htm?id=609758951113 2)全套实验源码 手册 视频下载地址:http://www.openedv.com/thread-300792-1-1.html 3)正点原子FPGA感兴趣的同学可以加群讨论:99424016 4)关注正点原子微信官方账号,获取最新信息更新
LCD采用薄膜晶体管的液晶显示屏(TFT)提高图像亮度和对比度等技术。与传统相比CRT显示器,LCD它具有重量轻、功耗低、无辐射、图像质量好等优点,广泛应用于电视、电脑显示器、手机等各种显示设备中。 本章包括以下几个部分: 2222.1简介 22.2实验任务 22.3硬件设计 22.4程序设计 22.5下载验证
22.1简介 LCD的全称是Liquid Crystal Display,即液晶显示屏,它显示的每个像素点都是由集成在液晶后面的薄膜晶体管独立驱动,因此LCD响应速度高,图像质量好。正点原子推出RGB-LCD更多的液晶屏,7寸RGB-LCD如下图所示:
图 22.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列,如图 22.1.2所示:
图 22.1.2 像素点排布 上图就是1080P显示器的像素示意图,X轴就是LCD横轴显示器,Y轴是显示器的垂直轴。图中的小方块是像素点,共1920年1080=2073600个像素点。左上角的A点是第一个像素点,右下角的C点是最后一个像素点。K就是25601440个像素点,4K是38402160个像素点。很明显,在LCD分辨率越高越清晰。同样,在分辨率不变的情况下,LCD尺寸越小越清晰。例如,我们常用的24英寸显示器基本上是1080P是的,我们现在用的5寸手机基本都是1080P是的,但是手机的细腻程度比24寸的显示器好很多!由此可见,LCD显示器的分辨率是一个非常重要的参数,但分辨率辨率越高LCD就越好。衡量一款LCD分辨率只是其中一个参数,还有其他参数,如色彩还原度、色彩偏差、亮度、视角、屏幕刷新率等。 2、像素格式 如上所述,一个像素点相当于一个像素点RGB小灯,通过控制R、G、B这三种颜色的亮度可以显示各种颜色。如何控制?R、G、B这三种颜色的显示亮度呢?通常是一个R、G、B这三部分分别使用8bit一个像素点是8bit3=24bit,也就是说,像素点有三个字节,称为像素格式 RGB888,共需要24人,每人对应RGB如下图所示:
图 22.1.3 RGB888数据格式 当然常用的像素点格式还有RGB所以一个像素点是565bit 6bit 5bit=16bit,只需要两个字节,但颜色亮度稍差。我们的新起点开发板受到限制FPGA IO因此,引脚的数量RGB-LCD是的RGB565像素格式,共16位,每位对应RGB如下图所示:
图 22.1.4 RGB565数据格式 这里以RGB以888格式为例,介绍不同的颜色重量。 22.1.3.一个像素点占据三个字节bit23bit16是RED通道,bit15bit8是GREEN通道,bit7~bit0是BLUE通道。所以红色对应的值是24‘hFF蓝色对应的值为24’h0000FF,绿色对应的值为24’h00FF00。通过调节R、G、B比例可以产生其他颜色,如24’hFFFF00就是黄色,24’h黑色是一万,24hFFFFFF就是白色。您可以打开计算机的绘图工具,使用调色板获得所需颜色对应的值,如图所示 22.1.5所示:
图 22.1.5 选择调色板的颜色 3、LCD屏幕接口 LCD屏幕或显示器有多种接口,如显示器上常见的接口VGA、HDMI、DP等等,支持新起点开发板RGB接口的LCD和HDMI接口显示器。本章介绍了RGB-LCD接口,RGB-LCD接口信号线如下表所示: 表 22.1.1 RGB数据线
表 22.1.1就是RGB-LCD的信号线,R[7:0]、G[7:0]和B[7:0]是24位数据,DE、VSYNC、HSYNC和PCLK是四个控制信号。 需要注意的是,正点原子RGB LCD屏幕数据格式为RGB888,新起点板载RGB LCD接口为RGB565格式,即新起点R4R0,对应LCD屏的R7R3;新起点的G5R0,对应LCD屏的G7R2;新起点的B4B0,对应LCD屏的B7B3; 有五种正点原子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-如图所示:
图 22.1.6 RGB-LCD液晶屏幕接口 图中J1就是对外接口,是一个40PIN的FPC座(0.5mm间距),通过FPC线路可以连接到新起点的开发板,从而实现与开发板的连接。接口非常完美,使用RGB支持触摸屏和背光控制的888格式。右侧的电阻并非全部焊接,但用户可以自行选择。默认情况,R1和R6 焊接,设置LCD_LR和LCD_UD,控制LCD扫描方向,从左到右,从上到下(横屏看)。而LCD_R7/G7/B7 则用来设置LCD的ID,由于RGB-LCD没有读写寄存器,就没有所谓的ID,在这里,我们控制模块R7/G7/B7的上/下拉,来自定义LCD模块的ID,帮助MCU判断当前LCD为了提高程序兼容性,面板的分辨率和相关参数。这些位置的设置关系如表所示 22.1.2所示: 表 22.1.2 RGB-LCD模块和ID对应关系
ATK-7016模块,就设置M2:M0 = 010即可。这样,我们在程序里面,读取LCD_R7/G7/B7,得到M0:M2 的值,从而判断RGB-LCD模块的型号,并执行不同的配置,即可实现不同LCD模块的兼容。 4、LCD时间参数 如果将LCD显示一帧图像的过程想象成绘画,那么在显示的过程中就是用一根“笔”在不同的像素点画上不同的颜色。这根笔按照从左至右、从上到下的顺序扫描每个像素点,并且在像素画上对应的颜色,当画到最后一个像素点的时候一幅图像就绘制好了。假如一个LCD的分辨率为1024*600,那么其扫描如图 22.1.7所示:
图 22.1.7 LCD时间参数 结合图 22.1.7我们来看一下LCD是怎么扫描显示一帧图像的。一帧图像也是由一行一行组成的。HSYNC是水平同步信号,也叫做行同步信号,当产生此信号的话就表示开始显示新的一行了,所以此信号都是在图 22.1.7的最左边。VSYNC信号是垂直同步信号,也叫做帧同步信号,当产生此信号的话就表示开始显示新的一帧图像了,所以此信号在图 22.1.7的左上角。 在图 22.1.7可以看到有一圈“黑边”,真正有效的显示区域是中间的白色部分。那这一圈“黑边”是什么东西呢?这就要从显示器的“祖先”CRT显示器开始说起了,CRT显示器就是以前很常见的那种大屁股显示器,在2019年应该很少见了,如果在农村应该还是可以见到的。CRT显示器屁股后面是个电子枪,这个电子枪就是我们上面说的“画笔”,电子枪打出的电子撞击到屏幕上的荧光物质使其发光。只要控制电子枪从左到右扫完一行(也就是扫描一行),然后从上到下扫描完所有行,这样一帧图像就显示出来了。也就是说,显示一帧图像电子枪是按照‘Z’形在运动,当扫描速度很快的时候看起来就是一幅完成的画面了。 当显示完一行以后会发出HSYNC信号,此时电子枪就会关闭,然后迅速的移动到屏幕的左边,当 HSYNC信号结束以后就可以显示新的一行数据了,电子枪就会重新打开。在HSYNC信号结束到电子枪重新打开之间会插入一段延时,这段延时就是图 22.1.7中的HBP。当显示完一行以后就会关闭电子枪等待 HSYNC信号产生,关闭电子枪到HSYNC信号产生之间会插入一段延时,这段延时就是图 22.1.7中的HFP 信号。同理,当显示完一帧图像以后电子枪也会关闭,然后等到VSYNC信号产生,期间也会加入一段延时,这段延时就是图 22.1.7中的VFP。VSYNC信号产生,电子枪移动到左上角,当VSYNC信号结束以后电子枪重新打开,中间也会加入一段延时,这段延时就是图 22.1.7中的VBP。 HBP、HFP、VBP和VFP就是导致图 22.1.7中黑边的原因,但是这是CRT显示器存在黑边的原因,现在是LCD显示器,不需要电子枪了,那么为何还会有黑边呢?这是因为RGB-LCD屏幕内部是有一个IC 的,发送一行或者一帧数据给IC,IC是需要反应时间的。通过这段反应时间可以让IC识别到一行数据扫描完了,要换行了,或者一帧图像扫描完了,要开始下一帧图像显示了。因此,在LCD屏幕中继续存在HBP、HFP、VPB和VFP这四个参数的主要目的是为了锁定有效的像素数据。 5、RGB-LCD屏幕时序 上面介绍了LCD的时间参数,我们接下来看一下行显示对应的时序图,如图 22.1.8所示。
图 22.1.8 LCD行显示时序 图 22.1.8就是RGB-LCD的行显示时序,我们来分析一下其中重要的几个参数: HSYNC:行同步信号,当此信号有效的时候就表示开始显示新的一行数据,查阅所使用的LCD数据手册可以知道此信号是低电平有效还是高电平有效,图 22.1.8为低电平有效。 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的帧显示时序如图 22.1.9所示:
图 22.1.9 LCD帧显示时序 图 22.1.9就是RGB-LCD的帧显示时序,我们来分析一下其中重要的几个参数: VSYNC:帧(场)同步信号,当此信号有效的时候就表示开始显示新的一帧数据,查阅所使用的LCD数据手册可以知道此信号是低电平有效还是高电平有效,图 22.1.9为低电平有效。 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接口的时序图非常相似,只是参数不同,如图 22.1.8和图 22.1.9中的行同步信号(HSYNC)和场同步信号(VSYNC)作为数据的同步信号,此时数据使能信号(DE)必须为低电平。 当选择DE同步模式时,LCD的DE信号作为数据的有效信号,如图 22.1.8和图 22.1.9中的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屏的时序参数,这里整理了不同分辨率的时序参数,如表 22.1.3所示: 表 22.1.3 不同分辨率的LCD时序参数
22.2实验任务 本节的实验任务是使用新起点开发板上的RGB-LCD接口,驱动RGB-LCD液晶屏(支持目前推出的所有RGB-LCD屏),并显示出彩条。 22.3硬件设计 新起点开发板上RGB-LCD接口部分的原理图如下图所示。
图 22.3.1 RGB TFTLCD接口原理图 从上图中可以看到,FPGA管脚输出的颜色数据位宽为16bit,数据格式为RGB565,即R0R4表示红色,G0G5表示绿色,B0~B4表示蓝色。由于这16位数据不仅仅作为输出给LCD屏的颜色数据,同时LCD_R4、LCD_G5和LCD_B4也用来获取LCD屏的ID,因此这16位颜色数据对于新起点开发板来说,是一个双向的引脚。 另外,RGB-LCD模块支持触摸功能,图中以字母T开头的5个信号(T_PEN、T_SCK等)与模块上的触摸芯片相连接。由于本次实验不涉及触摸功能的实现,因此这些信号并未用到。 本实验中,各端口信号的管脚分配如下表所示: 表 22.3.1 RGB-LCD彩条实验管脚分配
对应的管脚分配约束语句如下所示: #系统时钟和复位
set_location_assignment PIN_M2 -to sys_clk
set_location_assignment PIN_M1 -to sys_rst_n
#RGB LCD
set_location_assignment PIN_R1 -to lcd_bl
set_location_assignment PIN_T2 -to lcd_de
set_location_assignment PIN_T3 -to lcd_hs
set_location_assignment PIN_P3 -to lcd_vs
set_location_assignment PIN_R3 -to lcd_clk
set_location_assignment PIN_L1 -to lcd_rst
set_location_assignment PIN_T6 -to lcd_rgb[0]
set_location_assignment PIN_R5 -to lcd_rgb[1]
set_location_assignment PIN_T5 -to lcd_rgb[2]
set_location_assignment PIN_R4 -to lcd_rgb[3]
set_location_assignment PIN_T4 -to lcd_rgb[4]
set_location_assignment PIN_T9 -to lcd_rgb[5]
set_location_assignment PIN_R8 -to lcd_rgb[6]
set_location_assignment PIN_T8 -to lcd_rgb[7]
set_location_assignment PIN_R7 -to lcd_rgb[8]
set_location_assignment PIN_T7 -to lcd_rgb[9]
set_location_assignment PIN_R6 -to lcd_rgb[10]
set_location_assignment PIN_R11 -to lcd_rgb[11]
set_location_assignment PIN_T11 -to lcd_rgb[12]
set_location_assignment PIN_R10 -to lcd_rgb[13]
set_location_assignment PIN_T10 -to lcd_rgb[14]
set_location_assignment PIN_R9 -to lcd_rgb[15]
22.4程序设计 RGB-LCD输入时序包含三个要素:像素时钟、同步信号、以及图像数据,由此我们可以大致规划出系统结构如下图所示。其中,读取ID模块用于获取LCD屏的ID;由于不同分辨率的屏幕需要不同的驱动时钟,因此时钟分频模块根据LCD ID来输出不同频率的像素时钟;LCD显示模块负责产生液晶屏上显示的数据,即彩条数据;LCD驱动模块根据LCD屏的ID,输出不同参数的时序,来驱动LCD屏,并将输入的彩条数据显示到LCD屏上。
图 22.4.1 系统框图 由系统框图可知,FPGA部分包括五个模块,顶层模块(lcd_rgb_colorbar)、读取ID模块(rd_id)、时钟分频模块(clk_div)、LCD显示模块(lcd_display)以及LCD驱动模块(lcd_driver)。其中在顶层模块中完成对其余模块的例化。 各模块端口及信号连接如下图所示:
图 22.4.2 顶层模块原理图 读取ID模块(rd_id)在上电时将RGB双向数据总线设置为输入,来读取LCD屏的ID;时钟分频模块(clk_div)根据读取的ID来配置LCD的像素时钟;LCD驱动模块(lcd_driver)在像素时钟的驱动下输出数据使能信号用于数据同步,同时还输出像素点的纵横坐标,供LCD显示模块(lcd_display)调用,以绘制彩条图案。
1 module lcd_rgb_colorbar(
2 input sys_clk, //系统时钟
3 input sys_rst_n, //系统复位
4
5 //RGB LCD接口
6 output lcd_de, //LCD 数据使能信号
7 output lcd_hs, //LCD 行同步信号
8 output lcd_vs, //LCD 场同步信号
9 output lcd_clk, //LCD 像素时钟
10 inout [15:0] lcd_rgb, //LCD RGB565颜色数据
11 output lcd_rst,
12 output lcd_bl
13
14 );
15
16 wire [15:0] lcd_id ; //LCD屏ID
17 wire lcd_pclk ; //LCD像素时钟
18 wire [10:0] pixel_xpos; //当前像素点横坐标
19 wire [10:0] pixel_ypos; //当前像素点纵坐标
20 wire [10:0] h_disp ; //LCD屏水平分辨率
21 wire [10:0] v_disp ; //LCD屏垂直分辨率
22 wire [15:0] pixel_data; //像素数据
23 wire [15:0] lcd_rgb_o ; //输出的像素数据
24 wire [15:0] lcd_rgb_i ; //输入的像素数据
25
26 //*****************************************************
27 //** main code
28 //*****************************************************
29
30 //像素数据方向切换
31 assign lcd_rgb = lcd_de ? lcd_rgb_o : {
16{
1'bz}};
32 assign lcd_rgb_i = lcd_rgb;
33
34 //读LCD ID模块
35 rd_id u_rd_id(
36 .clk (sys_clk ),
37 .rst_n (sys_rst_n),
38 .lcd_rgb (lcd_rgb_i),
39 .lcd_id (lcd_id )
40 );
41
42 //时钟分频模块
43 clk_div u_clk_div(
44 .clk (sys_clk ),
45 .rst_n (sys_rst_n),
46 .lcd_id (lcd_id ),
47 .lcd_pclk (lcd_pclk )
48 );
49
50 //LCD显示模块
51 lcd_display u_lcd_display(
52 .lcd_pclk (lcd_pclk ),
53 .rst_n (sys_rst_n ),
54 .pixel_xpos (pixel_xpos),
55 .pixel_ypos (pixel_ypos),
56 .h_disp (h_disp ),
57 .v_disp (v_disp ),
58 .pixel_data (pixel_data)
59 );
60
61 //LCD驱动模块
62 lcd_driver u_lcd_driver(
63 .lcd_pclk (lcd_pclk ),
64 .rst_n (sys_rst_n ),
65 .lcd_id (lcd_id ),
66 .pixel_data (pixel_data),
67 .pixel_xpos (pixel_xpos),
68 .pixel_ypos (pixel_ypos),
69 .h_disp (h_disp ),
70 .v_disp (v_disp ),
71
72 .lcd_de (lcd_de ),
73 .lcd_hs (lcd_hs ),
74 .lcd_vs (lcd_vs ),
75 .lcd_clk (lcd_clk ),
76 .lcd_rgb (lcd_rgb_o ),
77 .lcd_rst (lcd_rst ),
78 .lcd_bl (lcd_bl)
79 );
80
81 endmodule
顶层模块主要完成对其他模块的例化。这里需要重点注意第31行代码,由于lcd_rgb是16位的双向引脚,所以这里对双向引脚的方向做一个切换。当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 module rd_id(
2 input clk , //时钟
3 input rst_n , //复位,低电平有效
4 input [15: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:B4 M1:G5 M0:R4
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[4],lcd_rgb[10],lcd_rgb[15]})
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'h0;
31 endcase
32 end
33 end
34 end
35
36 endmodule
读取ID模块根据输入的lcd_rgb值来寄存LCD屏的ID。lcd_rgb[4](B4)、lcd_rgb[10](G5)和lcd_rgb[15](R4)分别对应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_25m;
9 reg clk_12_5m;
10 reg div_4_cnt;
11
12 //时钟2分频 输出25MHz时钟
13 always @(posedge clk or negedge rst_n) begin
14 if(!rst_n)
15 clk_25m <= 1'b0;
16 else
17 clk_25m <= ~clk_25m;
18 end
19
20 //时钟4分频 输出12.5MHz时钟
21 always @(posedge clk or negedge rst_n) begin
22 if(!rst_n) begin
23 div_4_cnt <= 1'b0;
24 clk_12_5m <= 1'b0;
25 end
26 else begin
27 div_4_cnt <= div_4_cnt + 1'b1;
28 if(div_4_cnt == 1'b1)
29 clk_12_5m <= ~clk_12_5m;
30 end
31 end
32
33 always @(*) begin
34 case(lcd_id)
35 16'h4342 : lcd_pclk = clk_12_5m;
36 16'h7084 : lcd_pclk = clk_25m;
37 16'h7016 : lcd_pclk = clk;
38 16'h4384 : lcd_pclk = clk_25m;
39 16'h1018 : lcd_pclk = clk;
40 default : lcd_pclk = 1'b0;
41 endcase
42 end
43
44 endmodule
分频模块根据输入的LCD ID对50Mhz时钟进行分频。由于不同分辨率的LCD屏需要的像素时钟频率不一样,因此分频模块根据输入的LCD ID,来输出不同频率的像素时钟lcd_pclk。需要说明的是,我们在本章简介部分向大家列出了一张表,表格里记录了不同分辨率的屏幕所需的像素时钟频率,为了方便编写分频的代码,我们这里没有严格按照表格里所要求的时钟频率进行输出,而是输出接近于表格所要求的时钟频率。例如10.1寸屏,分辨率1280800,如果刷新率为60Hz的话,需要输出70Mhz的像素时钟,这个时钟频率是无法通过编写代码的方式来得到,而是必须使例化时钟模块PLL IP核来得到。因此,对于分辨率为1280800的10.1寸屏幕来说,我们输出的是50Mhz的像素时钟,当然大家使用的是10.1寸屏幕,也可以通过例化时钟模块的方式,来输出一个70Mhz的像素时钟。 分频模块通过两个always语句,分别进行2分频和4分频,得到一个25Mhz的时钟和一个12.5Mhz的时钟,如代码中第12行至第31行代码所示。下面我们介绍下如何对输入的时钟进行四分频,也就是50Mhz的时钟四分频后,得到一个12.5Mhz的时钟,其实只需要分频后时钟的周期是原时钟的四倍即可。 在代码的第33行至第42行,通过组合逻辑根据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 [15: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 reg lcd_bl, //LCD 背光控制信号
15 output lcd_clk, //LCD 像素时钟
16 output [15:0] lcd_rgb, //LCD RGB565颜色数据
17 output reg lcd_rst //LCD 复位,低电平有效
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; //场扫描周期
代码较长,省略部分源代码……
86 //reg define
87 reg [10:0] h_sync ;
88 reg [10:0] h_back ;
89 reg [10:0] h_total;
90 reg [10:0] v_sync ;
91 reg [10:0] v_back ;
92 reg [10:0] v_total;
93 reg [10:0] h_cnt ;
94 reg [10:0] v_cnt ;
95
96 //wire define
97 wire lcd_en;
98 wire data_req;
99
100 //*****************************************************
101 //** main code
102 //*****************************************************
103
104 //RGB LCD 采用DE模式时,行场同步信号需要拉高
105 assign lcd_hs = 1'b1; //LCD行同步信号
106 assign lcd_vs = 1'b1; //LCD场同步信号
107
108 assign lcd_clk = lcd_pclk; //LCD像素时钟
109 assign lcd_de = lcd_en; //LCD数据有效信号
110
111 //使能RGB565数据输出
112 assign lcd_en = ((h_cnt >= h_sync + h_back) && (h_cnt < h_sync + h_back + h_disp)
113 && (v_cnt >= v_sync + v_back) && (v_cnt < v_sync + v_back + v_disp))
114 ? 1'b1 : 1'b0;
115
116 //请求像素点颜色数据输入
117 assign data_req =((h_cnt>=h_sync + h_back - 1
标签: 21pin翻盖连接器