FPGA--VGA显示实验之Verilog代码描述(VGA时序控制模块)

发布于:2023-01-07 ⋅ 阅读:(558) ⋅ 点赞:(0)

        

 本篇内容将介绍 vga_ctrl 模块的Verilog代码实现。

功能介绍

        vga_ctrl模块的功能是输出满足时序要求的行扫描与场扫描信号,以及向vga_pic模块发出像素坐标索引,索要该像素点的颜色数据,同时在行有效周期和场有效周期输出像素RGB565参数。

基本参数

  •  一个Hsync周期包含800个像素时钟周期
  • 一个Vsync周期包含525个Hsync周期

(上图, 单个Hsync的时钟分布,时间单位为像素时钟周Hz)

 (上图,单个Vsync的时钟分布,时间单位为 一个Hsync周期,相当于800个像素时钟周期)

输入输出表

 (图片来源:野火电子)

实现思路

        第一部分:行同步时序与场同步时序

        首先解决时序单位的问题,由于场同步是以行同步为周期,行同步是以像素时钟周期为单位;因此首先设计一个模块,计数行同步的周期数,以及场同步的周期数。

  • cnt_h :每一个像素时钟周期加一(800一个循环,10位宽)
  • cnt_v :cnt_h加到800后加一(525一个循环,10位宽)

reg [9:0] cnt_h,cnt_v;//十位宽的值

