今天给大侠带来基于FPGA的VGA/LCD显示控制器设计,由于篇幅较长,分三篇。今天带来第三篇,下篇,程序的仿真与测试以及总结,话不多说,上货。
导读
VGA (Video Graphics Array) 即视频图形阵列,是IBM于1987年随PS/2机(PersonalSystem 2)一起推出的使用模拟信号的一种视频传输标准。这个标准对于现今的个人电脑市场已经十分过时。但在当时具有分辨率高、显示速率快、颜色丰富等优点,在彩色显示器领域取得了广泛的应用,是众多制造商所共同支持的一个低标准。
LCD ( Liquid Crystal Display 的简称)液晶显示器。LCD 的构造是在两片平行的玻璃基板当中放置液晶盒,下基板玻璃上设置TFT(薄膜晶体管),上基板玻璃上设置彩色滤光片,通过TFT上的信号与电压改变来控制液晶分子的转动方向,从而达到控制每个像素点偏振光出射与否而达到显示目的。按照背光源的不同,LCD可以分为CCFL显示器和LED显示器两种。LCD已经替代CRT成为主流,价格也已经下降了很多,并已充分普及。
在之前的文章中介绍了如何获取、处理摄像头提供的视频信号,在实际应用中还需要将经过处理的信号显示在显示器上。这个过程与信号处理中的过程上是相反的,将数字信号按照电视信号的制式组成合乎时序、格式要求的信号,并加入用于控制的各种同步信号。本篇将通过 FPGA实现一个 VGA/LCD 显示控制器的实例,并详细介绍实现过程。
第三篇内容摘要:本篇会介绍程序的仿真与测试以及总结等相关内容。
四、程序的仿真与测试
为了检验程序是否实现预先设定的功能,需要编写仿真程序。仿真程序的主要代码如下:
module test;//寄存器reg clk;reg rst;//参数parameter LINE_FIFO_AWIDTH = 7;申明wire int;wire [31:0] wb_addr_o;wire [31:0] wb_data_i;wire [31:0] wb_data_o;wire [3:0] wb_sel_o;wire wb_we_o;wire wb_stb_o;wire wb_cyc_o;wire [2:0] wb_cti_o;wire [1:0] wb_bte_o;wire wb_ack_i;wire wb_err_i;wire [31:0] wb_addr_i;wire [31:0] wbm_data_i;wire [3:0] wb_sel_i;wire wb_we_i;wire wb_stb_i;wire wb_cyc_i;wire wb_ack_o;wire wb_rty_o;wire wb_err_o;reg pclk_i;wire pclk;wire hsync;wire vsync;wire csync;wire blanc;wire [7:0] red;wire [7:0] green;wire [7:0] blue;wire dvi_pclk_p_o;wire dvi_pclk_m_o;wire dvi_hsync_o;wire dvi_vsync_o;wire dvi_de_o;wire [11:0] dvi_d_o;wire vga_stb_i;wire clut_stb_i;reg scen;测试程序变量integer wd_cnt;integer error_cnt;reg [31:0] data;reg [31:0] pattern;reg int_warn;integer n;integer mode;reg [7:0] thsync, thgdel;reg [15:0] thgate, thlen;reg [7:0] tvsync, tvgdel;reg [15:0] tvgate, tvlen;reg hpol;reg vpol;reg cpol;reg bpol;integer p, l;reg [31:0] pn;reg [31:0] pra, paa, tmp;reg [23:0] pd;reg [1:0] cd;reg pc;reg [31:0] vbase;reg [31:0] cbase;reg [31:0] vbara;reg [31:0] vbarb;reg [7:0] bank;常量定义CTRL 32'h0000_0000STAT 32'h0000_0004HTIM 32'h0000_0008VTIM 32'h0000_000cHVLEN 32'h0000_0010VBARA 32'h0000_0014VBARB 32'h0000_0018USE_VC 1parameter PCLK_C = 20;//测试内容initialbegin(-9, 1, " ns", 12);$display(" ");$display("******************************************************");Controller Simulation started ... *");$display("******************************************************");$display(" ");WAVES$shm_open("waves");$shm_probe("AS",test,"AS");: Signal dump enabled ... ");`endifscen = 0;error_cnt = 0;clk = 0;pclk_i = 0;rst = 0;int_warn=1;@(posedge clk);rst = 1;@(posedge clk);if(0)beginendelseif(1)beginVGA_12BIT_DVIdvi_pd_test;`endifendelsebegin测试区域$display(" ");$display("*****************************************************");XXX Test ***");$display("***************************************************** ");s0.fill_mem(1);@(posedge clk);//参数设置vbara = 32'h0000_0000;vbarb = 32'h0001_0000;`VBARA, 4'hf, vbara );`VBARB, 4'hf, vbarb );thsync = 0;thgdel = 0;thgate = 340;thlen = 345;tvsync = 0;tvgdel = 0;tvgate = 240;tvlen = 245;/*thsync = 0;thgdel = 0;thgate = 63;thlen = 70;tvsync = 0;tvgdel = 0;tvgate = 32;tvlen = 36;*/hpol = 0;vpol = 0;cpol = 0;bpol = 0;`HTIM, 4'hf, {thsync, thgdel, thgate} );`VTIM, 4'hf, {tvsync, tvgdel, tvgate} );`HVLEN, 4'hf, {thlen, tvlen} );mode = 2;=0;bank<3;bank=bank + 1)begincase(mode)0:begincd = 2'h2;pc = 1'b0;end1:begincd = 2'h0;pc = 1'b0;end2:begincd = 2'h0;pc = 1'b1;end3:begincd = 2'h1;pc = 1'b0;endendcase`CTRL, 4'hf, {// Reservedcpol,hpol,// 1'b0, // PC// 2'h2, // CD// VBL// Reserved// CBSWE// VBSWE// BSIE// HIE// VIE// Video Enable});: %0d Screen: %0d", mode, bank);@(posedge vsync);vsync);每一行数据=0;lFor each Pixel=0;pbegin@(posedge pclk);vbase = vbarb[31:2];else vbase = vbara[31:2];cbase = 32'h0000_0c00;else cbase = 32'h0000_0800;各种显示模式= 行数* (thgate + 1) + ppn = l * (thgate + 1) + p;case(mode)0: // 24 位模式beginpra = pn[31:2] * 3;paa = pra + vbase; // 像素决定地址像素数据:0])0:begintmp = s0.mem[paa];pd = tmp[31:8];end1:begintmp = s0.mem[paa];:16] = tmp[7:0];tmp = s0.mem[paa+1];:0] = tmp[31:16];end2:begintmp = s0.mem[paa+1];:8] = tmp[15:0];tmp = s0.mem[paa+2];:0] = tmp[31:24];end3:begintmp = s0.mem[paa+2];pd = tmp[23:0];endendcaseend1: // 8 位灰度模式beginpra = pn[31:2]; // 像素相对地址paa = pra + vbase; // 像素绝对地址:0])0:begintmp = s0.mem[paa];pd = { tmp[31:24], tmp[31:24], tmp[31:24] };end1:begintmp = s0.mem[paa];pd = { tmp[23:16], tmp[23:16], tmp[23:16] };end2:begintmp = s0.mem[paa];pd = { tmp[15:8], tmp[15:8], tmp[15:8] };end3:begintmp = s0.mem[paa];pd = { tmp[7:0], tmp[7:0], tmp[7:0] };endendcaseend2: // 8 位伪彩色模式beginpra = pn[31:2]; //像素相对地址paa = pra + vbase; //像素绝对地址:0])0:begintmp = s0.mem[paa];tmp = s0.mem[cbase[31:2] + tmp[31:24]];pd = tmp[23:0];end1:begintmp = s0.mem[paa];tmp = s0.mem[cbase[31:2] + tmp[23:16]];pd = tmp[23:0];end2:begintmp = s0.mem[paa];tmp = s0.mem[cbase[31:2] + tmp[15:8]];pd = tmp[23:0];end3:begintmp = s0.mem[paa];tmp = s0.mem[cbase[31:2] + tmp[7:0]];pd = tmp[23:0];endendcaseend3: // 16 位模式beginpra = pn[31:1]; //像素相对地址paa = pra + vbase; //像素绝对地址case(pn[0])0:begintmp = s0.mem[paa];:0] = tmp[31:16];pd = {tmp[15:11], 3'h0, tmp[10:5], 2'h0, tmp[4:0], 3'h0};end1:begintmp = s0.mem[paa];pd = {tmp[15:11], 3'h0, tmp[10:5], 2'h0, tmp[4:0], 3'h0};endendcaseendendcase!== {red, green, blue} )begin: Pixel Data Mismatch: Expected: %h, Got: %h %h %h",red, green, blue);pixel=%0d, line=%0d, (%0t)",p,l,$time);error_cnt = error_cnt + 1;endpclk);endendshow_errors;$display("*****************************************************");Test DONE ... ***");end@(posedge clk);$finish;end//同步监视VGA_12BIT_DVIsync_check #(PCLK_C*2) ucheck(`elsesync_check #(PCLK_C) ucheck(`endifpclk ),rst ),scen ),hsync ),vsync ),csync ),blanc ),hpol ),vpol ),cpol ),bpol ),thsync ),thgdel ),thgate ),thlen ),tvsync ),tvgdel ),tvgate ),tvlen ) );视频数据监视wb_b3_check u_wb_check (( clk ),( wb_cyc_o ),( wb_stb_o ),( wb_cti_o ),( wb_bte_o ),( wb_we_o ),( wb_ack_i ),( wb_err_i ),( 1'b0 ) );//看门狗计数器always @(posedge clk)| wb_cyc_o | wb_ack_i | wb_ack_o | hsync)wd_cnt <= #1 0;elsewd_cnt <= #1 wd_cnt + 1;always @(wd_cnt)if(wd_cnt>9000)begin$display(" ************************************* ");: Watch Dog Counter Expired ");$display("************************************* ");$finish;endalways @(posedge int)if(int_warn)begin$display(" ************************************* ");: Recieved Interrupt (%0t)", $time);$display("************************************* ");endalways #2.5 clk = ~clk;always #(PCLK_C/2) pclk_i = ~pclk_i;//模块原型vga_enh_top #(1'b0, LINE_FIFO_AWIDTH) u0 (( clk ),( 1'b0 ),( rst ),( int ),//从信号( wb_addr_i[11:0] ),( wb_data_i ),( wb_data_o ),( wb_sel_i ),( wb_we_i ),( wb_stb_i ),( wb_cyc_i ),( wb_ack_o ),( wb_rty_o ),( wb_err_o ),//主信号( wb_addr_o[31:0] ),( wbm_data_i ),( wb_sel_o ),( wb_we_o ),( wb_stb_o ),( wb_cyc_o ),( wb_cti_o ),( wb_bte_o ),( wb_ack_i ),( wb_err_i ),信号( pclk_i ),VGA_12BIT_DVI( dvi_pclk_p_o ),( dvi_pclk_m_o ),( dvi_hsync_o ),( dvi_vsync_o ),( dvi_de_o ),( dvi_d_o ),`endif( pclk ),( hsync ),( vsync ),( csync ),( blanc ),( red ),( green ),( blue ));wb_mast m0( .clk( clk ),rst ),wb_addr_i ),wb_data_o ),wb_data_i ),wb_cyc_i ),wb_stb_i ),wb_sel_i ),wb_we_i ),wb_ack_o ),wb_err_o ),1'b0 ));wb_slv #(24) s0(.clk( clk ),rst ),{1'b0, wb_addr_o[30:0]} ),32'h0 ),wbm_data_i ),wb_cyc_o ),wb_stb_o ),wb_sel_o ),wb_we_o ),wb_ack_i ),wb_err_i ),));"tests.v"endmodule
五、总结
本篇介绍了一个 VGA/LCD 显示控制器的实例。首先介绍了 VGA/LCD 显示的相关知识,然后介绍了程序的主要结构和主要功能模块的实现过程。最后用一个测试程序验证程序的功能是否满足要求。本章为各位大侠设计自己的 VGA/LCD 显示控制器提供了一个可以使用的方案。
审核编辑 :李倩
全部0条评论
快来发表一下你的评论吧 !