【從零開(kāi)始走進(jìn)FPGA】 玩轉VGA
Bingo例程以16bit RGB VGA驅動(dòng)為例,不同位數的顯示只要改一下vga_data即可。
本文引用地址:http://dyxdggzs.com/article/275552.htm前文以及代碼講述了那么多,此處不再貼完整代碼,而是對代碼中部分結構進(jìn)行解析。
代碼下載地址:http://blog.chinaaet.com/detail/21606.html
(1)vga_driver.v代碼分析
a) 參數例化列表
#(
// VGA_1024_768_60fps_65MHz
// Horizontal Parameter ( Pixel )
parameter H_DISP = 11'd1024,
parameter H_FRONT = 11'd24,
parameter H_SYNC = 11'd136,
parameter H_BACK = 11'd160,
parameter H_TOTAL = 11'd1344,
// Virtical Parameter ( Line )
parameter V_DISP = 10'd768,
parameter V_FRONT = 10'd3,
parameter V_SYNC = 10'd6,
parameter V_BACK = 10'd29,
parameter V_TOTAL = 10'd806
)
這樣寫(xiě)的目的是為了軟件封裝性,能夠在例化的時(shí)候修改法分辨率,同時(shí)電路結構保持不變。
DISP,FRONT ,SYNC,BACK,TOTAL分別為顯示期,消隱前肩,消音期,消隱后肩,總時(shí)間,各自對應各自的行場(chǎng)信號。
b) 行同步信號設計
//------------------------------------------
// 行同步信號發(fā)生器
reg [10:0] hcnt;
always @ (posedge clk_vga or negedge rst_n)
begin
if (!rst_n)
hcnt <= 0;
else
begin
if (hcnt < H_TOTAL-1'b1)
hcnt <= hcnt + 1'b1;
else
hcnt <= 0;
end
end
//------------------------------------------
always@(posedge clk_vga or negedge rst_n)
begin
if(!rst_n)
vga_hs <= 1;
else
begin
if( (hcnt >= H_DISP+H_FRONT-1'b1) && (hcnt < H_DISP+H_FRONT+H_SYNC-1'b1) )
vga_hs <= 0;
else
vga_hs <= 1;
end
end
如上所示,分析代碼可以知道,行同步信號的計數狀態(tài)機按照時(shí)序的劃分,是以下過(guò)程:H_DISP,H_FRONT,H_SYNC,H_BACK,這似乎和上述分析的VGA時(shí)序不是完全吻合。但是VGA時(shí)序是一個(gè)循環(huán),順推H_BACK個(gè)時(shí)終域便可以得到以上時(shí)期劃分,但是這樣更方便后續坐標計數,因為Bingo此處這樣設計,當然實(shí)際證明是完全可行的。
注意:(hcnt >= H_DISP+H_FRONT-1'b1) && (hcnt < H_DISP+H_FRONT+H_SYNC-1'b1) 只是因為后續坐標計算,就把時(shí)序提前了1個(gè)時(shí)鐘已達到同步。
c) 場(chǎng)同步信號設計
同上。
d) 數據顯示坐標以及輸出設計
//------------------------------------------
assign vga_xpos = (hcnt < H_DISP) ? hcnt[9:0]+1'b1 : 10'd0;
assign vga_ypos = (vcnt < V_DISP) ? vcnt[9:0]+1'b1 : 10'd0;
assign vga_rgb = ((hcnt < H_DISP) && (vcnt < V_DISP)) ? vga_data : 16'd0;
這部分很容易理解,在顯示期坐標根據顯示的掃描而改變,在非顯示期,坐標置零。
(2)Vga_display.v代碼分析
a) 標準色彩定義
//define colors RGB--5|6|5
localparam RED = 16'hF800;
localparam GREEN = 16'h07E0;
localparam BLUE = 16'h001F;
localparam WHITE = 16'hFFFF;
localparam BLACK = 16'h0000;
localparam YELLOW = 16'hFFE0;
localparam CYAN = 16'hF81F;
localparam ROYAL = 16'h07FF;
定義當地的參數,目的是為了后續標準色彩調用的方便,沒(méi)有其他作用。
b) 根據固定區域輸出數據
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
vga_data <= 16'h0;
else
begin
if (vga_xpos >= 0 && vga_xpos < (H_DISP/3))
vga_data <= RED;
else if(vga_xpos >= (H_DISP>>3)*1 && vga_xpos < (H_DISP/3)*2)
vga_data <= GREEN;
else
vga_data <= BLUE;
end
end
如上代碼,根據xpos坐標,來(lái)輸出固定色彩。由于vga_driver模塊已經(jīng)完全設計好接口,因此vga_display.v模塊就是簡(jiǎn)單的根據區域,輸出設計的顏色。
(3) Vga_ctrl.v代碼分析
a) 同步化解析
略。
b) 可控鎖相環(huán)PLL設計

