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

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

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

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

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

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

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

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

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

評(píng)論