VGA Video Graphics Array
视频图形阵列,一种使用模拟信号进行视频传输的标准
接口定义
行同步时序
行扫描,一行扫描周期扫完后继续下一行扫描
场同步时序
一次场扫描周期中可以完成一帧图像的显示,单位是一个完整的行扫描周期
分辨率
@60:每秒钟刷新60次
时钟计算:800x525x60=25200000,与时钟周期有微小差异
系统框图:
顶层模块原理图
代码
module vga_colorbar(
input sys_clk,
input sys_rst_n,
output vga_hs,
output vga_vs,
output [15:0] vga_rgb
);
wire vga_clk_w;
wire locked_w;
wire rst_n_w;
wire [15:0] pixel_data_w;
wire [9:0] pixel_xpos_w;
wire [9:0] pixel_ypos_w;
assign rst_n_w = sys_rst_n & locked_w;
vga_pll u_vga_pll(
.inclk0 (sys_clk),
.areset (~sys_rst_n),
.c0 (vga_clk_w),
.locked_w (locked_w)
);
vga_driver u_vga_driver(
.vga_clk (vga_clk_w),
.sys_rst_n (rst_n_w),
.vga_hs (vga_hs),
.vga_vs (vga_vs),
.vga_rgb (vga_rgb),
.pixel_data (pixel_data_w),
.pixel_xpos (pixel_xpos_w),
.pixel_ypos (pixel_ypos_w)
);
vga_display u_vga_display(
.vga_clk (vga_clk_w),
.sys_rst_n (rst_n_w),
.pixel_data (pixel_data_w),
.pixel_xpos (pixel_xpos_w),
.pixel_ypos (pixel_ypos_w)
);
endmodule
module vga_driver(
input vga_clk ,
input sys_rst_n,
output vga_hs , //行同步信号
output vga_vs ,//场同步信号
output [15:0] vga_rgb ,//红绿蓝三原色输出
input [15:0] pixel_data, //像素点数据
output [9:0] pixel_xpos, //像素点横坐标
output [9:0] pixel_ypos //像素点纵坐标
);
parameter H_SYNC = 10'd96; //行同步
parameter H_BACK = 10'd48; //行显示后沿
parameter H_DISP = 10'd640; //行有效数据
parameter H_FRONT = 10'd16; //行显示前沿
parameter H_TOTAL = 10'd800; //行扫描周期
parameter V_SYNC = 10'd2; //场同步
parameter V_BACK = 10'd33; //场显示后沿
parameter V_DISP = 10'd480; //场有效数据
parameter V_FRONT = 10'd10; //场显示前沿
parameter V_TOTAL = 10'd525; //场扫描周期
reg [9:0] cnt_h;
reg [9:0] cnt_v;
wire vga_en;
wire data_req;
assign vga_hs = (cnt_h <= H_SYNC - 1'b1)?1'b0:1'b1;
assign vga_vs = (cnt_v <= V_SYNC - 1'b1)?1'b0:1'b1;
assign vga_en = (((cnt_h >= H_SYNC + H_BACK) && (cnt_h < H_SYNC + H_BACK + H_DISP))
&& ((cnt_v >= V_SYNC + V_BACK) && (cnt_v < V_SYNC + V_BACK + V_DISP)))
? 1'b1:1'b0;
//RGB565数据输出
assign vga_rgb = vga_en ? pixel_data : 16'd0;
//请求像素点颜色数据输入
assign vga_req = (((cnt_h >= H_SYNC + H_BACK - 1'b1) && (cnt_h < H_SYNC + H_BACK + H_DISP - 1'b1))
&& ((cnt_v >= V_SYNC + V_BACK) && (cnt_v < V_SYNC + V_BACK + V_DISP)))
? 1'b1:1'b0;
//像素点坐标
assign pixel_xpos = data_req ? (cnt_h - (H_SYNC + H_BACK - 1'b1)) : 10'd0;
assign pixel_ypos = data_req ? (cnt_v - (V_SYNC + V_BACK - 1'b1)) : 10'd0;
always @(posedge vga_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt_h <= 10'd0;
else begin
if(cnt_h < H_TOTAL - 1'b1)
cnt_h <= cnt_h + 1'b1;
else
cnt_h <= 10'd0;
end
end
always @(posedge vga_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt_v <= 10'd0;
else if(cnt_h == H_TOTAL = 1'b1) begin
if(cnt_v < V_TOTAL - 1'b1)
cnt_v <= cnt_v + 1'b1;
else
cnt_v <= 10'd0;
end
end
endmodule
module vga_display(
input vga_clk ,
input sys_rst_n,
,
input [9:0] pixel_data,
input [9:0] pixel_xpos,
output reg [15:0] pixel_ypos
);
parameter H_DISP = 10'd640; //分辨率--行
parameter V_DISP = 10'd480; //分辨率--列
localparam WHITE = 16'b11111_11111_11111;
localparam BLACK = 16'b00000_00000_00000;
localparam RED = 16'b11111_00000_00000;
localparam GREEN = 16'b00000_11111_00000;
localparam BLUE = 16'b00000_00000_11111;
always @(posedge vga_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
pixel_data <= 16'd0;
else begin
if((pixel_data >= 0) && (pixel_xpos <= (H_DISP/5)*1))
pixel_data <= WHITE;
else if((pixel_data >= (H_DISP/5)*1)) && (pixel_xpos <= (H_DISP/5)*2))
pixel_data <= BLACK;
else if((pixel_data >= (H_DISP/5)*2)) && (pixel_xpos <= (H_DISP/5)*3))
pixel_data <= RED;
else if((pixel_data >= (H_DISP/5)*3)) && (pixel_xpos <= (H_DISP/5)*4))
pixel_data <= GREEN;
else
pixel_data <= BLUE;
end
end
endmodule
显示结果:
方块移动只需要更改上述代码的display模块:
module vga_display(
input vga_clk ,
input sys_rst_n,
,
input [9:0] pixel_data,
input [9:0] pixel_xpos,
output reg [15:0] pixel_ypos
);
parameter H_DISP = 10'd640;
parameter V_DISP = 10'd480;
localparam SIDE_W = 10'd40;
localparam BLOCK_W = 10'd40;
localparam BLUE = 16'b00000_00000_11111;
localparam WHITE = 16'b11111_11111_11111;
localparam BLACK = 16'b00000_00000_00000;
reg [9:0] block_x;
reg [9:0] block_y;
reg [21:0] div_cnt;
reg h_direct;
reg v_direct;
wire move_en;
assign move_en = (div_cnt == 22'd250000 - 1'b1)? 1'b1:1'b0;
//通过对vga驱动时钟技术,实现时钟分频
always @(posedge vga_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
div_cnt <= 22'd0;
else begin
if(div_cnt < 22'd250000 - 1'b1)
div_cnt <= div_cnt + 1'b1;
else
div_cnt <= 22'd0;
end
end
//当方块移动到边界时,改变移动方向
always @(posedge vga_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
h_direct <= 1'b1;
v_direct <= 1'b1;
end
else begin
if(block_x == SIDE_W - 1'b1)
h_direct <= 1'b1;
else
if(block_x == H_DISP - SIDE_W - BLOCK_W)
h_direct <= 1'b0;
else
h_direct <= h_direct;
if(block_y == SIDE_W - 1'b1)
v_direct <= 1'b1;
else
if(block_y == V_DISP - SIDE_W - BLOCK_W)
v_direct <= 1'b0;
else
v_direct <= v_direct;
end
end
//根据方块移动方向,改变其纵横坐标
always @(posedge vga_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
block_x <= 22'd100;
block_y <= 22'd100;
end
else if(move_en) begin
if(h_direct)
block_x <= block_x + 1'b1;
else
block_x <= block_x - 1'b1;
if(v_direct)
block_y <= block_y + 1'b1;
else
block_y <= block_y - 1'b1;
end
else begin
block_x <= block_x;
block_y <= block_y;
end
end
//给不同的区域绘制不同的颜色
always @(posedge vga_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
pixel_data <= BLACK;
else begin
if((pixel_xpos < SIDE_W) || (pixel_data >= H_DISP - SIDE_W)
|| (pixel_ypos < SIDE_W) || (pixel_data >= V_DISP - SIDE_W))
pixel_data <= BLUE;
else
if((pixel_xpos >= block_x) || (pixel_data < block_x + BLOCK_W)
|| (pixel_ypos >= block_y) || (pixel_data < block_y + BLOCK_W))
pixel_data <= BLUE;
else
pixel_data <= WHITE;
end
end
endmodule