1、VGA显示原理
VGA,英文全称“Video Graphics Array”,译为视频图形阵列,是一种使用模拟信号进行视频传输的标准协议。
VGA接口电路原理图如下:
VGA只能识别模拟信号,而FPGA输出的图像信息为数字信号,在VGA的图像显示中,想要将数字图像信号转换为VGA能够识别的模拟信号有两种方法。
1.使用专用的转换芯片进行转换,但这样的成本也比较高。
2.如上图所示,采用权电阻网络的方式实现数模转换。
VGAD[15:0]:RGB565图像数据;
VGA_HSYNC:VGA行同步信号,TTL电平;
VGA_VSYNC:VGA场同步信号,TTL电平。
VGA显示器显示图像,并不是直接让图像在显示器上显示出来,而是采用扫描的方式,将构成图像的像素点,在行同步信号和场同步信号的同步下,按照从上到下、由左到右的顺序扫描到显示屏上。VGA显示器扫描方式,具体见下图:
2、VGA时序标准
行时序参数:a:行同步脉冲 b:行后沿 c:行有效 d:行前沿
场时序参数:a:场同步脉冲 b:场后沿 c:场有效 d:场前沿
只有行、场的有效时序交叉区域的数据才有效,也就是图上的黄色区域。
640*480@60
640x480是指VGA的分辨率,640是指有效显示图像每一行有640个像素点,480是指每一帧图像有480行,@60是指VGA显示图像的刷新频率。
时钟(MHz):25.175MHz
这是VGA显示的工作时钟。
3、模块划分
一共分为三部分,接口模块、数据产生模块和一个顶层模块。
参考代码
顶层文件代码
/**************************************************************
@File : ct_top.v
@Time : 2024/05/06 15:56:55
@Author : renchenglong
@EditTool: VS Code
@Font : UTF-8
@Function: 彩条显示顶层
**************************************************************/
`include"../param.vh"
module ct_top(
input clk ,
input rst_n ,
output [`VGA_DATA_W-1:0] vga_data ,
output vga_hsync ,
output vga_vsync
);
wire clk_vga;
wire locked;
vga_if_pll vga_if_pll_inst (
.areset ( ~rst_n ),
.inclk0 ( clk ),
.c0 ( clk_vga ),
.locked ( locked )
);
wire st_ready;
wire st_vld ;
wire st_sop ;
wire st_eop ;
wire [`VGA_DATA_W-1:0] st_data ;
data_gen data_gen(
/*input */ .clk_vga (clk_vga ),
/*input */ .rst_n (locked ),
/*input */ .st_ready (st_ready ),
/*output */ .st_vld (st_vld ),
/*output */ .st_sop (st_sop ),
/*output */ .st_eop (st_eop ),
/*output [`VGA_DATA_W-1:0]*/ .st_data (st_data )
);
vga_interface vga_interface(
/*input */ .clk_vga (clk_vga ), //25.175M
/*input */ .rst_n (locked ),
/*input */ .st_clk (clk_vga ),
/*input */ .st_sop (st_sop ), //数据包开始信号
/*input */ .st_eop (st_eop ), //数据包结束信号
/*input [`VGA_DATA_W-1:0]*/ .st_data (st_data ),
/*input */ .st_vld (st_vld ),
/*output */ .st_ready (st_ready ),
/*output [`VGA_DATA_W-1:0]*/ .vga_data (vga_data ), //图像色彩信息
/*output */ .vga_hsync (vga_hsync ), //行
/*output */ .vga_vsync (vga_vsync ) //场
);
endmodule
接口模块代码
/**************************************************************
@File : vga_interface.v
@Time : 2024/05/06 10:31:55
@Author : renchenglong
@EditTool: VS Code
@Font : UTF-8
@Function: VGA接口模块
**************************************************************/
`include"../param.vh"
module vga_interface(
input clk_vga ,
input rst_n ,
input st_clk ,
input st_sop , //数据包开始信号
input st_eop , //数据包结束信号
input [`VGA_DATA_W-1:0] st_data ,
input st_vld ,
output st_ready ,
output [`VGA_DATA_W-1:0] vga_data , //图像色彩信息
output vga_hsync , //行
output vga_vsync //场
);
reg work_flag;
reg [$clog2(`H_TOTAL)-1:0] cnt_h;
wire add_h_cnt;
wire end_h_cnt;
reg [$clog2(`V_TOTAL)-1:0] cnt_v;
wire add_v_cnt;
wire end_v_cnt;
wire [`VGA_DATA_W+2-1:0] fifo_wr_data;
wire fifo_wr_req ;
wire fifo_rd_req ;
wire [`VGA_DATA_W+2-1:0] fifo_rd_data;
wire fifo_empty ;
wire fifo_full ;
wire vga_active ; //vga处于行场同时有效区域
/**************************************************************
同步fifo,流接口转vga (采用fifo IP源代码,不用再去IP处修改参数,直接在这里改就可以了)
**************************************************************/
assign fifo_wr_req = !fifo_full && st_vld && st_ready;
assign fifo_wr_data = {st_sop,st_eop,st_data};
assign fifo_rd_req = !fifo_empty && vga_active;
assign st_ready = !fifo_full;
dcfifo dcfifo_component (
.aclr (!rst_n ),
.data (fifo_wr_data ),
.rdclk (clk_vga ),
.rdreq (fifo_rd_req ),
.wrclk (st_clk ),
.wrreq (fifo_wr_req ),
.q (fifo_rd_data ),
.rdempty (fifo_empty ),
.wrfull (fifo_full ),
.eccstatus (),
.rdfull (),
.rdusedw (),
.wrempty (),
.wrusedw ());
defparam
dcfifo_component.intended_device_family = "Cyclone IV E",
dcfifo_component.lpm_numwords = `VGA_FIFO_DEPTH, //fifo深度
dcfifo_component.lpm_showahead = "ON", //前显模式
dcfifo_component.lpm_type = "dcfifo",
dcfifo_component.lpm_width = `VGA_DATA_W + 2, //数据宽度 VGA数据位宽+sop+eop
dcfifo_component.lpm_widthu = $clog2(`VGA_FIFO_DEPTH),
dcfifo_component.overflow_checking = "ON",
dcfifo_component.rdsync_delaypipe = 4,
dcfifo_component.read_aclr_synch = "OFF",
dcfifo_component.underflow_checking = "ON",
dcfifo_component.use_eab = "ON",
dcfifo_component.write_aclr_synch = "OFF",
dcfifo_component.wrsync_delaypipe = 4;
/**************************************************************
行场计数器
**************************************************************/
always@(posedge clk_vga or negedge rst_n)
if(!rst_n)
work_flag <= 0;
else if(fifo_rd_data[`VGA_DATA_W + 1]) //识别到sop
work_flag <= 1;
else if(end_v_cnt) //一帧图像传输完成
work_flag <= 0;
always@(posedge clk_vga or negedge rst_n)
if(!rst_n)
cnt_h <= 'd0;
else if(add_h_cnt) begin
if(end_h_cnt)
cnt_h <= 'd0;
else
cnt_h <= cnt_h + 1'b1;
end
assign add_h_cnt = work_flag ;
assign end_h_cnt = add_h_cnt && cnt_h == `H_TOTAL - 1 ;
always@(posedge clk_vga or negedge rst_n)
if(!rst_n)
cnt_v <= 'd0;
else if(add_v_cnt) begin
if(end_v_cnt)
cnt_v <= 'd0;
else
cnt_v <= cnt_v + 1'b1;
end
assign add_v_cnt = end_h_cnt ;
assign end_v_cnt = add_v_cnt && cnt_v == `V_TOTAL - 1 ;
assign vga_active = (cnt_h >= `H_SYNC + `H_BACK) && (cnt_h < `H_SYNC + `H_BACK + `H_AVLD) && //数据有效区域
(cnt_v >= `V_SYNC + `V_BACK) && (cnt_v < `V_SYNC + `V_BACK + `V_AVLD);
/**************************************************************
VGA输出
**************************************************************/
assign vga_data = vga_active? fifo_rd_data[15:0] : 0;
assign vga_hsync = cnt_h >= `H_SYNC;
assign vga_vsync = cnt_v >= `V_SYNC;
endmodule
彩条数据产生模块
/**************************************************************
@File : data_gen.v
@Time : 2024/05/06 14:05:35
@Author : renchenglong
@EditTool: VS Code
@Font : UTF-8
@Function: 彩条数据提供模块
**************************************************************/
`include"../param.vh"
module data_gen(
input clk_vga ,
input rst_n ,
input st_ready,
output st_vld ,
output st_sop ,
output st_eop ,
output [`VGA_DATA_W-1:0] st_data
);
reg [$clog2(`H_AVLD)-1:0] cnt_h;
wire add_h_cnt;
wire end_h_cnt;
reg [$clog2(`V_AVLD)-1:0] cnt_v;
wire add_v_cnt;
wire end_v_cnt;
reg [`VGA_DATA_W-1:0] pix_data ;
/**************************************************************
行、场计数器
**************************************************************/
always@(posedge clk_vga or negedge rst_n)
if(!rst_n)
cnt_h <= 'd0;
else if(add_h_cnt) begin
if(end_h_cnt)
cnt_h <= 'd0;
else
cnt_h <= cnt_h + 1'b1;
end
assign add_h_cnt = st_ready ;
assign end_h_cnt = add_h_cnt && cnt_h == `H_AVLD - 1 ;
always@(posedge clk_vga or negedge rst_n)
if(!rst_n)
cnt_v <= 'd0;
else if(add_v_cnt) begin
if(end_v_cnt)
cnt_v <= 'd0;
else
cnt_v <= cnt_v + 1'b1;
end
assign add_v_cnt = end_h_cnt ;
assign end_v_cnt = add_v_cnt && cnt_v ==`V_AVLD - 1 ;
/**************************************************************
输出彩条
**************************************************************/
assign st_sop = cnt_h == 0 && cnt_v == 0; //第一个像素
assign st_eop = end_v_cnt; //最后一个像素
assign st_vld = add_h_cnt;
assign st_data = pix_data ;
always@(*) //十个彩条 可随意调节
if(cnt_v < `V_AVLD*1/10)
pix_data = `RED;
else if(cnt_v < `V_AVLD*2/10)
pix_data = `ORANGE;
else if(cnt_v < `V_AVLD*3/10)
pix_data = `YELLOW;
else if(cnt_v < `V_AVLD*4/10)
pix_data = `GREEN;
else if(cnt_v < `V_AVLD*5/10)
pix_data = `CYAN;
else if(cnt_v < `V_AVLD*6/10)
pix_data = `BLUE;
else if(cnt_v < `V_AVLD*7/10)
pix_data = `PURPPLE;
else if(cnt_v < `V_AVLD*8/10)
pix_data = `BLACK;
else if(cnt_v < `V_AVLD*9/10)
pix_data = `WHITE;
else
pix_data = `GRAY;
endmodule
相关参数文件
/**************************************************************
@File : param.vh
@Time : 2024/05/06 11:15:55
@Author : renchenglong
@EditTool: VS Code
@Font : UTF-8
@Function: 参数定义
**************************************************************/
/**************************************************************
系统参数选择
**************************************************************/
// `define BMP //仿真调试是否使用BMP图片输出,只能用于仿真
//选择输出边缘检测的方法 二选一
//`define MID_SOBEL //中间值
//`define GAUSS_SOBEL //高斯
// `define min //仅用于仿真测试
`define pix_640x480
`define OV5640_LUT_NUM 252
`define VGA_FIFO_DEPTH 64
`define VDMA_FIFO_DEPTH 2048 //fifo深度
`define VDMA_FIFO_DATA_W 18 //VDMA数据位宽 + sop + eop
/**************************************************************
图像算法
**************************************************************/
`define VIP_DATA_W 8
/**************************************************************
VGA彩条测试
**************************************************************/
`define RED 16'hF800 //红色
`define ORANGE 16'hFC00 //橙色
`define YELLOW 16'hFFE0 //黄色
`define GREEN 16'h07E0 //绿色
`define CYAN 16'h07FF //青色
`define BLUE 16'h001F //蓝色
`define PURPPLE 16'hF81F //紫色
`define BLACK 16'h0000 //黑色
`define WHITE 16'hFFFF //白色
`define GRAY 16'hD69A //灰色
/**************************************************************
VGA接口配置
**************************************************************/
`define VGA_DATA_W 16 //VGA数据位宽
`ifdef pix_640x480
//640*480@60 时钟25.175Mhz
`define H_SYNC 96 //行 同步脉冲
`define H_BACK 48 //行 后沿
`define H_AVLD 640 //行 数据有效
`define H_FRONT 16 //行 前沿
`define V_SYNC 2 //列 同步脉冲
`define V_BACK 33 //列 后沿
`define V_AVLD 480 //列 数据有效
`define V_FRONT 10 //列 前沿
`elsif min //仿真用
`define H_SYNC 96/10
`define H_BACK 48/10
`define H_AVLD 640/10
`define H_FRONT 16/10
`define V_SYNC 2
`define V_BACK 33/10
`define V_AVLD 480/10
`define V_FRONT 10/10
`else
//1280*720@60 时钟74.25Mhz
`define H_SYNC 40
`define H_BACK 220
`define H_AVLD 1280
`define H_FRONT 110
`define V_SYNC 5
`define V_BACK 20
`define V_AVLD 720
`define V_FRONT 5
`endif
`define H_TOTAL `H_SYNC+`H_BACK+`H_AVLD+`H_FRONT //行 扫描周期
`define V_TOTAL `V_SYNC+`V_BACK+`V_AVLD+`V_FRONT //列 扫描周期