概述
VGA是一種學(xué)習(xí)FPGA最常見的基礎(chǔ)實驗。雖然現(xiàn)在的顯示屏大多已經(jīng)采用DVI和HDMI方案,但其實VGA在另一個地方還有應(yīng)用,那就是大屏的LCD。目前4.3寸以上的TFT基本都是VGA接口,這樣在完成一個FPGA系統(tǒng)設(shè)計時,選擇一個VGA接口的TFT用來顯示便是最簡單方便的方案。
現(xiàn)在2017年全國大學(xué)生電子設(shè)計大賽還有不到一個月,熟練的使用VGA顯示各種圖形、文字、波形還是很重要的,而不是停留在只能顯示彩條的入門實驗上。這篇博文便致力于解決這個問題。
VGA顯示驅(qū)動
目前常見的電路板上的VGA接口是這樣的,單獨使用R、G、B三條線控制顏色:
或者是這樣的,增加一個電阻網(wǎng)絡(luò)來使可以控制的顏色更加豐富:
現(xiàn)在應(yīng)該很少會看到專門使用VGA驅(qū)動芯片的了。使用電阻網(wǎng)絡(luò)已經(jīng)能獲得不錯的顯示效果。FPGA需要處理的信號有行同步信號HSYNC和場同步信號VSYNC,以及R、G、B三組顏色控制信號。在驅(qū)動VGA之前,我們首先要確定自己的顯示參數(shù),分辨率及刷新率,比如800*600@60Hz的顯示方式其時序參數(shù)如下所示:
不同的分辨率和刷新率有不同的參數(shù),這個數(shù)據(jù)可以在這個網(wǎng)頁中查到。進(jìn)下來就進(jìn)行VGA的時序驅(qū)動,我的習(xí)慣是先將關(guān)鍵性數(shù)據(jù)用parameter定義出來:
//-------------------------------------------------//
// 掃描參數(shù)的設(shè)定 640*480 60Hz VGA
//-------------------------------------------------//
parameter H_SYNC_END = 96; //行同步脈沖結(jié)束時間
parameter V_SYNC_END = 2; //列同步脈沖結(jié)束時間
parameter H_SYNC_TOTAL = 800; //行掃描總像素單位
parameter V_SYNC_TOTAL = 525; //列掃描總像素單位
parameter H_SHOW_START = 144; //顯示區(qū)行開始像素點
parameter V_SHOW_START = 35; //顯示區(qū)列開始像素點
VGA的時序驅(qū)動部分是相當(dāng)固定的,只要我們使用VGA,肯定會加入下面這段代碼。主要方法是定義兩個計數(shù)器,一個管理行掃描,一個管理列掃描;當(dāng)行掃描計數(shù)器掃描完行同步脈沖后置高HSYNC信號;同理,當(dāng)列掃描計數(shù)器掃描完列同步脈沖后置高VSYNC信號。
//水平掃描
always@(posedge clk_25M or negedge RSTn)
if(!RSTn) x_cnt 《= ‘d0;
else if (x_cnt == H_SYNC_TOTAL) x_cnt 《= ’d0;
else x_cnt 《= x_cnt + 1‘b1;
//垂直掃描
always@(posedge clk_25M or negedge RSTn)
if(!RSTn) y_cnt 《= ’d0;
else if (y_cnt == V_SYNC_TOTAL) y_cnt 《= ‘d0;
else if (x_cnt == H_SYNC_TOTAL) y_cnt 《= y_cnt + 1’b1;
else y_cnt 《= y_cnt;
//H_SYNC信號
always@(posedge clk_25M or negedge RSTn)
if(!RSTn) hsync 《= ‘d0;
else if (x_cnt == ’d0) hsync 《= 1‘b0;
else if (x_cnt == H_SYNC_END) hsync 《= 1’b1;
else hsync 《= hsync;
//_SYNC信號
always@(posedge clk_25M or negedge RSTn)
if(!RSTn) vsync 《= ‘d0;
else if (y_cnt == ’d0) vsync 《= 1‘b0;
else if (y_cnt == V_SYNC_END) vsync 《= 1’b1;
else vsync 《= vsync;
由于VGA需要一個時鐘來管理掃描的速度,因此這個時鐘大小就應(yīng)當(dāng)為掃面面積*刷新率,如上例中的640*480@60Hz的顯示方式需要的VGA時鐘大小為800*525*60=25.2MHz(掃描時不僅包括顯示區(qū)域,還有同步脈沖、顯示前沿和顯示后沿,因此整個區(qū)域要大于分辨率)。VGA時鐘可以用PLL或分頻等方法產(chǎn)生,通常要求不會太嚴(yán)苛,上例取整為25MHz即可。
為了后面的顯示方便,一種實用的方法是再定義兩個寄存器,專門存儲顯示區(qū)域的坐標(biāo),即以可以顯示的第一個像素點為坐標(biāo)(0,0)。
assign x_pos = x_cnt - H_SHOW_START;
assign y_pos = y_cnt - V_SHOW_START;
這樣上例中行掃描計數(shù)器和列掃描計數(shù)器的范圍分別為800和525,而顯示區(qū)域的坐標(biāo)x_pos和y_pos范圍只有640和480。
VGA顯示圖形、波形、文字
其實在得到了顯示區(qū)域的坐標(biāo)后,我們控制顯示圖像的方法就是當(dāng)計數(shù)器掃描到指定位置后,為R、G、B三組信號賦值得到對應(yīng)的圖形。以前面寫的“FPGA綜合系統(tǒng)設(shè)計(一):貪吃蛇游戲(VGA+鍵盤)”這個工程中的顯示部分代碼為例:
always@(posedge clk_25M)
if (area) //坐標(biāo)處于顯示分?jǐn)?shù)的區(qū)域內(nèi),80*80
begin
case(pop)
0: color_out 《= data0 ? 3‘b111 : 3’b000;
1: color_out 《= data1 ? 3‘b111 : 3’b000;
2: color_out 《= data2 ? 3‘b111 : 3’b000;
3: color_out 《= data3 ? 3‘b111 : 3’b000;
4: color_out 《= data4 ? 3‘b111 : 3’b000;
5: color_out 《= data5 ? 3‘b111 : 3’b000;
6: color_out 《= data6 ? 3‘b111 : 3’b000;
7: color_out 《= data7 ? 3‘b111 : 3’b000;
8: color_out 《= data8 ? 3‘b111 : 3’b000;
9: color_out 《= data9 ? 3‘b111 : 3’b000;
10: color_out 《= data10 ? 3‘b111 : 3’b000;
11: color_out 《= data11 ? 3‘b111 : 3’b000;
12: color_out 《= data12 ? 3‘b111 : 3’b000;
default : color_out 《= 3‘b000;
endcase
end
else //坐標(biāo)處于游戲界面的區(qū)域內(nèi)
begin
lox=x_pos[3:0]; //取偏移坐標(biāo)
loy=y_pos[3:0];
/* 根據(jù)當(dāng)前掃描到的點是哪一部分輸出相應(yīng)顏色 */
/*蘋果*/
if(x_pos[9:4]==apple_x&&y_pos[9:4]==apple_y)
case({loy,lox})
8’b0000_0000:color_out=3‘b000;
default:color_out=3’b001;
endcase
/*背景*/
else if(snake==NONE)
color_out=3‘b000;
/*墻壁*/
else if(snake==WALL)
color_out=3’b101;
/*蛇頭與蛇身*/
else if(snake==HEAD|snake==BODY)
case({lox,loy})
8‘b0000_0000:color_out=3’b000;
default:color_out=(snake==HEAD)?HEAD_COLOR:BODY_COLOR;
endcase
end
看這個的設(shè)計思路,always里我把整個顯示區(qū)域劃分為if(area)和else兩個區(qū)域,area是用邏輯判斷定義好的一個80*80大小的區(qū)域,用來顯示分?jǐn)?shù);else則是顯示屏的剩下區(qū)域, 用來顯示游戲。
先看if(area)區(qū)域,我事先將各個分?jǐn)?shù)以圖片的形式存到了ROM中,所有的ROM接的是一組地址線,每個ROM又有不同的數(shù)據(jù)線。根據(jù)當(dāng)前的游戲分?jǐn)?shù),我使用case來決定選擇哪個ROM中的圖形作為當(dāng)前區(qū)域的輸出。這個設(shè)計思路用處就大了,比如顯示電壓、電流、頻率等如何讓其動態(tài)變化,這就是一種好的方法。
再來看else區(qū)域,我使用計數(shù)器位數(shù)之間的關(guān)系,來將整個屏幕劃分為幾個小格子,然后根據(jù)格子應(yīng)當(dāng)屬于哪種游戲元素來決定顯示什么顏色,這樣整個顯示區(qū)域就劃分為蘋果、墻壁、蛇頭、蛇身等各個游戲元素。
其實顯示波形的方法和else區(qū)域顯示的方法基本是一樣的。假設(shè)我要畫一段512個點長的頻譜,我就可以選擇出行計數(shù)器掃描中的512個像素點,每一個像素點作為一個頻譜點;用同樣的方法,我們把列計數(shù)器掃描的像素點按一定比例分配給不同的峰值,這樣掃描到指定點時輸出顏色,看起來就是一個完整的頻譜圖了。當(dāng)然如果覺得圖形不夠連貫,可以用更多像素點來顯示,對中間的像素點插值即可。
-
FPGA
+關(guān)注
關(guān)注
1645文章
22049瀏覽量
618379 -
VGA
+關(guān)注
關(guān)注
5文章
572瀏覽量
64607
發(fā)布評論請先 登錄
基于FPGA實現(xiàn)VGA的彩色圖片顯示

利用可編程器件CPLD/FPGA實現(xiàn)VGA圖像控制器的設(shè)計方案

基于FPGA、CPLD的嵌入式VGA顯示系統(tǒng).pdf
基于FPGA的VGA控制器設(shè)計與實現(xiàn)
基于Actel FPGA的VGA顯示控制方案
VGA圖形控制器的FPGA實現(xiàn)

基于FPGA的VGA圖形控制器設(shè)計

基于FPGA的圖形式AMLCD控制器的設(shè)計

VGA顯示與基于FPGA的VGA彩色圖片顯示設(shè)計

采用FPGA對VGA圖形控制器的Verilog設(shè)計方法

使用FPGA實現(xiàn)VGA顯示的資料詳細(xì)說明

使用FPGA芯片和EDA設(shè)計VGA顯示器控制電路的論文說明

評論