本來(lái)可空鎖相環(huán)PLL設計,Bingo想單獨成章來(lái)講述的,但覺(jué)得可能別的地方實(shí)際應用價(jià)值不是很大,最后便在此處闡明這樣設計的原因。
由于VGA不同分辨率的掃描時(shí)鐘不同,因此分辨率變化的時(shí)候,PLL的輸出時(shí)鐘是必要跟隨著(zhù)變化。但是Bingo覺(jué)得好麻煩,于是想了偷懶的一招:PLL IP定義,無(wú)非是用Quartus II GUI對PLL參數的設定,最后生成pll.v這個(gè)文件。而這個(gè)文件相當于是鎖相環(huán)的驅動(dòng)電路,故勢必包含著(zhù)參數的定義。實(shí)際如下:
altpll_component.clk0_divide_by = 1,
altpll_component.clk0_duty_cycle = 50,
altpll_component.clk0_multiply_by = 1,
如上圖所示,每次修改參數,這三個(gè)變量會(huì )相應的發(fā)生變化。因此,何不把這三個(gè)參數作為例化的參數,可以再頂層直接修改代碼來(lái)實(shí)現固定頻率的輸出?這樣豈不是很方便?
因此設計參數例化接口如下:
#(
parameter DUTY_CYCLE = 50,
parameter DIVIDE_DATA = 1,
parameter MULTIPLY_DATA = 1
)
理論上是完全行得通的,這樣設計的另一個(gè)好處就是電路的封裝性更好Bingo實(shí)踐證明,完全可行,因此在此處說(shuō)明,要學(xué)會(huì )正確的偷懶呵呵。
(4)Vga_design.v頂層文件代碼解析
a) Vga接口定義
//vga interface
output vga_adv_clk,
output vga_blank_n,
output vga_sync_n,
output vga_hs,
output vga_vs,
output [15:0] vga_rgb
如上所示,上面三個(gè)信號線(xiàn)是在使用adv712x視頻轉換芯片的時(shí)候才會(huì )出現,一般的電阻模擬電路,或者直接RGB3線(xiàn)驅動(dòng),可以直接刪除相關(guān)信號以及電路。
b) 進(jìn)一步偷懶法則
根據常用的幾種分辨率,Bingo進(jìn)行了總結,以下三種應用較多,因此進(jìn)一步偷懶法則,圍繞他們三者來(lái)(不在這三種以?xún)鹊脑?huà),自己模仿著(zhù)再寫(xiě)一個(gè)):
VGA_640_480_60FPS_25MHz
VGA_800_600_72FPS_50MHz
VGA_1024_768_60FPS_65MHz
Verilog語(yǔ)法也有define的用法,是否還記得C語(yǔ)言中,大工程的調試經(jīng)常對相關(guān)變量的注釋?zhuān)N(xiāo)來(lái)調整整個(gè)工程變量的應用,因此此處Bingo套用這種思維模式,定義以上三種模式的變量,通過(guò)修改注釋define便可以輕松修改全局。具體如下所示:
//----------------------------------------
//vga parameter define
//`define VGA_640_480_60FPS_25MHz
//`define VGA_800_600_72FPS_50MHz
`define VGA_1024_768_60FPS_65MHz
`ifdef VGA_640_480_60FPS_25MHz
parameter DUTY_CYCLE = 50;
parameter DIVIDE_DATA = 2;
parameter MULTIPLY_DATA = 1;
parameter H_DISP = 11'd640;
parameter H_FRONT = 11'd16;
parameter H_SYNC = 11'd96;
parameter H_BACK = 11'd48;
parameter H_TOTAL = 11'd800;
parameter V_DISP = 10'd480;
parameter V_FRONT = 10'd10;
parameter V_SYNC = 10'd2;
parameter V_BACK = 10'd33;
parameter V_TOTAL = 10'd525;
`endif
`ifdef VGA_800_600_72FPS_50MHz
parameter DUTY_CYCLE = 50;
parameter DIVIDE_DATA = 1;
parameter MULTIPLY_DATA = 1;
parameter H_DISP = 11'd800;
parameter H_FRONT = 11'd56;
parameter H_SYNC = 11'd120;
parameter H_BACK = 11'd64;
parameter H_TOTAL = 11'd1040;
parameter V_DISP = 10'd600;
parameter V_FRONT = 10'd37;
parameter V_SYNC = 10'd6;
parameter V_BACK = 10'd23;
parameter V_TOTAL = 10'd666;
`endif
`ifdef VGA_1024_768_60FPS_65MHz
parameter DUTY_CYCLE = 50;
parameter DIVIDE_DATA = 10;
parameter MULTIPLY_DATA = 13;
parameter H_DISP = 11'd1024;
parameter H_FRONT = 11'd24;
parameter H_SYNC = 11'd136;
parameter H_BACK = 11'd160;
parameter H_TOTAL = 11'd1344;
parameter V_DISP = 10'd768;
parameter V_FRONT = 10'd3;
parameter V_SYNC = 10'd6;
parameter V_BACK = 10'd29;
parameter V_TOTAL = 10'd806;
`endif
四、Display方案以及效果
1、彩條
(1)代碼
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
vga_data <= 16'h0;
else
begin
if (vga_xpos >= 0 && vga_xpos < (H_DISP>>3))
vga_data <= RED;
else if(vga_xpos >= (H_DISP>>3)*1 && vga_xpos < (H_DISP>>3)*2)
vga_data <= GREEN;
else if(vga_xpos >= (H_DISP>>3)*2 && vga_xpos < (H_DISP>>3)*3)
vga_data <= BLUE;
else if(vga_xpos >= (H_DISP>>3)*3 && vga_xpos < (H_DISP>>3)*4)
vga_data <= WHITE;
else if(vga_xpos >= (H_DISP>>3)*4 && vga_xpos < (H_DISP>>3)*5)
vga_data <= BLACK;
else if(vga_xpos >= (H_DISP>>3)*5 && vga_xpos < (H_DISP>>3)*6)
vga_data <= YELLOW;
else if(vga_xpos >= (H_DISP>>3)*6 && vga_xpos < (H_DISP>>3)*7)
vga_data <= CYAN;
else// if(vga_xpos >= (H_DISP<<3)*7 && vga_xpos < (H_DISP<<3)*8)
vga_data <= ROYAL;
end
end
通過(guò)簡(jiǎn)單的對X坐標地址的分割,來(lái)得到彩條。這是應該是VGA初學(xué)者一開(kāi)始最興奮的幾個(gè)界面吧。
(2)效果圖

2、花型矩陣
(1)代碼
wire [19:0] vga_result = vga_xpos * vga_ypos;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
vga_data <= 16'h0;
else
vga_data = vga_result[15:0];
end
通過(guò)x坐標地址和y坐標地址的乘積的值,取低16位,得到的數據有一定的規律。Bingo當年也是不小心發(fā)現的,僅此獻給初學(xué)的孩子們,這個(gè)比彩條更帥氣。
(2)效果圖

fpga相關(guān)文章:fpga是什么
評論