使用 FPGA 驱动 VGA 虽然不适合用来显示复杂多变的图像内容,但是却常用于显示实时图像内容,例如显示图像传感器实时采集到的图像。此种方式数据流由图像传感器实时提
供,FPGA 只需要控制好图像数据流的存储和传输即可,无需主动生成需要绘制的图像数据,
所以实现相对简单。
图像的采集和显示系统设计,我们首先解决VGA部分的理解与代码设计
一、VGA理解
我们的设计目的是设计一个能够产生符合 VGA 显示时序的逻辑控制器,为了实现这个目的,我们需要产生用于行同步的行同步信号脉冲(horizontal sync pulse)、用于场同步的场同步信号脉冲(vertical sync pulse)、并在一行图像的显示有效区间内将需要显示的图像内容的对应像素点的颜色数据输出,在一场图像的显示有效区间内使能将需要显示的图像内容输出。
640*480分辨率的参数设置
对于行同步信号,其行同步头为一行扫描的前 96 个像素时钟周期。其场同步头为一行扫描的前 2 个像素时钟周期 。
二、Verilog代码设计及仿真
`timescale 1ns / 1ps
module VGA_1#(
parameter H_SYNC_TIME = 10'd96 , //H_xxx 行相关参数单位为 像素单元
H_BACK_PORCH = 10'd40 ,
H_LEFT_BORDER = 10'd8 ,
H_DATA_TIME = 10'd640 ,
H_RIGHT_BORDER = 10'd8 ,
H_FRONT_PORCH = 10'd8 ,
V_SYNC_TIME = 10'd2 , //V_xxx 列相关参数单位为 行
V_BACK_PORCH = 10'd25 ,
V_TOP_BORDER = 10'd8 ,
V_DATA_TIME = 10'd480 ,
V_BOTTOM_BORDER = 10'd8 ,
V_FRONT_PORCH = 10'd2
)(
input i_clk50M ,
input i_rst_n ,
input [23:0] i_data ,
output o_VGA_HS , //VGA行同步信号
output o_VGA_VS , //VGA场同步信号
output[23:0] o_VGA_data ,
output[9:0] o_hcount , //方便模块调用实时扫描位置输出
output[9:0] o_vcount
);
localparam
VGA_HS_end = H_SYNC_TIME - 1 ,
hdat_begin = VGA_HS_end + H_BACK_PORCH + H_LEFT_BORDER ,
hdat_end = hdat_begin + H_DATA_TIME ,
hpixel_end = hdat_end + H_RIGHT_BORDER + H_FRONT_PORCH ,
VGA_VS_end = V_SYNC_TIME - 1 ,
vdat_begin = VGA_VS_end + V_BACK_PORCH + V_TOP_BORDER ,
vdat_end = vdat_begin + V_DATA_TIME ,
vline_end = vdat_end + V_BOTTOM_BORDER + V_FRONT_PORCH;
reg [9:0] r_hcount; //修改分辨时,注意计数器的位数修改
reg [9:0] r_vcount;
wire data_valid; //有效显示区标定
assign data_valid = ((r_hcount >= hdat_end)&&(r_hcount <= hdat_end))
&&((r_vcount >= vdat_begin)&&(r_vcount <= vdat_end));
assign o_VGA_HS = (r_hcount > VGA_HS_end);
assign o_VGA_VS = (r_vcount > VGA_VS_end);
assign o_hcount = data_valid ? (r_hcount - hdat_begin) : 'd0;
assign o_vcount = data_valid ? (r_vcount - vdat_begin) : 'd0;
assign o_VGA_data = (data_valid) ? i_data : 'd0;
always @(posedge i_clk50M or negedge i_rst_n) begin
if(!i_rst_n)
r_hcount <= 'd0;
else if(r_hcount >= hpixel_end)
r_hcount <= 'd0;
else
r_hcount <= r_hcount + 1;
end
always @(posedge i_clk50M or negedge i_rst_n) begin
if(!i_rst_n)
r_vcount <= 'd0;
else if(r_hcount >= hpixel_end)begin
if(r_vcount >= vline_end)
r_vcount <= 'd0;
else
r_vcount <= r_vcount + 1;
end
else
r_vcount <= r_vcount;
end
endmodule
tb文件(省去例化)
initial r_clk50M = 0;
always #(`clk_period / 2) r_clk50M = ~r_clk50M;
initial begin
r_rst_n = 0;
r_data = 0;
#(`clk_period * 20 + 1);
r_rst_n = 1;
r_data = 24'hffffff;
end
在线仿真
由上图可知,行同步输出信号满足时序要求。
由上图可知,场同步输出信号满足时序要求。