今天給大俠帶來基于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_0000
STAT 32'h0000_0004
HTIM 32'h0000_0008
VTIM 32'h0000_000c
HVLEN 32'h0000_0010
VBARA 32'h0000_0014
VBARB 32'h0000_0018
USE_VC 1
parameter PCLK_C = 20;
//測試內容
initial
begin
(-9, 1, " ns", 12);
$display(" ");
$display("******************************************************");
Controller Simulation started ... *");
$display("******************************************************");
$display(" ");
WAVES
$shm_open("waves");
$shm_probe("AS",test,"AS");
Signal dump enabled ... "); :
`endif
scen = 0;
error_cnt = 0;
clk = 0;
pclk_i = 0;
rst = 0;
int_warn=1;
@(posedge clk);
rst = 1;
@(posedge clk);
if(0)
begin
end
else
if(1)
begin
VGA_12BIT_DVI
dvi_pd_test;
`endif
end
else
begin
測試區域
$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) =
begin
case(mode)
0:
begin
cd = 2'h2;
pc = 1'b0;
end
1:
begin
cd = 2'h0;
pc = 1'b0;
end
2:
begin
cd = 2'h0;
pc = 1'b1;
end
3:
begin
cd = 2'h1;
pc = 1'b0;
end
endcase
`CTRL, 4'hf, {
// Reserved
cpol,
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;l
= For each Pixel
0;p
= begin
@(posedge pclk);
vbase = vbarb[31:2];
else vbase = vbara[31:2];
cbase = 32'h0000_0c00;
else cbase = 32'h0000_0800;
各種顯示模式
行數* (thgate + 1) + p =
pn = l * (thgate + 1) + p;
case(mode)
0: // 24 位模式
begin
pra = pn[31:2] * 3;
paa = pra + vbase; // 像素決定地址
像素數據
0]) :
0:
begin
tmp = s0.mem[paa];
pd = tmp[31:8];
end
1:
begin
tmp = s0.mem[paa];
16] = tmp[7:0]; :
tmp = s0.mem[paa+1];
0] = tmp[31:16]; :
end
2:
begin
tmp = s0.mem[paa+1];
8] = tmp[15:0]; :
tmp = s0.mem[paa+2];
0] = tmp[31:24]; :
end
3:
begin
tmp = s0.mem[paa+2];
pd = tmp[23:0];
end
endcase
end
1: // 8 位灰度模式
begin
pra = pn[31:2]; // 像素相對地址
paa = pra + vbase; // 像素絕對地址
0]) :
0:
begin
tmp = s0.mem[paa];
pd = { tmp[31:24], tmp[31:24], tmp[31:24] };
end
1:
begin
tmp = s0.mem[paa];
pd = { tmp[23:16], tmp[23:16], tmp[23:16] };
end
2:
begin
tmp = s0.mem[paa];
pd = { tmp[15:8], tmp[15:8], tmp[15:8] };
end
3:
begin
tmp = s0.mem[paa];
pd = { tmp[7:0], tmp[7:0], tmp[7:0] };
end
endcase
end
2: // 8 位偽彩色模式
begin
pra = pn[31:2]; //像素相對地址
paa = pra + vbase; //像素絕對地址
0]) :
0:
begin
tmp = s0.mem[paa];
tmp = s0.mem[cbase[31:2] + tmp[31:24]];
pd = tmp[23:0];
end
1:
begin
tmp = s0.mem[paa];
tmp = s0.mem[cbase[31:2] + tmp[23:16]];
pd = tmp[23:0];
end
2:
begin
tmp = s0.mem[paa];
tmp = s0.mem[cbase[31:2] + tmp[15:8]];
pd = tmp[23:0];
end
3:
begin
tmp = s0.mem[paa];
tmp = s0.mem[cbase[31:2] + tmp[7:0]];
pd = tmp[23:0];
end
endcase
end
3: // 16 位模式
begin
pra = pn[31:1]; //像素相對地址
paa = pra + vbase; //像素絕對地址
case(pn[0])
0:
begin
tmp = s0.mem[paa];
0] = tmp[31:16]; :
pd = {tmp[15:11], 3'h0, tmp[10:5], 2'h0, tmp[4:0], 3'h0};
end
1:
begin
tmp = s0.mem[paa];
pd = {tmp[15:11], 3'h0, tmp[10:5], 2'h0, tmp[4:0], 3'h0};
end
endcase
end
endcase
!== {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;
end
pclk);
end
end
show_errors;
$display("*****************************************************");
Test DONE ... ***");
end
@(posedge clk);
$finish;
end
//同步監視
VGA_12BIT_DVI
sync_check #(PCLK_C*2) ucheck(
`else
sync_check #(PCLK_C) ucheck(
`endif
pclk ),
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;
else
wd_cnt <= #1 wd_cnt + 1;
always @(wd_cnt)
if(wd_cnt>9000)
begin
$display(" ************************************* ");
Watch Dog Counter Expired "); :
$display("************************************* ");
$finish;
end
always @(posedge int)
if(int_warn)
begin
$display(" ************************************* ");
Recieved Interrupt (%0t)", $time); :
$display("************************************* ");
end
always #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 顯示控制器提供了一個可以使用的方案。
審核編輯 :李倩
-
FPGA
+關注
關注
1630文章
21759瀏覽量
604327 -
控制器
+關注
關注
112文章
16402瀏覽量
178571 -
lcd
+關注
關注
34文章
4432瀏覽量
167825
原文標題:系統設計精選 | 基于FPGA的VGA/LCD顯示控制器設計(附代碼)
文章出處:【微信號:HXSLH1010101010,微信公眾號:FPGA技術江湖】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論