这里为640*480分辨率的屏幕设计一个VGA控制器
其行扫描过程如下:
场扫描过程:
代码如下:
module VGA_TEST (
input Pclk25M, //VGA 像素时钟,25MHz
input Rst_n,
input [23:0] data_in, //待显示数据输入端口
output [9:0] X_addr, //图像区行扫描地址
output [9:0] Y_addr, //图像区场扫描地址
output H_pluse, //VGA 接口行同步信号
output V_pluse, //VGA 接口场同步信号
output VGA_BLK, //场消隐信号
output VGA_CLK, //VGA 时钟输出
output [23:0] VGA_RGB //VGA 三元色数据输出
);
reg [9:0] H_count;
reg [9:0] V_count;
wire data_valid;
//输出数据锁存时钟信号
assign VGA_CLK = ~Pclk25M; //将VGA控制器时钟信号取反输出,作为DAC数据锁存信号
//行计数器
always @(posedge Pclk25M or negedge Rst_n) begin
if(!Rst_n)
H_count <= 0;
else if(H_count == 10'd799)
H_count <= 0;
else
H_count <= H_count + 1'b1;
end
//场计数器
always @(posedge Pclk25M or negedge Rst_n) begin
if(!Rst_n)
V_count <= 0;
else if(H_count == 10'd799)
begin
if(V_count == 10'd524)
V_count <= 0;
else
V_count <= V_count + 1'b1;
end
else
V_count <= V_count;
end
//行使能脉冲结束时间--行同步信号
assign H_pluse = (H_count > 10'd95);
//场使能脉冲结束时间--场同步信号
assign V_pluse = (V_count > 10'd1);
//数据输出有效信号
assign data_valid = ((H_count > 10'd143) && (H_count < 10'd783))
&& ((V_count > 10'd34) && (V_count > 10'd514));
//场消隐信号
assign VGA_BLK = data_valid;
//信号输出
assign VGA_RGB = data_valid ? data_in : 24'h000000;
//行位置信号
assign X_addr = data_valid ? (H_count - 10'd143) : 10'd0;
//列位置信号
assign Y_addr = data_valid ? (V_count - 10'd34) : 10'd0;
endmodule
接下来对其进行仿真验证,仿真文件如下:
`timescale 1ns/1ns
`define clock_period 40
module VGA_TEST_tb ();
reg Pclk25M;
reg Rst_n;
reg [23:0] data_in;
wire [9:0] X_addr;
wire [9:0] Y_addr
wire H_pluse;
wire V_pluse;
wire VGA_BLK;
wire VGA_CLK;
wire [23:0] VGA_RGB;
reg [11:0] V_cnt = 0;
initial Pclk25M = 1;
always #20 Pclk25M = ~Pclk25M;
VGA_TEST VGA_TEST(
.Pclk25M(Pclk25M), //VGA 像素时钟,25MHz
.Rst_n(Rst_n),
.data_in(data_in), //待显示数据输入端口
.X_addr(X_addr), //图像区行扫描地址
.Y_addr(Y_addr), //图像区场扫描地址
.H_pluse(H_pluse), //VGA 接口行同步信号
.V_pluse(V_pluse), //VGA 接口场同步信号
.VGA_BLK(VGA_BLK),
.VGA_CLK(VGA_CLK),
.VGA_RGB(VGA_RGB) //VGA 三元色数据输出
);
initial begin
Rst_n = 0;
data_in = 0;
#101;
Rst_n = 1;
data_in = 24'hffffff;
end
always @ (posedge V_pluse)
V_cnt <= V_cnt + 1'b1;
initial begin
wait(V_cnt == 3);
$stop;
end
endmodule
仿真结果如下:
将代码改写成参数化定义,方便修改分辨率以适配不同尺寸的屏幕
module VGA_TEST (
input Pclk25M, //VGA 像素时钟,25MHz
input Rst_n,
input [23:0] data_in, //待显示数据输入端口
output [9:0] X_addr, //图像区行扫描地址
output [9:0] Y_addr, //图像区场扫描地址
output H_pluse, //VGA 接口行同步信号
output V_pluse, //VGA 接口场同步信号
output VGA_BLK,
output VGA_CLK,
output [23:0] VGA_RGB //VGA 三元色数据输出
);
reg [9:0] H_count;
reg [9:0] V_count;
wire data_valid;
parameter VGA_H_END = 10'd799, //行分辨率的最大像素值
VGA_V_END = 10'd524, //列分辨率的最大像素值
H_data_start = 10'd143, //行数据有效开始
H_data_end = 10'd783, //行数据有效结束
V_data_start = 10'd34, //场数据有效开始
V_data_end = 10'd514, //场数据有效结束
H_pluse_end = 10'd95, //行同步信号上升沿
V_pluse_end = 10'd1; //场同步信号上升沿
//输出数据锁存时钟信号
assign VGA_CLK = ~Pclk25M; //将VGA控制器时钟信号取反输出,作为DAC数据锁存信号
//行计数器
always @(posedge Pclk25M or negedge Rst_n) begin
if(!Rst_n)
H_count <= 0;
else if(H_count == VGA_H_END)
H_count <= 0;
else
H_count <= H_count + 1'b1;
end
//场计数器
always @(posedge Pclk25M or negedge Rst_n) begin
if(!Rst_n)
V_count <= 0;
else if(H_count == VGA_H_END)
begin
if(V_count == VGA_V_END)
V_count <= 0;
else
V_count <= V_count + 1'b1;
end
else
V_count <= V_count;
end
//行使能脉冲结束时间--行同步信号
assign H_pluse = (H_count > H_pluse_end);
//场使能脉冲结束时间--场同步信号
assign V_pluse = (V_count > V_pluse_end);
//数据输出有效信号
assign data_valid = ((H_count > H_data_start) && (H_count < H_data_end))
&& ((V_count > V_data_start) && (V_count > V_data_end));
//场消隐信号
assign VGA_BLK = data_valid;
//信号输出
assign VGA_RGB = data_valid ? data_in : 24'h000000;
//行位置信号
assign X_addr = data_valid ? (H_count - H_data_start) : 10'd0;
//列位置信号
assign Y_addr = data_valid ? (V_count - V_data_start) : 10'd0;
endmodule