大俠好,歡迎來(lái)到FPGA技術(shù)江湖,江湖偌大,相見(jiàn)即是緣分。大俠可以關(guān)注FPGA技術(shù)江湖,在“闖蕩江湖”、"行俠仗義"欄里獲取其他感興趣的資源,或者一起煮酒言歡。
今天給大俠帶來(lái)基于FPGA的VGA驅(qū)動(dòng)設(shè)計(jì)。
設(shè)計(jì)背景
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)。
設(shè)計(jì)原理
VGA的實(shí)體圖與接口示意圖,如下圖所示,它有15個(gè)針孔:
在本次設(shè)計(jì)使用的開(kāi)發(fā)板中,VGA的電路原理圖如下圖所示:
通過(guò)原理圖,我們不難發(fā)現(xiàn),VGA需要我們控制的接口只有5個(gè):
顯示器的掃描規(guī)律是什么?本設(shè)計(jì)采用逐行掃描,逐行掃描是掃描從屏幕左上角一點(diǎn)開(kāi)始,從左向右逐點(diǎn)掃描,每掃描完一行,電子束回到屏幕的左邊下一行的起始位置,在這期間,CRT對(duì)電子束進(jìn)行消隱,每行結(jié)束時(shí),用行同步信號(hào)進(jìn)行行同步;當(dāng)掃描完所有的行,形成一幀,用場(chǎng)同步信號(hào)進(jìn)行場(chǎng)同步,并使掃描回到屏幕左上方,同時(shí)進(jìn)行場(chǎng)消隱,開(kāi)始下一幀。通過(guò)這種掃描規(guī)律,很容易看出,在設(shè)計(jì)兩個(gè)有效范圍計(jì)數(shù)器時(shí),場(chǎng)同步信號(hào)計(jì)數(shù)器是以行同步信號(hào)計(jì)數(shù)器為周期的。
VGA的顯示標(biāo)準(zhǔn)如下表所示:
對(duì)于普通的VGA顯示器都要嚴(yán)格遵循“VGA工業(yè)標(biāo)準(zhǔn)”,否則可能會(huì)損害VGA顯示器,因此我們?cè)谠O(shè)計(jì)時(shí)VGA控制器時(shí),都需要參考顯示器的顯示標(biāo)準(zhǔn),下面是VGA的行掃描時(shí)序與場(chǎng)掃描時(shí)序:
行掃描時(shí)序:
場(chǎng)掃描時(shí)序:
根據(jù)上述顯示器的掃描參數(shù)以及掃描時(shí)序,例如800*600@60的顯示模式,60指得是顯示器圖像的刷新頻率,時(shí)鐘40MHz指得是一個(gè)像素輸出的頻率。800*600為VGA的分辨率,指有效顯示區(qū)域?yàn)闀r(shí)序中的c段只有800*600,也就是行計(jì)數(shù)在[216,1016],列計(jì)數(shù)在[27,627],在這個(gè)范圍內(nèi),給RGB色值才會(huì)有效。
在VGA 工業(yè)標(biāo)準(zhǔn)顯示模式要求:行同步、場(chǎng)同步都為負(fù)極性,即同步脈沖要求是負(fù)脈沖。行同步信號(hào)上電拉高,在行同步計(jì)數(shù)為0時(shí)拉低a個(gè)時(shí)鐘周期,即128,之后拉高,在行同步計(jì)數(shù)到1055時(shí),行同步計(jì)數(shù)器清零,場(chǎng)同步計(jì)數(shù)器加1。在行掃描時(shí)序中,掃描計(jì)數(shù)時(shí),周期就是一個(gè)像素點(diǎn)的時(shí)間。
場(chǎng)同步信號(hào)上電拉高,在場(chǎng)同步計(jì)數(shù)為0時(shí)拉低場(chǎng)同步a個(gè)時(shí)鐘周期,即4,之后拉高,在場(chǎng)同步計(jì)數(shù)到627時(shí),場(chǎng)同步計(jì)數(shù)器清零。
在VGA控制器中,還需要控制三個(gè)接口,即三種基色(R、G、B),它們共專用8位,分別是Red為3位,Green為3位,Blue為3位,所以可以顯示256種顏色,RGB數(shù)據(jù)的格式如下表所示:
設(shè)計(jì)框架
本設(shè)計(jì)選擇的VGA顯示標(biāo)準(zhǔn)為800*600@60,實(shí)現(xiàn)點(diǎn)亮整個(gè)屏幕,并顯示為全紅。通過(guò)分析設(shè)計(jì)的功能,可以得到如下的頂層架構(gòu):
頂層模塊端口列表如下:
vga_pll模塊是為了滿足分辨率800*600@60的時(shí)鐘為40MHz,而ZX_1開(kāi)發(fā)板的系統(tǒng)時(shí)鐘為50MHz,通過(guò)鎖相環(huán),將50MHz轉(zhuǎn)化為40MHz。vga_control模塊是為了設(shè)定行場(chǎng)同步信號(hào),并標(biāo)定出有效顯示區(qū)域,并輸出控制顏色的po_rgb信號(hào)。為了便于移植,根據(jù)800*600@60分辨率下的參數(shù),對(duì)其進(jìn)行參數(shù)化定義。
設(shè)計(jì)代碼
頂層模塊vga_display_pure代碼:
module vga_display_pure (pi_clk, pi_rst_n, po_hs, po_vs, po_rgb);
input pi_clk, pi_rst_n; //系統(tǒng)時(shí)鐘復(fù)位
output po_vs; //VGA場(chǎng)同步信號(hào)
output po_hs; //VGA行同步信號(hào)
output [7:0] po_rgb; //VGA場(chǎng)紅綠藍(lán)三基色
//----------------VGA時(shí)序-----------------------------------
// 顯示模式 時(shí)鐘
// 800*600@60 40MHz
//行/場(chǎng) 同步(a) 消隱后沿(b) 有效顯示(c) 消隱前沿(d) 掃描時(shí)間(e)
//hs 128 88 800 40 1056
//vs 4 23 600 1 628
wire vga_clk;
vga_pll vga_pll_dut(
.areset(~pi_rst_n),
.inclk0(pi_clk),
.c0(vga_clk)
);
vga_control vga_control_dut(
.pi_clk(vga_clk),
.pi_rst_n(pi_rst_n),
.po_hs(po_hs),
.po_vs(po_vs),
.po_rgb(po_rgb)
);
endmodule
VGA控制器vga_control 模塊代碼:
module vga_control (pi_clk, pi_rst_n, po_hs, po_vs, po_rgb);
input pi_clk, pi_rst_n; //系統(tǒng)時(shí)鐘復(fù)位
output reg po_vs; //VGA場(chǎng)同步信號(hào)
output reg po_hs; //VGA行同步信號(hào)
output [7:0] po_rgb; //VGA場(chǎng)紅綠藍(lán)三基色
//----------------VGA時(shí)序-----------------------------------
// 顯示模式 時(shí)鐘
// 800*600@60 40MHz
//行/場(chǎng) 同步(a) 消隱后沿(b) 有效顯示(c) 消隱前沿(d) 掃描時(shí)間(e)
//hs 128 88 800 40 1056
//vs 4 23 600 1 628
// 行(Horizontal)掃描 Parameter (像素)
parameter H_A = 128;
parameter H_B = 80;
parameter H_C = 800;
parameter H_D = 40;
parameter H_E = 1056;
// 場(chǎng)(Vertical)掃描 Parameter (行數(shù))
parameter V_A = 4;
parameter V_B = 23;
parameter V_C = 600;
parameter V_D = 1;
parameter V_E = 628;
//行掃描計(jì)數(shù)器,
reg [10:0] hcnt;
always @ (posedge pi_clk or negedge pi_rst_n)
begin
if (!pi_rst_n)
hcnt <= 11'd0;
else
begin
if (hcnt == (H_E - 1'b1)) //掃描完一行像素
hcnt <= 11'd0;
else
hcnt <= hcnt + 1'b1;
end
end
//場(chǎng)掃描計(jì)數(shù)器
reg [10:0] vcnt;
always @ (posedge pi_clk or negedge pi_rst_n)
begin
if (!pi_rst_n)
vcnt <= 11'd0;
else if (vcnt == (V_E - 1'b1))
vcnt <= 11'd0;
else if (hcnt == (H_E - 1'b1))
vcnt <= vcnt + 1;
end
//行同步輸出
always @ (posedge pi_clk or negedge pi_rst_n)
begin
if (!pi_rst_n)
po_hs <= 1'b1;
else if (hcnt < H_A)
po_hs <= 1'b0;
else
po_hs <= 1'b1;
end
//assign po_hs = (hcnt <= H_A - 1'b1) ? 1'b0 : 1'b1;
//場(chǎng)同步輸出
always @ (posedge pi_clk or negedge pi_rst_n)
begin
if (!pi_rst_n)
po_vs <= 1'b1;
else if (vcnt < V_A)
po_vs <= 1'b0;
else
po_vs <= 1'b1;
end
//assign po_vs = (vcnt <= V_A - 1'b1) ? 1'b0 : 1'b1;
wire rgb_en;
assign rgb_en = (hcnt >= H_A + H_B && hcnt < H_A + H_B + H_C) &&
(vcnt >= V_A + V_B && vcnt < V_A + V_B + V_C) ? 1'b1 : 1'b0;
assign po_rgb = rgb_en ? 8'b111_000_00 : 8'b0000_0000;
endmodule
通過(guò)編譯后生成的RTL視圖如下:
仿真測(cè)試
為了驗(yàn)證本設(shè)計(jì)的邏輯正確性,我們先對(duì)其進(jìn)行了仿真,在仿真時(shí),為了減少仿真的時(shí)間,先將行、場(chǎng)掃描的對(duì)應(yīng)參數(shù),進(jìn)行了縮放,這樣不僅節(jié)約了仿真時(shí)間,同時(shí)由于掃描數(shù)據(jù)量變少,更加便于分析觀察。其仿真代碼所示:
`timescale 1ns/1ps //仿真時(shí)間精度時(shí)間單位
module vga_display_pure_tb;
reg pi_clk, pi_rst_n; //系統(tǒng)時(shí)鐘復(fù)位
wire po_vs; //VGA場(chǎng)同步信號(hào)
wire po_hs; //VGA行同步信號(hào)
wire [7:0] po_rgb; //VGA場(chǎng)紅綠藍(lán)三基色
//初始化數(shù)據(jù),并附相應(yīng)初值
initial begin
pi_clk = 0;
pi_rst_n = 0;
#200.1 pi_rst_n = 1;
end
vga_display_pure vga_display_pure_inst (
.pi_clk(pi_clk),
.pi_rst_n(pi_rst_n),
.po_hs(po_hs),
.po_vs(po_vs),
.po_rgb(po_rgb)
);
always #10 pi_clk = ~pi_clk; //50MHz時(shí)鐘描述
endmodule
仿真圖:
rgb_en信號(hào),只有當(dāng)po_vs和po_hs同時(shí)為高電平時(shí),才有效,并且有po_rgb Red基色信號(hào)輸出,時(shí)序仿真細(xì)節(jié)圖如下所示:
通過(guò)觀察和分析時(shí)序圖,可以發(fā)現(xiàn)與設(shè)計(jì)吻合,接下來(lái)則可進(jìn)行管腳分配,并下板驗(yàn)證,驗(yàn)證結(jié)果如下:
獲取源碼,請(qǐng)?jiān)凇癋PGA技術(shù)江湖”公眾號(hào)內(nèi)回復(fù)“VGA驅(qū)動(dòng)設(shè)計(jì)源碼”,可獲取源碼文件。