Zedboard学习(七):VGA显示

VGA硬件接口
到zedboard官方给出的原理图中查看:

RGB信号,各四位;这里的设计是使用了电阻分压模拟了DAC芯片实现了4X4X4的RGB信号,如果要更好的显示效果还是建议使用专门的DAC。

上面给出了所有的引脚分配。

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)
begin
if(rst)
x_cnt else if(x_cnt == H_Total)
x_cnt else
x_cnt end

//根据时序图参数,产生行同步信号
reg hsync_r;
always @(posedge pixel_clk or posedge rst)
begin
if(rst)
hsync_r else if(x_cnt>=0 && x_cnt hsync_r else
hsync_r end

//行信号有效,即当前数据有效
reg hs_de;
always @(posedge pixel_clk or posedge rst)
begin
if(rst)
hs_de else if(x_cnt>=H_Start && x_cnt hs_de else
hs_de end

//场信号计数器
reg [11:0] y_cnt;
always @(posedge pixel_clk or posedge rst)
begin
if(rst)
y_cnt else if(y_cnt == V_Total)
y_cnt else if(x_cnt == H_Total)
y_cnt end

//根据时序图参数,产生场同步信号
reg vsync_r;
always @(posedge pixel_clk or posedge rst)
begin
if(rst)
vsync_r else if(y_cnt>=0 && y_cnt vsync_r else
vsync_r end

//列信号有效,即当前数据有效
reg vs_de;
always @(posedge pixel_clk or posedge rst)
begin
if(rst)
vs_de else if(y_cnt>=V_Start && y_cnt vs_de else
vs_de end

//按键消抖,按下后延时一段时间,再检测是否按下
reg [16:0] key_counter;
always @(posedge pixel_clk)
begin
if(turn_mode)
key_counter else if((turn_mode == 1'b0) && (key_counter key_counter end

//显示模式技术,每次按下按键,模式改变,最多有12种显示模式
reg [3:0] dis_mode;
assign mode = dis_mode;
always @(posedge pixel_clk)
begin
if(key_counter == 17'h11704)
begin
if(dis_mode == 4'd12)
dis_mode else
dis_mode end
end

//产生小格子,黑白棋盘
reg [7:0] grid_data_1;
always @(posedge pixel_clk)
begin
if((x_cnt[4] == 1'b0) ^ (y_cnt[4] == 1'b0))
grid_data_1 else
grid_data_1 end

//产生大格子,黑白棋盘
reg [7:0] grid_data_2;
always @(posedge pixel_clk)
begin
if((x_cnt[6] == 1'b0) ^ (y_cnt[6] == 1'b0))
grid_data_2 else
grid_data_2 end

//产生彩条
reg [23:0] color_bar;
always @(posedge pixel_clk)
begin
if(x_cnt>=216 && x_cnt color_bar else if(x_cnt>=316 && x_cnt color_bar else if(x_cnt>=416 && x_cnt color_bar else if(x_cnt>=516 && x_cnt color_bar else if(x_cnt>=616 && x_cnt color_bar else if(x_cnt>=716 && x_cnt color_bar else if(x_cnt>=816 && x_cnt color_bar else if(x_cnt>=916 && x_cnt color_bar else
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)
begin
if(rst)
begin
vga_r_reg vga_g_reg vga_b_reg end
else
begin
case(dis_mode)
4'd0: //全黑
begin
vga_r_reg vga_g_reg vga_b_reg end

4'd1: //全白
begin
vga_r_reg vga_g_reg vga_b_reg end

4'd2: //全红
begin
vga_r_reg vga_g_reg vga_b_reg end

4'd3: //全绿
begin
vga_r_reg vga_g_reg vga_b_reg end

4'd4: //全蓝
begin
vga_r_reg vga_g_reg vga_b_reg end

4'd5: //小格子,黑白棋盘
begin
vga_r_reg vga_g_reg vga_b_reg end

4'd6: //大格子,黑白棋盘
begin
vga_r_reg vga_g_reg vga_b_reg end

4'd7: //根据行信号渐变,周期性从黑到白
begin
vga_r_reg vga_g_reg vga_b_reg end

4'd8: //根据场信号渐变,周期性从黑到白
begin
vga_r_reg vga_g_reg vga_b_reg end

4'd9: //根据行信号渐变,周期性红色从浅到深
begin
vga_r_reg vga_g_reg vga_b_reg end

4'd10: //根据列信号渐变,周期性绿色从浅到深
begin
vga_r_reg vga_g_reg vga_b_reg end

4'd11: //根据行信号渐变,周期性蓝色从浅到深
begin
vga_r_reg vga_g_reg vga_b_reg end

4'd12: //彩条信号
begin
vga_r_reg vga_g_reg vga_b_reg end

default:
begin
vga_r_reg vga_g_reg vga_b_reg end
endcase
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
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2017/07/27 23:12:46
// Design Name:
// Module Name: vga_disp
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////

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

# Clk(板子上的GCLK)
set_property PACKAGE_PIN Y9 [get_ports {clk100M}]
set_property IOSTANDARD LVCMOS33 [get_ports {clk100M}]

# Rst(板子上的BTNU)
set_property PACKAGE_PIN T18 [get_ports {rst}]
set_property IOSTANDARD LVCMOS33 [get_ports {rst}]

# key 板子上的按键
set_property PACKAGE_PIN P16 [get_ports {key}]
set_property IOSTANDARD LVCMOS33 [get_ports {key}]

# Led0
set_property PACKAGE_PIN T22 [get_ports {led[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[0]}]

# Led1
set_property PACKAGE_PIN T21 [get_ports {led[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[1]}]

# Led2
set_property PACKAGE_PIN U22 [get_ports {led[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[2]}]

# Led3
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线,可以看到现象如下:












---------------------
作者:hongbin_xu
来源:CSDN
原文:https://blog.csdn.net/hongbin_xu/article/details/76582103

推荐阅读