一、任务需求:
设计VGA接口驱动,显示图像的分辨率为640*480,60hz,显示全白色。
二、VGA介绍
三、需求分析
要求显示一张640*480的纯白色图像,刷新率60Hz。
1、行时序中,一个周期内,依次 同步脉冲a,显示后延b,显示时序段c,显示前沿d 共四段组成,按照640*480,60Hz要求a段96个脉冲,b段45个脉冲,c段数据段646个脉冲,d段13个脉冲,一行的长度就是96+45+646+13 = 800个脉冲(像素,一个脉冲一个像素)。至此,传输完了一个图像的一行。
2、场时序,垂直时序,一个中期内的过程与行时序相同,也分为同步脉冲a,显示后延b,显示时序段c,显示前沿d四个阶段,但是场时序的单位是 一行 的时间(也就是行时序中一个周期的时间,此例子中是800个脉冲)。a段是2行,b段是30行,c段数据段是484行,d段9行。总共2+30+484+9 = 525行。至此传输完了一副完整的图像。
也就是说,真正的图像是640*480个像素,但是实际上花费的时间可以传输800*525个像素,但是实际上就传输了640*480个像素,其他时间用来进行同步和显示前沿和显示后沿了。
我们计算出了传输一幅图像的需要800*525个单位时间,但是每个单位时间是多少?
图像的刷新频率是60Hz,也就是一秒钟刷新60次,一幅图像的显示时间是1s/60,一幅图像有525行的单位时间,所以每一行的时间是(1/60)/525 = 31.75us,一行有800个像素点的时间,所以一个像素点的时间是31.75us/800 = 40ns。我们希望每一个时钟的上升沿传输一个像素点(一拍一个),也就是传输时钟周期是40ns,频率为25MHz。
我的板子上的时钟是50MHz,需要分频。
四、代码实现
1、利用Quartus IP产生二分频(25MHz)的时钟。
2、设计vga_driver.v代码。
3、设计顶层代码。
4、仿真。
五、源代码分享
/****************************
name: vga_driver.v
time: 2021/04/08
author: csdn_A_PIG
describe: This is a VGA driver, the whole screen is white
****************************/
module vga_driver(
clk ,
rst_n ,
lcd_hs ,
lcd_vs ,
lcd_data
);
//define input signal
input clk ;//VGA clock = 25MHz.
input rst_n ;
//define output signal
output lcd_hs ;//行同步信号
output lcd_vs ;//场同步信号
//The RGB signal of VGA,lcd_data[15:13] is R,lcd_data[10:8] is G,lcd_data[4:2]is B;
output[7:0] lcd_data;
reg lcd_hs ;
reg lcd_vs ;
reg [15:0] lcd_data;
reg[9:0] lcd_hs_cnt ;//count for lcd_hs:0-799
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
lcd_hs_cnt <= 10'b0;
end
else if(lcd_hs_cnt == 10'd799) begin
lcd_hs_cnt <= 10'b0;
end
else begin
lcd_hs_cnt <= lcd_hs_cnt + 1;
end
end
//行同步信号
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
lcd_hs <= 1'b0;
end
else if(lcd_hs_cnt == 10'd95)begin
lcd_hs <= 1'b1;
end
else if(lcd_hs_cnt == 10'd799)begin
lcd_hs <= 1'b0;
end
end
//场计数器--计数有多少行
reg[9:0] lcd_vs_cnt;
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
lcd_vs_cnt <= 10'b0;
end
else if(lcd_hs_cnt == 10'd799)begin
if(lcd_vs_cnt == 10'd524)
lcd_vs_cnt <= 10'b0;
else
lcd_vs_cnt <= lcd_vs_cnt + 1'b1;
end
end
//场信号
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
lcd_vs <= 1'b0;
end
else if(lcd_vs_cnt<10'd2)begin
lcd_vs <= 1'b0;
end
else
lcd_vs <= 1'b1;
end
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
lcd_data <= 8'b0;
end
else if(lcd_vs_cnt<32)begin
lcd_data <= 8'b0;
end
else if(lcd_vs_cnt>484+32-1)begin
lcd_data <= 8'b0;
end
else begin
if(lcd_hs_cnt<(96+45))begin
lcd_data <= 0;
end
else if(lcd_hs_cnt>(96+45+646-1))begin
lcd_data <= 0;
end
else begin
lcd_data <= 16'b11111_111111_11111;//All screen is white.
end
end
end
endmodule