今天給大俠帶來(lái)基于FPGA的VGA/LCD顯示控制器設(shè)計(jì),由于篇幅較長(zhǎng),分三篇。今天帶來(lái)第三篇,下篇,程序的仿真與測(cè)試以及總結(jié),話不多說(shuō),上貨。
導(dǎo)讀
VGA (Video Graphics Array) 即視頻圖形陣列,是IBM于1987年隨PS/2機(jī)(PersonalSystem 2)一起推出的使用模擬信號(hào)的一種視頻傳輸標(biāo)準(zhǔn)。這個(gè)標(biāo)準(zhǔn)對(duì)于現(xiàn)今的個(gè)人電腦市場(chǎng)已經(jīng)十分過(guò)時(shí)。但在當(dāng)時(shí)具有分辨率高、顯示速率快、顏色豐富等優(yōu)點(diǎn),在彩色顯示器領(lǐng)域取得了廣泛的應(yīng)用,是眾多制造商所共同支持的一個(gè)低標(biāo)準(zhǔn)。
LCD ( Liquid Crystal Display 的簡(jiǎn)稱)液晶顯示器。LCD 的構(gòu)造是在兩片平行的玻璃基板當(dāng)中放置液晶盒,下基板玻璃上設(shè)置TFT(薄膜晶體管),上基板玻璃上設(shè)置彩色濾光片,通過(guò)TFT上的信號(hào)與電壓改變來(lái)控制液晶分子的轉(zhuǎn)動(dòng)方向,從而達(dá)到控制每個(gè)像素點(diǎn)偏振光出射與否而達(dá)到顯示目的。按照背光源的不同,LCD可以分為CCFL顯示器和LED顯示器兩種。LCD已經(jīng)替代CRT成為主流,價(jià)格也已經(jīng)下降了很多,并已充分普及。
在之前的文章中介紹了如何獲取、處理攝像頭提供的視頻信號(hào),在實(shí)際應(yīng)用中還需要將經(jīng)過(guò)處理的信號(hào)顯示在顯示器上。這個(gè)過(guò)程與信號(hào)處理中的過(guò)程上是相反的,將數(shù)字信號(hào)按照電視信號(hào)的制式組成合乎時(shí)序、格式要求的信號(hào),并加入用于控制的各種同步信號(hào)。本篇將通過(guò) FPGA實(shí)現(xiàn)一個(gè) VGA/LCD 顯示控制器的實(shí)例,并詳細(xì)介紹實(shí)現(xiàn)過(guò)程。
第三篇內(nèi)容摘要:本篇會(huì)介紹程序的仿真與測(cè)試以及總結(jié)等相關(guān)內(nèi)容。
四、程序的仿真與測(cè)試
為了檢驗(yàn)程序是否實(shí)現(xiàn)預(yù)先設(shè)定的功能,需要編寫仿真程序。仿真程序的主要代碼如下:
module test;
//寄存器
reg clk;
reg rst;
//參數(shù)
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;
測(cè)試程序變量
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;
//測(cè)試內(nèi)容
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
測(cè)試區(qū)域
$display(" ");
$display("*****************************************************");
XXX Test ***");
$display("***************************************************** ");
s0.fill_mem(1);
@(posedge clk);
//參數(shù)設(shè)置
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);
每一行數(shù)據(jù)
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;
各種顯示模式
行數(shù)* (thgate + 1) + p =
pn = l * (thgate + 1) + p;
case(mode)
0: // 24 位模式
begin
pra = pn[31:2] * 3;
paa = pra + vbase; // 像素決定地址
像素?cái)?shù)據(jù)
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]; // 像素相對(duì)地址
paa = pra + vbase; // 像素絕對(duì)地址
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]; //像素相對(duì)地址
paa = pra + vbase; //像素絕對(duì)地址
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]; //像素相對(duì)地址
paa = pra + vbase; //像素絕對(duì)地址
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
//同步監(jiān)視
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 ) );
視頻數(shù)據(jù)監(jiān)視
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 ) );
//看門狗計(jì)數(shù)器
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 ),
//從信號(hào)
( 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 ),
//主信號(hà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 ),
信號(hào)
( 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
五、總結(jié)
本篇介紹了一個(gè) VGA/LCD 顯示控制器的實(shí)例。首先介紹了 VGA/LCD 顯示的相關(guān)知識(shí),然后介紹了程序的主要結(jié)構(gòu)和主要功能模塊的實(shí)現(xiàn)過(guò)程。最后用一個(gè)測(cè)試程序驗(yàn)證程序的功能是否滿足要求。本章為各位大俠設(shè)計(jì)自己的 VGA/LCD 顯示控制器提供了一個(gè)可以使用的方案。
審核編輯 :李倩
-
FPGA
+關(guān)注
關(guān)注
1643文章
21966瀏覽量
614123 -
控制器
+關(guān)注
關(guān)注
114文章
16972瀏覽量
182918 -
lcd
+關(guān)注
關(guān)注
34文章
4504瀏覽量
170715
原文標(biāo)題:系統(tǒng)設(shè)計(jì)精選 | 基于FPGA的VGA/LCD顯示控制器設(shè)計(jì)(附代碼)
文章出處:【微信號(hào):HXSLH1010101010,微信公眾號(hào):FPGA技術(shù)江湖】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
中小尺寸彩屏TFT-LCD顯示控制器RA8889ML3N電路原理圖
在fpga上實(shí)現(xiàn)NAND控制器的問(wèn)題請(qǐng)教
基于FPGA的VGA驅(qū)動(dòng)設(shè)計(jì)(附源工程)

想用一個(gè)控制器來(lái)直接對(duì)TSB81BA3E的寄存器進(jìn)行讀寫,怎么實(shí)現(xiàn)?
FPGA 與微控制器優(yōu)缺點(diǎn)比較
VGA轉(zhuǎn)成USB-C的方法
基于FPGA的LCD1602液晶顯示模塊驅(qū)動(dòng)設(shè)計(jì)

vga接口怎么接線 vga接口轉(zhuǎn)換器怎么用
德州儀器發(fā)布超小型DLP顯示控制器
S1D15K01是一種混合LCD驅(qū)動(dòng)器IC

新型微控制器S1C31W73非常適合帶LCD顯示器的可穿戴產(chǎn)品

評(píng)論