一. 简介
本例是FPGA之旅设计的第十七例,本例将介绍如何使用FPGA来驱动VGA显示器,并且显示彩条,为后面的图像显示做好准备。
二. VGA简介
实物图如下,之前的显示器,一般都是VGA接口。现在可能都是HDMI接口的了,但也会转到VGA接口上弄,比较比较方便,因此掌握VGA时序是非常重要的
VGA接口原理图如下,信号接口可以分为三大类
VGA_HSYNC(1bit): 行同步信号,FPGA输出,默认为高电平,每一行显示之前,都要将其拉低,一定的周期,用于同步。
VGA_VSYNC(1bit): 帧同步信号,FPGA输出,默认为高电平,每一帧图像显示之前,都要将其拉低,一定的周期,用于同步。
Color(RGB)(16/24bit): 显示数据,FPGA输出,根据外部电路不同,可以有16bit RGB565 ,和 24bit RGB888,这两种常见的电路。
行同步时序如下,
帧同步时序如下
每幅图中,都标注出了五个关键点,以及下面的参数,就可以开始编写VGA驱动了。
每个部分持续的周期数,都在表中给出来了,根据选择的显示模式,确定行帧的周期数。
这里我选择的是第一种640*480@60的模式。
三. Verilog代码编写
(1)定义各状态的时间参数
根据表格定义好,即可。另外输入的时钟要是25Mhz
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; //场扫描周期
(2)行列计数
行计数器每计满一个周期,列计数器加一。
在计数器小于各种的同步周期内时,将各自的同步信号拉低即可。
reg[9:0] h_cnt; reg[9:0] v_cnt; assign vga_hsync = (h_cnt < H_SYNC) ? 1'b0 : 1'b1; assign vga_vsync = (v_cnt < V_SYNC) ? 1'b0 : 1'b1; always@(posedge vga_clk or negedge rst_n) begin if(rst_n == 1'b0) h_cnt <= 'd0; else if(h_cnt == (H_TOTAL - 1'b1)) h_cnt <= 'd0; else h_cnt <= h_cnt + 1'b1; end always@(posedge vga_clk or negedge rst_n) begin if(rst_n == 1'b0) v_cnt <= 'd0; else if(h_cnt == (H_TOTAL - 1'b1) && v_cnt == (V_TOTAL - 1'b1)) v_cnt <= 'd0; else if(h_cnt == (H_TOTAL - 1'b1)) v_cnt <= v_cnt + 1'b1; else v_cnt <= v_cnt; end
(3)数据使能输出
在行列都在有效数据阶段的时候,进行数据输出,其他时间输出零。
wire vga_en; assign vga_en = (((h_cnt >= H_SYNC+H_BACK) && (h_cnt < H_SYNC+H_BACK+H_DISP)) &&((v_cnt >= V_SYNC+V_BACK) && (v_cnt < V_SYNC+V_BACK+V_DISP))) ? 1'b1 : 1'b0; //RGB565数据输出 assign vga_rgb = vga_en ? display_data : 16'd0;
至此就完成了一个简单的VGA显示了。 效果如下
关注公众号 FPGA之旅 获取更多
回复 FPGA之旅设计99例之第十七例 获取驱动代码
公众号:FPGA之旅