always@(posedge clk)begin

    if(reset == 1'b1)begin //复位信号来临时
    cnt_h <= 9'd0;
    cnt_v <= 9'd0;
	end else if((cnt_h == 9'd799)&&(cnt_v == 9'd524))begin 
	cnt_h <= 9'd0;
	cnt_v <= 9'd0;
	end else if(cnt_h == 9'd799)begin
	cnt_h <= 9'd0;
	cnt_v <= cnt_v + 9'd1;
	end else 
	cnt_h <= cnt_h +9'd1;
end

编写一个TestBench测试一下:

 符合预期,我们的时间单位计数部分完成!

其次我们解决协议的问题:

对于行同步时序:

首先,同步部分,cnt_h从0计数到93,H_sync保持高电平,94到799都保持低电平。

H_sync = (cnt_h>= 10'd0)&&(cnt_h<=95);

对于RGB数据的输出而言,我们可以发现其实前三部分,共计144个周期都是无效的,即0开始计数到143都是无效的,144到783这640个周期是行有效果,其余的784到799也都是无效的。对于有效的周期,我们要进行标注,以便控制模块知道何时输出数据。

h_valid = (cnt_h>=10'd144 )&&(cnt_h <= 10'd783);

 对于场同步时序:

我们可以知道,0到1,V_sync为高,其余2到524无效。

assign V_sync = (cnt_v>= 10'd0)&&(cnt_v<=10'd1);

同理可以知道,0到34无效,35到514有效,515到524无效

assign v_valid = (cnt_v>=10'd35 )&&(cnt_v<= 10'd514);

先综合在一起:

module vga_ctrl(
input wire clk,
input wire reset,
output wire H_sync,
output wire V_sync);
wire h_valid,v_valid;
reg [9:0] cnt_h,cnt_v;//九位宽的值
always@(posedge clk)begin

    if(reset == 1'b1)begin //复位信号来临时
    cnt_h <= 10'd0;
    cnt_v <= 10'd0;
	end else if((cnt_h == 10'd799)&&(cnt_v == 10'd524))begin 
	cnt_h <= 10'd0;
	cnt_v <= 10'd0;
	end else if(cnt_h == 10'd799)begin
	cnt_h <= 10'd0;
	cnt_v <= cnt_v + 10'd1;
	end else 
	cnt_h <= cnt_h +10'd1;
end

assign h_valid = (cnt_h>=10'd144 )&&(cnt_h <= 10'd783);
assign v_valid = (cnt_v>=10'd35 )&&(cnt_v<= 10'd514);

assign H_sync = (cnt_h>= 10'd0)&&(cnt_h<=95);
assign V_sync = (cnt_v>= 10'd0)&&(cnt_v<=10'd1);

endmodule

编写Test_Bench进行测试:

H_sync:

 V_sync:

h_valid:

起始:

 终点:

 v_valid:

起始:

终点:

 

测试通过!

第二部分图像请求信号

        图像请求信号即向图像数据生成模块vga_pic发出像素坐标,然后vga_pic模块返回这个像素的颜色。

        首先我们要解决坐标信号,(pic_x,pic_y)何时送入vga_pic模块?
       h_valid从低电平向高电平跳变后,显示屏便开始采集rgb[15:0]端口上的值对应输出的模拟量,所以在h_valid变高之前,将坐标值(pic_x,pic_y)送到vga_pic的输入端口,这样,当h_valid跳变之时,第0个像素的数据就送到rgb[15:0]端口上了。这里我们设定一个pix_data_req用来控制坐标型号的生成。由题可知,pix_data_req在(35<= cnt_v <= 514)且(143<=cnt_h<=782)范围有效;

assign pix_data_req = (cnt_v>=10'd35 )&&(cnt_v<= 10'd514)&&(cnt_h>=10'd143 )&&(cnt_h <= 10'd782);

        其次,我们要解决坐标信号(pic_x,pic_y)值的大小,由对应关系可以知道:

assign pic_y = (pix_data_req)?(cnt_h - 10'd143):10h'3ff;//0~639
assign pic_x = (pix_data_req)?(cnt_v - 10'd35):10'h3ff; //0~479

 Test_bench仿真:

module vga_ctrl(
input wire clk,
input wire reset,
output wire H_sync,
output wire V_sync,
output wire [9:0] pic_x,
output wire [9:0] pic_y);
wire h_valid,v_valid,pix_data_req;
reg [9:0] cnt_h,cnt_v;//九位宽的值
always@(posedge clk)begin

    if(reset == 1'b1)begin //复位信号来临时
    cnt_h <= 10'd0;
    cnt_v <= 10'd0;
	end else if((cnt_h == 10'd799)&&(cnt_v == 10'd524))begin 
	cnt_h <= 10'd0;
	cnt_v <= 10'd0;
	end else if(cnt_h == 10'd799)begin
	cnt_h <= 10'd0;
	cnt_v <= cnt_v + 10'd1;
	end else 
	cnt_h <= cnt_h +10'd1;
end


assign h_valid = (cnt_h>=10'd144 )&&(cnt_h <= 10'd783);
assign v_valid = (cnt_v>=10'd35 )&&(cnt_v<= 10'd514);

assign H_sync = (cnt_h>= 10'd0)&&(cnt_h<=95);
assign V_sync = (cnt_v>= 10'd0)&&(cnt_v<=10'd1);

assign pix_data_req = (cnt_v>=10'd35 )&&(cnt_v<= 10'd514)&&(cnt_h>=10'd143 )&&(cnt_h <= 10'd782);

assign pic_y = (pix_data_req)?(cnt_h - 10'd143):10'h3ff;//0~639
assign pic_x = (pix_data_req)?(cnt_v - 10'd35):10'h3ff; //0~479

endmodule

仿真结果:

 

 从上图中可以看出:

  1. pix_data_req早于h_valid一个时钟周期,因此在cnt_h==143时,坐标数据就被送到vga_pic模块的输入端,当cnt_h由143到144时,(1,0)点对应的颜色数据就被输送到rbg[15:0]上,也就是第一个像素数据。如果不提前一个时钟周期,那么143到144这个跳变沿来临时,坐标(10‘h3ff,10’h3ff)的颜色数据将被送入rbg[15:0]。
  2. pic_x为行坐标,范围为 0~479,pic_y为列坐标,范围在0~639。

 从上图中可以看出,

  1. pic_x为行坐标,范围为 0~479,pic_y为列坐标,范围在0~639。
  2. h_valid比pix_data_req滞后一个周期,当然最后一个周期显示的点坐标是(0,639)

至此我们的vga_ctrl模块设计成功!

本文含有隐藏内容,请 开通VIP 后查看