VGA硬件接口
到zedboard官方給出的原理圖中查看:
RGB信號,各四位;這里的設計是使用了電阻分壓模擬了DAC芯片實現了4X4X4的RGB信號,如果要更好的顯示效果還是建議使用專門的DAC。
上面給出了所有的引腳分配。
信號功能引腳分配
| Red | 紅色視頻信號 | V20, U20, V19, V18 |
| Green | 綠色視頻信號 | AB22, AA22, AB21, AA21 |
| Blue | 藍色視頻信號 | Y21, Y20, AB20, AB19 |
| Hsync | 行同步信號 | AA19 |
| Vsync | 列同步信號 | Y19 |
VGA時序分析
如上圖所示,就是VGA時序的表示。按照這個時序圖,編寫程序。
Hsync是行同步信號,表示一行的開始和上一行的結束;
Vsync是列同步信號,表示一場的開始和上一場的結束;
行時序是以像素為單位的, 場時序是以行為單位的;
像素點從左到右算一行,行數從上到下算一場。
在圖上定義了很多區間,而根據這些區間我們可以看到整個時序圖被分為了三個矩形:中間的Adressable Video,其外面的Border,還有最外面的Blanking。
傳輸數據的時間就是中間的Adressable Video的這段時間,同步到每個像素即可。中間的那個矩形就對應顯示器顯示的范圍,其他的矩形可以看做是不可見的。
VGA的時序我只是簡單介紹了下,詳細的介紹可以查看:[筆記]VGA時序及其原理
列出幾個常用的時序:
640×480 @60HZ
800×600@60HZ
上面給出了幾個示例,圖中給出了時序參數的計算步驟以及最后結果,可以到這下載:VGA時序標準
現在我們只提取出最后要用到的時序參數:
(這個圖是我直接在網上截圖的,不保證全部正確,最好參考VGA時序標準確認一遍,以手冊為準)
編寫代碼
新建工程,添加Verilog代碼,這些步驟不再贅述。
直接上代碼了,代碼中添加了注釋。我選取的是800×600@60HZ。
程序的結構:
產生vga信號的代碼:
vga_data_gen.v
`timescale
1ns /
1ps
//
// Company:
// Engineer:
//
// Create Date:
2017/
07/
27 23:
15:
37
// Design Name:
// Module Name: vga_data_gen
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision
0.01 -
File Created
// Additional Comments:
//
//module vga_data_gen(input pixel_clk, //像素時鐘input rst, //復位按鍵,高電平復位output [
7:
0] vga_r, //vga信號紅色視頻信號output [
7:
0] vga_g, //vga信號綠色視頻信號output [
7:
0] vga_b, //vga信號藍色視頻信號output vga_hs, //行同步信號output vga_vs, //場同步信號output vga_de, //vga信號有效,如當前時刻傳輸數據有效,即為
1;否則為
0;input turn_mode, //按鍵。按下為高電平,切換vga顯示模式output [
3:
0] mode //當前顯示模式,用
4位編碼);//
// 水平掃描參數的設定
800*
600 60HZ
//
parameter H_Total =
1056 -
1;
parameter H_Sync =
128 -
1;
parameter H_Back =
88 -
1;
parameter H_Active =
800 -
1;
parameter H_Front =
40 -
1;
parameter H_Start =
216 -
1;
parameter H_End =
1016 -
1;//
// 垂直掃描參數的設定
1280*
720 60HZ
//
parameter V_Total =
628 -
1;
parameter V_Sync =
4 -
1;
parameter V_Back =
23 -
1;
parameter V_Active =
600 -
1;
parameter V_Front =
1 -
1;
parameter V_Start =
27 -
1;
parameter V_End =
627 -
1;//行信號計數器
reg [
11:
0] x_cnt;
always @(posedge pixel_clk
or posedge rst)
beginif(rst)x_cnt <=
12'd0;
else if(x_cnt == H_Total)x_cnt <=
12'd0;
elsex_cnt <= x_cnt +
1'b1;
end//根據時序圖參數,產生行同步信號
reg hsync_r;
always @(posedge pixel_clk
or posedge rst)
beginif(rst)hsync_r <=
1'b1;
else if(x_cnt>=
0 && x_cnt < H_Sync)hsync_r <=
1'b0;
elsehsync_r <=
1'b1;
end//行信號有效,即當前數據有效
reg hs_de;
always @(posedge pixel_clk
or posedge rst)
beginif(rst)hs_de <=
1'b0;
else if(x_cnt>=H_Start && x_cnt<H_End)hs_de <=
1'b1;
elsehs_de <=
1'b0;
end//場信號計數器
reg [
11:
0] y_cnt;
always @(posedge pixel_clk
or posedge rst)
beginif(rst)y_cnt <=
12'd0;
else if(y_cnt == V_Total)y_cnt <=
12'd0;
else if(x_cnt == H_Total)y_cnt <= y_cnt +
1'b1;
end//根據時序圖參數,產生場同步信號
reg vsync_r;
always @(posedge pixel_clk
or posedge rst)
beginif(rst)vsync_r <=
1'b1;
else if(y_cnt>=
0 && y_cnt<V_Sync)vsync_r <=
1'b0;
elsevsync_r <=
1'b1;
end//列信號有效,即當前數據有效
reg vs_de;
always @(posedge pixel_clk
or posedge rst)
beginif(rst)vs_de <=
1'b0;
else if(y_cnt>=V_Start && y_cnt<V_End)vs_de <=
1'b1;
elsevs_de <=
1'b0;
end//按鍵消抖,按下后延時一段時間,再檢測是否按下
reg [
16:
0] key_counter;
always @(posedge pixel_clk)
beginif(turn_mode)key_counter <=
17'd0;
else if((turn_mode ==
1'b0) && (key_counter <=
17'h11704))key_counter <= key_counter +
1'b1;
end//顯示模式技術,每次按下按鍵,模式改變,最多有
12種顯示模式
reg [
3:
0] dis_mode;
assign mode = dis_mode;
always @(posedge pixel_clk)
beginif(key_counter ==
17'h11704)
beginif(dis_mode ==
4'd12)dis_mode <=
4'd0;
else dis_mode <= dis_mode +
1'b1;
end
end//產生小格子,黑白棋盤
reg [
7:
0] grid_data_1;
always @(posedge pixel_clk)
beginif((x_cnt[
4] ==
1'b0) ^ (y_cnt[
4] ==
1'b0))grid_data_1 <=
8'h00;
elsegrid_data_1 <=
8'hff;
end//產生大格子,黑白棋盤
reg [
7:
0] grid_data_2;
always @(posedge pixel_clk)
beginif((x_cnt[
6] ==
1'b0) ^ (y_cnt[
6] ==
1'b0))grid_data_2 <=
8'h00;
elsegrid_data_2 <=
8'hff;
end//產生彩條
reg [
23:
0] color_bar;
always @(posedge pixel_clk)
beginif(x_cnt>=
216 && x_cnt<
316)color_bar <=
24'hff0000;
else if(x_cnt>=
316 && x_cnt<
416)color_bar <=
24'h00ff00;
else if(x_cnt>=
416 && x_cnt<
516)color_bar <=
24'h0000ff;
else if(x_cnt>=
516 && x_cnt<
616)color_bar <=
24'hff00ff;
else if(x_cnt>=
616 && x_cnt<
716)color_bar <=
24'hffff00;
else if(x_cnt>=
716 && x_cnt<
816)color_bar <=
24'h00ffff;
else if(x_cnt>=
816 && x_cnt<
916)color_bar <=
24'hffffff;
else if(x_cnt>=
916 && x_cnt<
1016)color_bar <=
24'h000000;
elsecolor_bar <= color_bar;
end//根據顯示模式傳輸rgb信號到緩存器中
reg [
7:
0] vga_r_reg;
reg [
7:
0] vga_g_reg;
reg [
7:
0] vga_b_reg;
always @(posedge pixel_clk
or posedge rst)
beginif(rst)
beginvga_r_reg <=
8'd0;vga_g_reg <=
8'd0;vga_b_reg <=
8'd0;
endelsebegincase(dis_mode)
4'd0: //全黑
beginvga_r_reg <=
8'd0;vga_g_reg <=
8'd0;vga_b_reg <=
8'd0;
end4'd1: //全白
beginvga_r_reg <=
8'b1111_1111;vga_g_reg <=
8'b1111_1111;vga_b_reg <=
8'b1111_1111;
end4'd2: //全紅
beginvga_r_reg <=
8'b1111_1111;vga_g_reg <=
8'd0;vga_b_reg <=
8'd0;
end4'd3: //全綠
beginvga_r_reg <=
8'd0;vga_g_reg <=
8'b1111_1111;vga_b_reg <=
8'd0;
end4'd4: //全藍
beginvga_r_reg <=
8'd0;vga_g_reg <=
8'd0;vga_b_reg <=
8'b1111_1111;
end4'd5: //小格子,黑白棋盤
beginvga_r_reg <= grid_data_1;vga_g_reg <= grid_data_1;vga_b_reg <= grid_data_1;
end4'd6: //大格子,黑白棋盤
beginvga_r_reg <= grid_data_2;vga_g_reg <= grid_data_2;vga_b_reg <= grid_data_2;
end4'd7: //根據行信號漸變,周期性從黑到白
beginvga_r_reg <= x_cnt[
7:
0];vga_g_reg <= x_cnt[
7:
0];vga_b_reg <= x_cnt[
7:
0];
end4'd8: //根據場信號漸變,周期性從黑到白
beginvga_r_reg <= y_cnt[
7:
0];vga_g_reg <= y_cnt[
7:
0];vga_b_reg <= y_cnt[
7:
0];
end4'd9: //根據行信號漸變,周期性紅色從淺到深
beginvga_r_reg <= x_cnt[
7:
0];vga_g_reg <=
8'd0;vga_b_reg <=
8'd0;
end4'd10: //根據列信號漸變,周期性綠色從淺到深
beginvga_r_reg <=
8'd0;vga_g_reg <= x_cnt[
7:
0];vga_b_reg <=
8'd0;
end4'd11: //根據行信號漸變,周期性藍色從淺到深
beginvga_r_reg <=
8'd0;vga_g_reg <=
8'd0;vga_b_reg <= x_cnt[
7:
0];
end4'd12: //彩條信號
beginvga_r_reg <= color_bar[
23:
16];vga_g_reg <= color_bar[
15:
8];vga_b_reg <= color_bar[
7:
0];
enddefault:
beginvga_r_reg <=
8'b1111_1111;vga_g_reg <=
8'b1111_1111;vga_b_reg <=
8'b1111_1111;
endendcase
end
end//將這些寄存器中的信號輸出
assign vga_hs = hsync_r;
assign vga_vs = vsync_r;
assign vga_de = hs_de & vs_de; //只有當行信號和場信號同時有效時數據才有效
assign vga_r = (hs_de & vs_de) ? vga_r_reg :
8'h0;
assign vga_g = (hs_de & vs_de) ? vga_g_reg :
8'h0;
assign vga_b = (hs_de & vs_de) ? vga_b_reg :
8'h0;endmodule
由于VGA信號是800×600@60HZ,我們還需要一個像素時鐘40MHZ。zedboard的PL部分默認的時鐘是100MHZ,所以我們還需要一個時鐘單元來產生40MHZ的特定時鐘。分頻的方法不穩定,不推薦。
點擊準備添加IP核。
如下圖所示找到clocking wizard。打開它,開始配置其功能。
這些都默認不改動,時鐘是100MHZ。
修改輸出時鐘為40MHZ,其他不做修改。
直接點擊OK,創建IP核。
點擊generate產生IP核。
最后會產生這個,我們可以通過Verilog調用這個模塊。
最后編寫頂層Verilog代碼:只是把前面幾個模塊包進來。
vga_disp.v
`timescale
1ns /
1ps
module vga_disp(input clk100M,input rst,input key,output [
3:
0] vga_r,output [
3:
0] vga_g,output [
3:
0] vga_b,output vga_hs,output vga_vs,output [
3:
0] led);wire pixel_clk;wire [
7:
0] R, G, B;wire HS, VS, DE;assign vga_r = R[
7:
4];assign vga_g = G[
7:
4];assign vga_b = B[
7:
4];assign vga_hs = HS;assign vga_vs = VS;vga_data_gen vga_data_gen(.pixel_clk(pixel_clk),.rst(rst),.vga_r(R),.vga_g(G),.vga_b(B),.vga_hs(HS),.vga_vs(VS),.vga_de(DE),.turn_mode(key),.mode(led));clk_wiz_0 clk(.clk_out1(pixel_clk),.reset(
1'b0),.locked(),.clk_in1(clk100M));endmodule
編寫引腳約束文件,在官方給出的原理圖中都可以查到。
pins.xdc
set_property PACKAGE_PIN Y9 [get_ports {clk100M}]
set_property IOSTANDARD LVCMOS33 [get_ports {clk100M}]
set_property PACKAGE_PIN T18 [get_ports {rst}]
set_property IOSTANDARD LVCMOS33 [get_ports {rst}]
set_property PACKAGE_PIN P16 [get_ports {key}]
set_property IOSTANDARD LVCMOS33 [get_ports {key}]
set_property PACKAGE_PIN T22 [get_ports {led[
0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[
0]}]
set_property PACKAGE_PIN T21 [get_ports {led[
1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[
1]}]
set_property PACKAGE_PIN U22 [get_ports {led[
2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[
2]}]
set_property PACKAGE_PIN U21 [get_ports {led[
3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[
3]}]
set_property PACKAGE_PIN Y19 [get_ports {vga_vs}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_vs}]
set_property PACKAGE_PIN AA19 [get_ports {vga_hs}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_hs}]
set_property PACKAGE_PIN V20 [get_ports {vga_r[
0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_r[
0]}]
set_property PACKAGE_PIN U20 [get_ports {vga_r[
1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_r[
1]}]
set_property PACKAGE_PIN V19 [get_ports {vga_r[
2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_r[
2]}]
set_property PACKAGE_PIN V18 [get_ports {vga_r[
3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_r[
3]}]
set_property PACKAGE_PIN AB22 [get_ports {vga_g[
0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_g[
0]}]
set_property PACKAGE_PIN AA22 [get_ports {vga_g[
1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_g[
1]}]
set_property PACKAGE_PIN AB21 [get_ports {vga_g[
2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_g[
2]}]
set_property PACKAGE_PIN AA21 [get_ports {vga_g[
3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_g[
3]}]
set_property PACKAGE_PIN Y21 [get_ports {vga_b[
0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_b[
0]}]
set_property PACKAGE_PIN Y20 [get_ports {vga_b[
1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_b[
1]}]
set_property PACKAGE_PIN AB20 [get_ports {vga_b[
2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_b[
2]}]
set_property PACKAGE_PIN AB19 [get_ports {vga_b[
3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_b[
3]}]
分析綜合產生比特流文件,后進行下載。
按鍵設置:
圖中BTNU鍵位復位鍵;BTNC鍵位模式切換鍵,每按一次切換顯示模式。
連上vga線,可以看到現象如下:
總結
以上是生活随笔為你收集整理的Zedboard学习(七):VGA显示的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。