RGB LCD 彩条显示实验 —1
TFT-LCD 的全称是 Thin Film Transistor-Liquid Crystal Display,即薄膜晶体管液晶显示屏,它显示的每个像素点都是由集成在液晶后面的薄膜晶体管独立驱动,因此 TFT-LCD 具有较高的响应速度以及较好的图像质量。
我们对于 LCD屏幕其实并不需要掌握其 实现的具体原理 我们只需要从使用的角度了解几个重点的东西
1080p 是 1920 x 1080
2K 是 2560 x 1440
4K 是 3840 x 2160
上面讲了一个像素点就相当于一个 RGB 小灯,通过控制 R、G、B 这三种颜色的亮度就可以显示出各种各样的色彩。那该如何控制 R、G、B 这三种颜色的显示亮度呢?一般一个 R、G、B 这三部分分别使用8bit 的数据,那么一个像素点就是 8bit*3=24bit,也就是说一个像素点 3 个字节,这种像素格式称为 RGB888。当然常用的像素点格式还有 RGB565,只需要两个字节,但在色彩鲜艳度上较差一些。我们领航者开发板上的 RGB TFT-LCD 接口采用的 RGB888 的像素格式,共需要 24 位,每一位对应 RGB 的颜色分量如下图所示:
一个像素点占用 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 就是白色
RGB LCD 接口的信号线
R[7:0]、G[7:0]和 B[7:0]是 24 位数据,DE、VSYNC、HSYNC 和PCLK 是四个控制信号
本次实验用到了 ATK-7016 RGB LCD模块
其实我们在之前的SOC 实验中 做过这样子的 大体设计
我们再复习一下
我们来看一下 LCD 是怎么扫描显示一帧图像的。一帧图像也是由一行一行组成的。HSYNC 是水平同步信号,也叫做行同步信号,当产生此信号的话就表示开始显示新的一行了,所以此信号都是在图 29.1.6 的最左边。VSYNC 信号是垂直同步信号,也叫做帧同步信号,当产生此信号的话就表示开始显示新的一帧图像了
RGB LCD 屏幕时序
HSYNC:行同步信号,当此信号有效的时候就表示开始显示新的一行数据,查阅所使用的 LCD 数据手
册可以知道此信号是低电平有效还是高电平有效,图 29.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。
VSYNC:帧(场)同步信号,当此信号有效的时候就表示开始显示新的一帧数据,查阅所使用的 LCD
数据手册可以知道此信号是低电平有效还是高电平有效,图 29.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 接口的时序图非常相似,只是参数不同。如图 29.1.7 和图 29.1.8 中的行同步信号(HSYNC)和场同步信号(VSYNC)作为数据的同步信号,此时数据使能信号(DE)必须为低电平。当选择 DE 同步模式时,LCD 的 DE 信号作为数据的有效信号,如图 29.1.7 和图 29.1.8 的 DE 信号所示。只有同时扫描到帧有效显示区域和行有效显示区域时,DE 信号才有效(高电平)。当选择 DE 同步模式时,此时行场同步信号 VS 和 HS 必须为高电平。由于 RGB LCD 液晶屏一般都支持 DE 模式,因此本章我们采用 DE 同步的方式驱动 LCD 液晶屏。
像素时钟 :
像素时钟就是 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。
我们选用 50MHz
领航者开发板 RGB TFT-LCD 接口原理图
从上图中可以看到,FPGA 管脚输出的颜色数据位宽为 24bit,数据格式为 RGB888,即数据高 8 位表示红色,中间 8 位表示绿色,低 8 位表示蓝色。由于这 24 位数据不仅仅作为输出给 LCD 屏的颜色数据,同时 LCD_R7、LCD_G7 和 LCD_B7 也用来获取 LCD 屏的 ID,因此这 24 位颜色数据对 ZYNQ 开发板来说,是一个双向的引脚。另外,RGBLCD 模块支持触摸功能,图中以字母 T 开头的 5 个信号(T_PEN、T_SCK 等)与模块上的触摸芯片相连接。由于本次实验不涉及触摸功能的实现,因此这些信号并未用到。需要说明的是,LCD 液晶屏有一个复位信号(LCD_RST),当 LCD_RST 为低电平时,可对 LCD 屏进行复位。
实验任务 :
使用正点原子 ZYNQ 开发板上的 RGB TFT-LCD 接口,驱动 RGB LCD 液晶屏(支持目前推出的所有 RGB LCD 屏),并显示出彩条。
下面是我自己改写的代码
我觉得他把本应该 分开写的 输出和 控制模块全部写到一个led_driver 模块中 不妥当 我把它拆分成前控制模块 和 单个输出模块
因为 更好的给大家比照学习的机会 ( 内心os : 不想写 testbench
所以我的变量名字都是用同样的写法
下面展示我自己的完整的逻辑框图
可能写的不明白 但是 初步介绍一下
第一个 Read 模块
主要是读取 参数 确定 究竟用的是什么屏幕
第二个是 clk 时钟分频模块
主要是 读取 ID之后 将根据 ID 的 不同把不同的 频率 分配完成 输出给下一级
下面一个是我自己的独立于它的LCD驱动模块
我这个模块的主要作用是 接收型号的传递之后告诉我下一级display 该怎么显示 显示什么样的东西
再下一个是显示模块
就是传入数据究竟是怎么样的一种格式
最后一个部分是输出模块 out
我们先来写read模块
我们读模块 ID 读取 ID 模块根据输入的 lcd_rgb 值来寄存 LCD 屏的 ID,lcd_rgb[7](B7)、lcd_rgb[15](G7)和 lcd_rgb[23](R7)分别对应 M2、M1 和 M0。
除此之外,为了方便将 LCD 的 ID 和分辨率对应起来,这里对 M2、M1 和 M0 的值做了一个译码。如3’b000 译码成 16’h4342,表示当前连接的是 4.3 寸屏,分辨率为 480*272。
还有一件事 区分一下 高位和低位
其中 bit23~bit16 是 RED 通道,bit15~bit8 是 GREEN 通道,bit7~bit0 是 BLUE 通道。
ok
代码和结构在最后统一展示
下面介绍时钟模块
时钟模块 主要在于接收上游发送的lcd_id 之后 对应输出 不同的时钟频率
我们现在按照要求 要输出一个 2分频和4分频
超链接一下 我上次 写的 分频器的章节
因为偶数频率相对来说好做一点 对于奇数频率 大家可以相对的去学习一下
偶数频率N 在于 取 N/2 - 1 的 clk 反转
ok
下一步 我这里和正点原子不同了
我希望我这个模块 只是用来将 不同的 分辨率 lcd 究竟该如何作画 区分开来
我们了解到了原理可以知道 红色框框是 整个屏幕 而 黑色的是 框框的 画布 我们会在上面进行作画 注意左上角的是 端点(0,0)
整个总长其实包括了 下面的几个部分
而 画布的长度其实就是其中数据 显示的 HOZVAL 假设 1024*600 其实就是1024
而总列长 我们可以通过 利用帧同步信号进行计算
每完成1行到头 + 1 加到多少 就是多少
这里有一个误区
因为这一的单位是 1行的时间 所以我们不去细究数据 的 大小 可能数据量上会小一点
所以 我们每走完一整行 再控制这个列的数字 + 1 这才是 我们需要注意到的 因为单位是 一整行
注意点说完了 下面开始代码构造 都放到了下面统一讲述了
下面演示主要代码
----------------------------------------------------------------------------read_id .v
module rd_id(input clk , //时钟input rst_n , //复位,低电平有效input [23:0] lcd_rgb, //RGB LCD像素数据,用于读取IDoutput reg [15:0] lcd_id //LCD屏ID);//reg definereg rd_flag; //读ID标志//*****************************************************//** main code//*****************************************************//获取LCD ID M2:B7 M1:G7 M0:R7always @(posedge clk or negedge rst_n)beginif(!rst_n)beginrd_flag <= 1'b0;lcd_id <= 16'd0;endelsebeginif(rd_flag == 1'b0)beginrd_flag <= 1'b1;case({lcd_rgb[7],lcd_rgb[15],lcd_rgb[23]})3'b000 :lcd_id <= 16'h4342; //4.3' RGB LCD RES:480x2723'b001 :lcd_id <= 16'h7084; //7' RGB LCD RES:800x4803'b010 :lcd_id <= 16'h7016; //7' RGB LCD RES:1024x6003'b100 :lcd_id <= 16'h4384; //4.3' RGB LCD RES:800x4803'b101 :lcd_id <= 16'h1018; //10' RGB LCD RES:1280x800default :lcd_id <= 16'd0;endcaseendendendendmodule
----------------------------------------------------------------------------clk.v
module clk_id(input clk ,input rst_n ,input [15:0] lcd_id ,output reg lcd_pclk);reg clk_25m;reg clk_12_5m;reg div_4_cnt;//时钟2分频 输出25MHz时钟always @(posedge clk or negedge rst_n)beginif(!rst_n)clk_25m <= 1'b0;elseclk_25m <= ~clk_25m;end//时钟4分频 输出12.5MHz时钟always @(posedge clk or negedge rst_n)beginif(!rst_n)begindiv_4_cnt <= 1'b0;clk_12_5m <= 1'b0;endelsebegindiv_4_cnt <= div_4_cnt + 1'b1;if(div_4_cnt == 1'b1)clk_12_5m <= ~clk_12_5m;endendalways @(*)begincase(lcd_id)16'h4342 :lcd_pclk = clk_12_5m;16'h7084 :lcd_pclk = clk_25m;16'h7016 :lcd_pclk = clk;16'h4384 :lcd_pclk = clk_25m;16'h1018 :lcd_pclk = clk;default :lcd_pclk = 1'b0;endcaseendendmodule
---------------------------------------------------------------------------lcd_set.v
module lcd_set(input clk ,input rst_n ,input [15:0] lcd_id ,output [10:0] pixel_xpos , // x 轴 对于点的移动坐标output [10:0] pixel_ypos , // y 轴 对于点的移动坐标output reg [10:0] h_disp , // it is 480*272 - 480output reg [10:0] v_disp // - 272);// ============================================ \\// we define signal and parameter \\// ============================================ \\
// next is copy// 4.3' 480*272parameter H_SYNC_4342 = 11'd41; //行同步parameter H_BACK_4342 = 11'd2; //行显示后沿parameter H_DISP_4342 = 11'd480; //行有效数据parameter H_FRONT_4342 = 11'd2; //行显示前沿parameter H_TOTAL_4342 = 11'd525; //行扫描周期parameter V_SYNC_4342 = 11'd10; //场同步parameter V_BACK_4342 = 11'd2; //场显示后沿parameter V_DISP_4342 = 11'd272; //场有效数据parameter V_FRONT_4342 = 11'd2; //场显示前沿parameter V_TOTAL_4342 = 11'd286; //场扫描周期// 7' 800*480parameter H_SYNC_7084 = 11'd128; //行同步parameter H_BACK_7084 = 11'd88; //行显示后沿parameter H_DISP_7084 = 11'd800; //行有效数据parameter H_FRONT_7084 = 11'd40; //行显示前沿parameter H_TOTAL_7084 = 11'd1056; //行扫描周期parameter V_SYNC_7084 = 11'd2; //场同步parameter V_BACK_7084 = 11'd33; //场显示后沿parameter V_DISP_7084 = 11'd480; //场有效数据parameter V_FRONT_7084 = 11'd10; //场显示前沿parameter V_TOTAL_7084 = 11'd525; //场扫描周期// 7' 1024*600parameter H_SYNC_7016 = 11'd20; //行同步parameter H_BACK_7016 = 11'd140; //行显示后沿parameter H_DISP_7016 = 11'd1024; //行有效数据parameter H_FRONT_7016 = 11'd160; //行显示前沿parameter H_TOTAL_7016 = 11'd1344; //行扫描周期parameter V_SYNC_7016 = 11'd3; //场同步parameter V_BACK_7016 = 11'd20; //场显示后沿parameter V_DISP_7016 = 11'd600; //场有效数据parameter V_FRONT_7016 = 11'd12; //场显示前沿parameter V_TOTAL_7016 = 11'd635; //场扫描周期// 10.1' 1280*800parameter H_SYNC_1018 = 11'd10; //行同步parameter H_BACK_1018 = 11'd80; //行显示后沿parameter H_DISP_1018 = 11'd1280; //行有效数据parameter H_FRONT_1018 = 11'd70; //行显示前沿parameter H_TOTAL_1018 = 11'd1440; //行扫描周期parameter V_SYNC_1018 = 11'd3; //场同步parameter V_BACK_1018 = 11'd10; //场显示后沿parameter V_DISP_1018 = 11'd800; //场有效数据parameter V_FRONT_1018 = 11'd10; //场显示前沿parameter V_TOTAL_1018 = 11'd823; //场扫描周期// 4.3' 800*480parameter H_SYNC_4384 = 11'd128; //行同步parameter H_BACK_4384 = 11'd88; //行显示后沿parameter H_DISP_4384 = 11'd800; //行有效数据parameter H_FRONT_4384 = 11'd40; //行显示前沿parameter H_TOTAL_4384 = 11'd1056; //行扫描周期parameter V_SYNC_4384 = 11'd2; //场同步parameter V_BACK_4384 = 11'd33; //场显示后沿parameter V_DISP_4384 = 11'd480; //场有效数据parameter V_FRONT_4384 = 11'd10; //场显示前沿parameter V_TOTAL_4384 = 11'd525; //场扫描周期// define 便于后面的使用 调用reg [10:0] h_sync ;reg [10:0] h_back ;reg [10:0] h_total;reg [10:0] v_sync ;reg [10:0] v_back ;reg [10:0] v_total;reg [10:0] h_cnt ;reg [10:0] v_cnt ;// ================================================== \\// next is main code \\// ================================================== \\
always @(*)begincase(lcd_id)16'h4342 :beginh_sync = H_SYNC_4342;h_back = H_BACK_4342;h_disp = H_DISP_4342;h_total = H_TOTAL_4342;v_sync = V_SYNC_4342;v_back = V_BACK_4342;v_disp = V_DISP_4342;v_total = V_TOTAL_4342;end16'h7084 :beginh_sync = H_SYNC_7084;h_back = H_BACK_7084;h_disp = H_DISP_7084;h_total = H_TOTAL_7084;v_sync = V_SYNC_7084;v_back = V_BACK_7084;v_disp = V_DISP_7084;v_total = V_TOTAL_7084;end16'h7016 :beginh_sync = H_SYNC_7016;h_back = H_BACK_7016;h_disp = H_DISP_7016;h_total = H_TOTAL_7016;v_sync = V_SYNC_7016;v_back = V_BACK_7016;v_disp = V_DISP_7016;v_total = V_TOTAL_7016;end16'h4384 :beginh_sync = H_SYNC_4384;h_back = H_BACK_4384;h_disp = H_DISP_4384;h_total = H_TOTAL_4384;v_sync = V_SYNC_4384;v_back = V_BACK_4384;v_disp = V_DISP_4384;v_total = V_TOTAL_4384;end16'h1018 :beginh_sync = H_SYNC_1018;h_back = H_BACK_1018;h_disp = H_DISP_1018;h_total = H_TOTAL_1018;v_sync = V_SYNC_1018;v_back = V_BACK_1018;v_disp = V_DISP_1018;v_total = V_TOTAL_1018;enddefault :beginh_sync = H_SYNC_4342;h_back = H_BACK_4342;h_disp = H_DISP_4342;h_total = H_TOTAL_4342;v_sync = V_SYNC_4342;v_back = V_BACK_4342;v_disp = V_DISP_4342;v_total = V_TOTAL_4342;endendcaseend// 下一步 我们想要确定整个画布的长度计数//因为 我们配置 x y 其实是为了下一步 display 而用的 我们这里的 配置的 计数// 是用来显示 总长度的计数 而 x y 的计数 是总长度计数 要减去 头尾的多余always@ (posedge clk or negedge rst_n)beginif(!rst_n)h_cnt <= 11'd0;elsebeginif(h_cnt == h_total - 1'b1)h_cnt <= 11'd0;elseh_cnt <= h_cnt + 1'b1;endend// 其实这个控制的是 总长 现在我们确定一下 列长always@ (posedge clk or negedge rst_n)beginif(!rst_n)v_cnt <= 11'd0;elsebeginif(h_cnt == h_total - 1'b1)beginif(v_cnt == v_total - 1'b1)v_cnt <= 11'd0;elsev_cnt <= v_cnt + 1'b1;endendend// 接下来 我们配置 x y 坐标// 我不太懂它 正点原子的什么鬼 我不知道为什么对于 data_reg 他非要 做一个减1 的操作// 也许是上面的那个说 data_reg 其实是有接口的但是要比 lcd_reg 少一个 clk 也许是这个原因// copy 一下//请求像素点颜色数据输入assign data_req = ((h_cnt >= h_sync + h_back - 1'b1) && (h_cnt < h_sync + h_back + h_disp - 1'b1)&& (v_cnt >= v_sync + v_back) && (v_cnt < v_sync + v_back + v_disp))? 1'b1 : 1'b0;//像素点坐标assign pixel_xpos = data_req ? (h_cnt - (h_sync + h_back - 1'b1)) : 11'd0;assign pixel_ypos = data_req ? (v_cnt - (v_sync + v_back - 1'b1)) : 11'd0;endmodule
----------------------------------------------------------------------------------- display.v
module lcd_display(input lcd_pclk ,input rst_n ,input [10:0] pixel_xpos ,input [10:0] pixel_ypos ,input [10:0] h_disp ,input [10:0] v_disp ,output reg [23:0] pixel_data);//parameter defineparameter WHITE = 24'hFFFFFF; //白色parameter BLACK = 24'h000000; //黑色parameter RED = 24'hFF0000; //红色parameter GREEN = 24'h00FF00; //绿色parameter BLUE = 24'h0000FF; //蓝// ========================================== \\// next is main code \\//==============================================\\always @(posedge lcd_pclk or negedge rst_n)beginif(!rst_n)pixel_data <= BLACK;elsebeginif((pixel_xpos >= 11'd0) && (pixel_xpos < h_disp/5*1))pixel_data <= WHITE;else if((pixel_xpos >= h_disp/5*1) && (pixel_xpos < h_disp/5*2))pixel_data <= BLACK;else if((pixel_xpos >= h_disp/5*2) && (pixel_xpos < h_disp/5*3))pixel_data <= RED;else if((pixel_xpos >= h_disp/5*3) && (pixel_xpos < h_disp/5*4))pixel_data <= GREEN;elsepixel_data <= BLUE;endendendmodule
-------------------------------------------------------------------------------------- lastout.v
module last_out(input lcd_pclk ,input rst_n ,input [15:0] lcd_id ,input [23:0] pixel_data ,output lcd_de , //LCD 数据使能信号output lcd_hs , //LCD 行同步信号output lcd_vs , //LCD 场同步信号output lcd_bl , //LCD 背光控制信号output lcd_clk , //LCD 像素时钟output lcd_rst , //LCD复位output [23:0] lcd_rgb //LCD RGB888颜色数据);//parameter define// 4.3' 480*272parameter H_SYNC_4342 = 11'd41; //行同步parameter H_BACK_4342 = 11'd2; //行显示后沿parameter H_DISP_4342 = 11'd480; //行有效数据parameter H_FRONT_4342 = 11'd2; //行显示前沿parameter H_TOTAL_4342 = 11'd525; //行扫描周期parameter V_SYNC_4342 = 11'd10; //场同步parameter V_BACK_4342 = 11'd2; //场显示后沿parameter V_DISP_4342 = 11'd272; //场有效数据parameter V_FRONT_4342 = 11'd2; //场显示前沿parameter V_TOTAL_4342 = 11'd286; //场扫描周期// 7' 800*480parameter H_SYNC_7084 = 11'd128; //行同步parameter H_BACK_7084 = 11'd88; //行显示后沿parameter H_DISP_7084 = 11'd800; //行有效数据parameter H_FRONT_7084 = 11'd40; //行显示前沿parameter H_TOTAL_7084 = 11'd1056; //行扫描周期parameter V_SYNC_7084 = 11'd2; //场同步parameter V_BACK_7084 = 11'd33; //场显示后沿parameter V_DISP_7084 = 11'd480; //场有效数据parameter V_FRONT_7084 = 11'd10; //场显示前沿parameter V_TOTAL_7084 = 11'd525; //场扫描周期// 7' 1024*600parameter H_SYNC_7016 = 11'd20; //行同步parameter H_BACK_7016 = 11'd140; //行显示后沿parameter H_DISP_7016 = 11'd1024; //行有效数据parameter H_FRONT_7016 = 11'd160; //行显示前沿parameter H_TOTAL_7016 = 11'd1344; //行扫描周期parameter V_SYNC_7016 = 11'd3; //场同步parameter V_BACK_7016 = 11'd20; //场显示后沿parameter V_DISP_7016 = 11'd600; //场有效数据parameter V_FRONT_7016 = 11'd12; //场显示前沿parameter V_TOTAL_7016 = 11'd635; //场扫描周期// 10.1' 1280*800parameter H_SYNC_1018 = 11'd10; //行同步parameter H_BACK_1018 = 11'd80; //行显示后沿parameter H_DISP_1018 = 11'd1280; //行有效数据parameter H_FRONT_1018 = 11'd70; //行显示前沿parameter H_TOTAL_1018 = 11'd1440; //行扫描周期parameter V_SYNC_1018 = 11'd3; //场同步parameter V_BACK_1018 = 11'd10; //场显示后沿parameter V_DISP_1018 = 11'd800; //场有效数据parameter V_FRONT_1018 = 11'd10; //场显示前沿parameter V_TOTAL_1018 = 11'd823; //场扫描周期// 4.3' 800*480parameter H_SYNC_4384 = 11'd128; //行同步parameter H_BACK_4384 = 11'd88; //行显示后沿parameter H_DISP_4384 = 11'd800; //行有效数据parameter H_FRONT_4384 = 11'd40; //行显示前沿parameter H_TOTAL_4384 = 11'd1056; //行扫描周期parameter V_SYNC_4384 = 11'd2; //场同步parameter V_BACK_4384 = 11'd33; //场显示后沿parameter V_DISP_4384 = 11'd480; //场有效数据parameter V_FRONT_4384 = 11'd10; //场显示前沿parameter V_TOTAL_4384 = 11'd525; //场扫描周期//reg definereg [10:0] h_sync ;reg [10:0] h_back ;reg [10:0] h_total;reg [10:0] v_sync ;reg [10:0] v_back ;reg [10:0] v_total;reg [10:0] h_cnt ;reg [10:0] v_cnt ;//wire definewire lcd_en;reg [10:0] h_disp ;reg [10:0] v_disp ;// 全是copy//行场时序参数always @(*)begincase(lcd_id)16'h4342 :beginh_sync = H_SYNC_4342;h_back = H_BACK_4342;h_disp = H_DISP_4342;h_total = H_TOTAL_4342;v_sync = V_SYNC_4342;v_back = V_BACK_4342;v_disp = V_DISP_4342;v_total = V_TOTAL_4342;end16'h7084 :beginh_sync = H_SYNC_7084;h_back = H_BACK_7084;h_disp = H_DISP_7084;h_total = H_TOTAL_7084;v_sync = V_SYNC_7084;v_back = V_BACK_7084;v_disp = V_DISP_7084;v_total = V_TOTAL_7084;end16'h7016 :beginh_sync = H_SYNC_7016;h_back = H_BACK_7016;h_disp = H_DISP_7016;h_total = H_TOTAL_7016;v_sync = V_SYNC_7016;v_back = V_BACK_7016;v_disp = V_DISP_7016;v_total = V_TOTAL_7016;end16'h4384 :beginh_sync = H_SYNC_4384;h_back = H_BACK_4384;h_disp = H_DISP_4384;h_total = H_TOTAL_4384;v_sync = V_SYNC_4384;v_back = V_BACK_4384;v_disp = V_DISP_4384;v_total = V_TOTAL_4384;end16'h1018 :beginh_sync = H_SYNC_1018;h_back = H_BACK_1018;h_disp = H_DISP_1018;h_total = H_TOTAL_1018;v_sync = V_SYNC_1018;v_back = V_BACK_1018;v_disp = V_DISP_1018;v_total = V_TOTAL_1018;enddefault :beginh_sync = H_SYNC_4342;h_back = H_BACK_4342;h_disp = H_DISP_4342;h_total = H_TOTAL_4342;v_sync = V_SYNC_4342;v_back = V_BACK_4342;v_disp = V_DISP_4342;v_total = V_TOTAL_4342;endendcaseend//行计数器对像素时钟计数always@ (posedge lcd_pclk or negedge rst_n)beginif(!rst_n)h_cnt <= 11'd0;elsebeginif(h_cnt == h_total - 1'b1)h_cnt <= 11'd0;elseh_cnt <= h_cnt + 1'b1;endend//场计数器对行计数always@ (posedge lcd_pclk or negedge rst_n)beginif(!rst_n)v_cnt <= 11'd0;elsebeginif(h_cnt == h_total - 1'b1)beginif(v_cnt == v_total - 1'b1)v_cnt <= 11'd0;elsev_cnt <= v_cnt + 1'b1;endendend// 这里要开始对最终的 结果进行说明了// lcd_de //LCD 数据使能信号// lcd_hs //LCD 行同步信号// lcd_vs //LCD 场同步信号// lcd_bl //LCD 背光控制信号// lcd_clk //LCD 像素时钟// lcd_rst //LCD复位// lcd_rgb //LCD RGB888颜色数据assign lcd_de = lcd_en; //LCD数据有效信号//使能RGB888数据输出assign lcd_en = ((h_cnt >= h_sync + h_back) && (h_cnt < h_sync + h_back + h_disp)&& (v_cnt >= v_sync + v_back) && (v_cnt < v_sync + v_back + v_disp)) ? 1'b1 : 1'b0;assign lcd_hs = 1'b1 ; //LCD行同步信号assign lcd_vs = 1'b1 ; //LCD场同步信号assign lcd_bl = 1'b1 ; //LCD背光控制信号assign lcd_clk = lcd_pclk ; //LCD像素时钟assign lcd_rst = 1'b1 ; //LCD复位//RGB888数据输出
assign lcd_rgb = lcd_en ? pixel_data : 24'd0;endmodule
---------------------------------------------------------------------------- top.v
module dig_top (input sys_clk, //系统时钟input sys_rst_n, //系统复位//RGB LCD接口output lcd_de, //LCD 数据使能信号output lcd_hs, //LCD 行同步信号output lcd_vs, //LCD 场同步信号output lcd_bl, //LCD 背光控制信号output lcd_clk, //LCD 像素时钟output lcd_rst, //LCD 复位inout [23:0] lcd_rgb //LCD RGB888颜色数据);// ============================================ \\// Next is define and signal parameter \\// ============================================ \\wire [15 : 0] lcd_id ;wire lcd_pclk ;wire [10 : 0] pixel_xpos ;wire [10 : 0] pixel_ypos ;wire [10 : 0] h_disp ;wire [10 : 0] v_disp ;wire [23 : 0] pixel_data ;wire [23:0] lcd_rgb_o ; //输出的像素数据wire [23:0] lcd_rgb_i ; //输入的像素数据assign lcd_rgb = lcd_de ? lcd_rgb_o : {24{1'bz}};assign lcd_rgb_i = lcd_rgb;// ================================================ \\
// next is main code \\
//================================================ \\
rd_id u_read_id(.clk ( sys_clk ),.rst_n ( sys_rst_n ),.lcd_rgb ( lcd_rgb ),.lcd_id ( lcd_id )
);clk_id u_clk_id(.clk ( sys_clk ),.rst_n ( sys_rst_n ),.lcd_id ( lcd_id ),.lcd_pclk ( lcd_pclk )
);lcd_set u_lcd_set(.clk ( lcd_pclk ),.rst_n ( sys_rst_n ),.lcd_id ( lcd_id ),.pixel_xpos ( pixel_xpos ),.pixel_ypos ( pixel_ypos ),.h_disp ( h_disp ),.v_disp ( v_disp )
);lcd_display u_lcd_display(.lcd_pclk ( lcd_pclk ),.rst_n ( sys_rst_n ),.pixel_xpos ( pixel_xpos ),.pixel_ypos ( pixel_ypos ),.h_disp ( h_disp ),.v_disp ( v_disp ),.pixel_data ( pixel_data )
);last_out u_last_out(.lcd_pclk ( lcd_pclk ),.rst_n ( sys_rst_n ),.lcd_id ( lcd_id ),.pixel_data ( pixel_data ),.lcd_de ( lcd_de ),.lcd_hs ( lcd_hs ),.lcd_vs ( lcd_vs ),.lcd_bl ( lcd_bl ),.lcd_clk ( lcd_clk ),.lcd_rst ( lcd_rst ),.lcd_rgb ( lcd_rgb )
);endmodule
// ================================================ testbench.v
`timescale 1ns / 1nsmodule tb_lcd_rgb_colorbar();//reg definereg sys_clk;reg sys_rst_n; //wire definewire lcd_de ;wire lcd_hs ;wire lcd_vs ;wire lcd_bl ;wire lcd_clk;wire [23:0] lcd_rgb;always #10 sys_clk = ~sys_clk;assign lcd_rgb = 24'h0;initial beginsys_clk = 1'b0;sys_rst_n = 1'b0;#200sys_rst_n = 1'b1;enddig_top u_dig_top(.sys_clk ( sys_clk ),.sys_rst_n ( sys_rst_n ),.lcd_de ( lcd_de ),.lcd_hs ( lcd_hs ),.lcd_vs ( lcd_vs ),.lcd_bl ( lcd_bl ),.lcd_clk ( lcd_clk ),.lcd_rst ( lcd_rst ),.lcd_rgb ( lcd_rgb )
);endmodule