目录
第一部分、实验结果
1、横的三色彩条效果
2、竖的三色彩条效果
第二部分、VGA驱动基本知识
1、VGA分辨率问题
2、VGA驱动波形
2.1、工业标准的时序波形图
2.2、比上面那张图更容易理解的图
2.3、每个区域对应的时间
2.4、不同分辨率的表格
3、VGA扫描范围问题
第三部分、VGA的时序波形图
第四部分、VGA的驱动代码
1、top-down结构图:
2、vga_ctrl.v模块代码:
3、top层代码
第五部分、总结
首先,关于VGA的深层次工作原理可以百度自行了解。
我的理解比较简单,我记得高中的物理课的时候物理老师有提过老式电视机的显示原理,一般老式电视机的都特别大,而且都有个大屁股,这是因为后面有个电子枪,疯狂的朝着电视的屏幕喷射电子,然后就出现的显示,而且喷射的顺序就是从屏幕的左上角到右下角。而VGA的原理和这个类似。
首先不同分辨率对应的驱动程序是稍有区别的,正常情况下显示器都支持很多种分辨率,例如我电脑屏幕现在用的显示器分辨率为1920 * 1080@60Hz。(查看方式:选择 “开始 > 设置 > 系统 > 显示 > 高级显示器 )
而本次实验选用的分辨率为640*480@60Hz,60Hz为刷新频率,也就是1s钟电脑显示60张图片,也就是从电子束从屏幕的左上角到右下角这个过程执行了60次。
这里发射的过程可以理解为扫描的过程,这样后面理解驱动程序时会简单许多。
HSync称作行同步信号,VSync称作场同步信号或者垂直同步信号。
图片来源于该篇博客http://t.csdn.cn/Hqvtc,有问题联系我删除。这张图翻译了上面每条英文的意思。
这张图来源于哪一篇博客我忘记了(有问题联系我删除),反正是一篇很好的博客,解释的更加透彻,每段时间点都标出来的。
该图片还是来源于该篇博客http://t.csdn.cn/Hqvtc,有问题联系我删除。这个表格解释不同分辨率,同步,后沿等时间的区别。
当然这里也有一个网址可以参考:VGA Signal Timing (tinyvga.com)
这里不同分辨率的驱动时钟计算方法如下:
时钟 = 行扫描周期 * 场扫描周期 * 刷新频率
以640*480@60分辨率的计算方式:
800 * 525 * 60 = 25,200,000 约等于 25MHz
看了上面的表格,不知道大家有没有有个问题,为什么分辨率640*480@60的行扫描为800(像素)而不是640(像素),场扫描为525(行数)而不是480(行数)?
因为640只是有效图像的像素点长度,除了这些还有其他的也要考虑进去,所有像素点的总和才为800。如下图所示,真正显示在屏幕上的只是灰色区域。
由上面,关于VGA的时序了解了差不多,这里需要注意的是:行扫描时序要求(单位:像素,即输出一个像素的时间间隔),场扫描时序要求(单位:行,即输出一行的时间间隔)。
将上面的波形图转换为更容易理解的波形图:
这里分别引入行扫描计数器和场扫描计数器用来计时
gen_clk模块为由PLL锁相环产生的25MHz时钟,vga_ctrl为vga的驱动模块。
// -----------------------------------------------------------------------------
// Copyright (c) 2014-2023 All rights reserved
// -----------------------------------------------------------------------------
// Author : BigFartPeach
// CSDN : 大屁桃
// E-mail : [email protected]
// File : vga_ctrl.v
// Create : 2023-06-06 14:23:19
// -----------------------------------------------------------------------------
module vga_ctrl(
input wire clk_25M,
input wire rst_n,
output reg hsync,
output reg vsync,
output reg [7:0]rgb
);
reg [9:0] hsync_cnt;
reg [9:0] vsync_cnt;
//行扫描计数器
always @(posedge clk_25M or negedge rst_n) begin
if (rst_n == 0) begin
hsync_cnt <= 'd0;
end
else if (hsync_cnt == 'd799) begin
hsync_cnt <= 'd0;
end
else begin
hsync_cnt <= hsync_cnt + 1'b1;
end
end
//行同步信号
always @(posedge clk_25M or negedge rst_n) begin
if (rst_n == 0) begin
hsync <= 1'b1;
end
else if (hsync_cnt == 'd95) begin
hsync <= 1'b0;
end
else if(hsync_cnt == 'd799)begin
hsync <= 1'b1;
end
end
//场扫描计数器
always @(posedge clk_25M or negedge rst_n) begin
if (rst_n == 0) begin
vsync_cnt <= 'd0;
end
else if (vsync_cnt == 'd524 && hsync_cnt == 'd799) begin
vsync_cnt <= 'd0;
end
else if (hsync_cnt == 'd799) begin
vsync_cnt <= vsync_cnt + 1'b1;
end
end
//场扫描信号
always @(posedge clk_25M or negedge rst_n) begin
if (rst_n == 0) begin
vsync <= 1'b1;
end
else if (hsync_cnt == 'd799 && vsync_cnt == 'd1) begin
vsync <= 1'b0;
end
else if(hsync_cnt == 'd799 && vsync_cnt == 'd524) begin
vsync <= 1'b1;
end
end
//RGB信号输出
always @(posedge clk_25M or negedge rst_n) begin
if (rst_n == 0) begin
rgb <= 'b000_000_00;
end
//横彩条
// else if (hsync_cnt>= 144 && hsync_cnt <= 783 && vsync_cnt>= 35 && vsync_cnt <= 194) begin
// rgb <= 'b111_000_00;//红色
// end
// else if (hsync_cnt>= 144 && hsync_cnt <= 783 && vsync_cnt>= 195 && vsync_cnt <= 354)begin
// rgb <= 'b000_111_00;//绿色
// end
// else if (hsync_cnt>= 144 && hsync_cnt <= 783 && vsync_cnt>= 355 && vsync_cnt <= 514)begin
// rgb <= 'b000_000_11;//蓝色
// end
//竖彩条
else if (hsync_cnt>= 144 && hsync_cnt <= 356 && vsync_cnt>= 35 && vsync_cnt <= 514) begin
rgb <= 'b111_000_00;//红色
end
else if (hsync_cnt>= 357 && hsync_cnt <= 569 && vsync_cnt>= 35 && vsync_cnt <= 514) begin
rgb <= 'b000_111_00;//绿色
end
else if (hsync_cnt>= 570 && hsync_cnt <= 783 && vsync_cnt>= 35 && vsync_cnt <= 514) begin
rgb <= 'b000_000_11;//蓝色
end
else begin//其它区域
rgb <= 'b000_000_00;//不显示
end
end
endmodule
// -----------------------------------------------------------------------------
// Copyright (c) 2014-2023 All rights reserved
// -----------------------------------------------------------------------------
// Author : BigFartPeach
// CSDN : 大屁桃
// E-mail : [email protected]
// File : top_vga.v
// Create : 2023-06-06 15:35:13
// -----------------------------------------------------------------------------
module top_vga(
input wire clk,
input wire rst_n,
output wire hsync,
output wire vsync,
output wire [7:0] rgb
);
wire clk_25M;
//PLL产生25M的时钟
gen_clk25 inst_clk25(
// Clock in ports
.CLK_IN1(clk), // IN
// Clock out ports
.CLK_OUT1(clk_25M)); // OUT
//例化640*480@60Hz驱动模块
vga_ctrl inst_vga_ctrl (
.clk_25M(clk_25M),
.rst_n(rst_n),
.hsync(hsync),
.vsync(vsync),
.rgb(rgb));
endmodule
这里只是实现简单的驱动,后面的这篇文中我将VGA的驱动程序重新修改了一下,使整个程序更容易移植,有需要的哥们可以接着往后看。
关于这篇文章的工程的代码如下,工程基于ISE软件,没积分的哥们评论留下邮箱即可:
FPGA入门第七篇、FPGA实现VGA接口驱动资源-CSDN文库
最后,希望我的博客对你有帮助,有需要的小伙伴可以查看本专栏更多的往期文章专栏链接如下:FPGA的学习之旅_大屁桃的博客-CSDN博客