大家可以根据B站小梅哥进行学习
分辨率为640*480
根据行场同步信号需要的各个时间节点。
以行扫描进行分析:(场扫描同理)
- Sync Pulse对应 H Sync Time 时间节点96,即代码中的HS_End
- Back Porch对应 H Back Porch 时间节点40
- Left Border对应H Left Border 时间节点8
- 此时行数据开始信号即代码中的Hdat_Begin = 96+40+8=144 即上面序号1.2.3时间节点相加
- Visible area对应HData Time 时间节点640即行像素
- 此时代码中的Hdat_End = 144 + 640=784 即数据结束位置
- Right Boder对应H Right Bordes 时间节点8
- Front Porch对应 H Front Porch 时间节点8
- H Total Time = 96+40+8+640+8+8 = 800 即代码中的Hsync_End =800
设计代码:
//640*480
module VGA_CTRL(
input Clk,//时钟25Mhz换算成40ns
input Rest_n,
input [23:0]Data,//输入24位数据
output reg [9:0]hcount,//扫描行像素的位置 640换算成2进制为10位
output reg [8:0]vcount,//扫描场像素的位置 480换算成2进制为9位
output reg VGA_HS,//行脉冲信号
output reg VGA_VS,//场脉冲信号
output reg VGA_Blk,//像素输出信号 0-639 0-479
output reg Data_Req,//数据请求脉冲信号,用于延时一拍,将像素输出信号与数据实时对应
output reg [23:0]VGA_RGB//输出24位数据
);
localparam Hsync_End = 800;//行同步信号结束位置
localparam Vsync_End = 525;//场同步信号结束位置:单位行
localparam HS_End = 96;//行同步脉冲结束位置
localparam VS_End = 2;//场同步脉冲结束位置:单位行
localparam Hdat_Begin = 144;//行数据开始输出位置
localparam Hdat_End = 784;//行数据结束输出位置
localparam Vdat_Begin = 35;//场数据开始输出位置:单位行
localparam Vdat_End = 515;//场数据结束输出位置:单位行
//行计数器
reg [9:0] h_cnt;//行总共需要计数800个像素,换算为2进制为10位
always @(posedge Clk or negedge Rest_n)
if(!Rest_n)
h_cnt <= 1'b0;
else if( h_cnt == Hsync_End - 1'd1 )
h_cnt <= 1'b0;
else
h_cnt <= h_cnt + 1'b1;
//行脉冲信号
always @(posedge Clk)
VGA_HS <= (h_cnt <= (HS_End - 1'd1)) ? 0:1;
//场计数器
reg [9:0] v_cnt;//场总共需要计数525个像素,换算为2进制为10位
always @(posedge Clk or negedge Rest_n)
if(!Rest_n)
v_cnt <= 1'b0;
else if( h_cnt == Hsync_End - 1'd1 )
begin
if(v_cnt == Vsync_End - 1'd1)
v_cnt <= 1'b0;
else
v_cnt <= v_cnt + 1'b1;
end
else
v_cnt <= v_cnt;
//场脉冲信号
always @(posedge Clk)
VGA_VS <= (v_cnt <= (VS_End - 1'd1)) ? 0:1;
//数据输出信号
always @(posedge Clk)
Data_Req <= ((h_cnt >= Hdat_Begin - 1'd1)&&(h_cnt < Hdat_End - 1'd1)&&(v_cnt > Vdat_Begin - 1'd1 )&&(v_cnt <= Vdat_End -1'd1))?1:0;
always @(posedge Clk)
VGA_Blk <= Data_Req;
//数据输出
always @(posedge Clk)
VGA_RGB <= Data_Req ? Data: 0;
//行扫描像素输出
always @(posedge Clk)
hcount <= Data_Req ? (h_cnt - Hdat_Begin):0;
//场扫描像素输出
always @(posedge Clk)
vcount <= Data_Req ? (v_cnt - Vdat_Begin):0;
endmodule
测试代码:
`timescale 1ns / 1ps
module VGA_CTRL_tb();
reg Clk;
reg Rest_n;
reg [23:0]Data;
wire [9:0]hcount;
wire [8:0]vcount;
wire VGA_HS;
wire VGA_VS;
wire VGA_Blk;
wire [23:0]VGA_RGB;
wire Data_Req;
VGA_CTRL VGA_CTRL(
Clk,
Rest_n,
Data,
hcount,
vcount,
VGA_HS,
VGA_VS,
VGA_Blk,
Data_Req,
VGA_RGB
);
initial Clk = 1;
always #20 Clk = ~Clk;//25M时钟 1/25000000=40ns 即20ns翻转一次
initial begin
Rest_n = 0;
#201;
Rest_n = 1;
#200000000;
$stop;
end
always @( posedge Clk or negedge Rest_n )
if(!Rest_n)
Data <= 1'b0;
else if(Data_Req)
Data <= Data + 1'b1;
else
Data <= Data;
endmodule