在HDMI 图像显示项目中vga_driver 模块负责产生,输出VESA 标准相关的h,v,de信号(1920 x 1080 @Hz)。在这个模块中, 并没有产生,输出视频数据信号。在vga_driver 模块中采用参数化设计, 使得我们只要更改很少的参数,就可以形成其他的VESA 标准。
vga_driver 模块代码:
`timescale 1ns/1ps module vga_driver #( parameter h_sync_pola = 1, parameter v_sync_pola = 1 )( input vga_clk, input rst_n, output h_sync, output v_sync, output hv_de ); //==============================640*480 //localparam h_pixels = 800; //H_总像素 //localparam h_sync_pix = 96; //H_同步时间 //localparam h_back_protch = 48; //H_后廊+左边界 //localparam h_active = 640; //H_有效像素 //localparam h_front_protch = 16; //H_前廊+右边界 //localparam v_pixels = 525; //一帧总行数 //localparam v_sync_pix = 2; //v信号需要的行数 //localparam v_back_protch = 33; //v_后廊+左边界需要的行数 //localparam v_active = 480; //v_有效行数 //localparam v_front_protch = 10; //v_前廊+右边界的行数 //==============================1920*1080 localparam h_pixels = 2200; //H_总像素 localparam h_sync_pix = 44; //H_同步时间 localparam h_back_protch = 148; //H_后廊+左边界 localparam h_active = 1920; //H_有效像素 localparam h_front_protch = 88; //H_前廊+右边界 localparam v_pixels = 1125; //一帧总行数 localparam v_sync_pix = 5; //v信号需要的行数 localparam v_back_protch = 36; //v_后廊+左边界需要的行数 localparam v_active = 1080; //v_有效行数 localparam v_front_protch = 4; //v_前廊+右边界的行数 //============================== reg [12:0] h_counter = 1; reg [11:0] v_counter = 0; wire h_rst = (h_counter == h_pixels) ? 1'b1 : 1'b0; always @ (posedge vga_clk) if((!rst_n) || h_rst) h_counter <= 1; else h_counter <= h_counter +1; //---- wire v_rst = (v_counter == v_pixels) ? 1'b1 : 1'b0; reg v_rst_r = 0; always @ (posedge vga_clk) v_rst_r <= v_rst & h_rst; always @ (posedge vga_clk) if(v_rst_r) v_counter <= 1; else if(h_counter == h_sync_pix) v_counter <= v_counter +1; //========================================= h_sync //h_sync reg h_dvi = 0; always @ (posedge vga_clk) if(h_rst) h_dvi <= 1; //+ else if(h_counter == h_sync_pix) h_dvi <= 0; assign h_sync = (h_sync_pola) ? h_dvi : ~h_dvi; //v_sync reg v_dvi = 0; always @ (posedge vga_clk) if(h_rst) begin if(v_rst) v_dvi <= 1; //+ else if(v_counter == v_sync_pix) v_dvi <= 0; end assign v_sync = (v_sync_pola) ? v_dvi : ~v_dvi; //============================================== //h_en reg [12:0] h_start = 0; reg [12:0] h_end = 0; always @ (posedge vga_clk) begin h_start <= (h_sync_pix + h_back_protch); h_end <= (h_active + h_start); end reg [12:0] it_h_counter = 1; reg it_h_rst = 0; always @ (posedge vga_clk) it_h_rst <= h_dvi; always @ (posedge vga_clk) if({it_h_rst,h_dvi} == 2'b01) it_h_counter <= 2; else it_h_counter <= it_h_counter +1; reg h_de_reg = 0; always @ (posedge vga_clk) begin if(it_h_counter == h_start) h_de_reg <= 1; if(it_h_counter == h_end) h_de_reg <= 0; end //====================================== //h_en reg [11:0] v_start = 0; reg [11:0] v_end = 0; always @ (posedge vga_clk) begin v_start <= (v_sync_pix + v_back_protch); v_end <= (v_active + v_start); end reg [11:0] it_v_counter = 1; reg it_v_rst = 0; always @ (posedge vga_clk) it_v_rst <= v_dvi; always @ (posedge vga_clk) if({it_v_rst,v_dvi} == 2'b01) it_v_counter <= 0; else if(h_counter == h_sync_pix) it_v_counter <= it_v_counter + 1; reg v_de_reg = 0; always @ (posedge vga_clk) begin if((it_v_counter == v_start) && (it_h_counter == h_sync_pix)) v_de_reg <= 1; if((it_v_counter == v_end) && (it_h_counter == h_sync_pix) ) v_de_reg <= 0; end assign hv_de = h_de_reg & v_de_reg; endmodule
localparam h_pixels = 2200; //H_总像素 localparam h_sync_pix = 44; //H_同步时间 localparam h_back_protch = 148; //H_后廊+左边界 localparam h_active = 1920; //H_有效像素 localparam h_front_protch = 88; //H_前廊+右边界 localparam v_pixels = 1125; //一帧总行数 localparam v_sync_pix = 5; //v信号需要的行数 localparam v_back_protch = 36; //v_后廊+左边界需要的行数 localparam v_active = 1080; //v_有效行数 localparam v_front_protch = 4; //v_前廊+右边界的行数
配置1920 x 1080 @ 60Hz 的VESA标准。
这里我们可以看出,所有的参数都是按照VESA 标准给出的。
reg [12:0] h_counter = 1; reg [11:0] v_counter = 0; wire h_rst = (h_counter == h_pixels) ? 1'b1 : 1'b0; always @ (posedge vga_clk) if((!rst_n) || h_rst) h_counter <= 1; else h_counter <= h_counter + 1; wire v_rst = (v_counter == v_pixels) ? 1'b1 : 1'b0; reg v_rst_r = 0; always @ (posedge vga_clk) v_rst_r <= v_rst & h_rst; always @ (posedge vga_clk) if(v_rst_r) v_counter <= 1; else if(h_counter == h_sync_pix) v_counter <= v_counter + 1;
设置两个标尺:h_counter, v_counter 。 h_counter 定义为一行有多少个pixel; v_counter 定义为一帧有多少行。
//h_sync reg h_dvi = 0; always @ (posedge vga_clk) if(h_rst) h_dvi <= 1; else if(h_counter == h_sync_pix) h_dvi <= 0; assign h_sync = (h_sync_pola) ? h_dvi : ~h_dvi; //v_sync reg v_dvi = 0; always @ (posedge vga_clk) if(h_rst) begin if(v_rst) v_dvi <= 1; else if(v_counter == v_sync_pix) v_dvi <= 0; end assign v_sync = (v_sync_pola) ? v_dvi : ~v_dvi;
通过标尺,计算H 信号的宽度,从每行的起始点开始 ,计数h_sync_pix; 计算V信号的宽度, 从每帧的起始行开始,计数v_sync_pix。
//h_en reg [12:0] h_start = 0; reg [12:0] h_end = 0; always @ (posedge vga_clk) begin h_start <= (h_sync_pix + h_back_protch); h_end <= (h_active + h_start); end reg [12:0] it_h_counter = 1; reg it_h_rst = 0; always @ (posedge vga_clk) it_h_rst <= h_dvi; always @ (posedge vga_clk) if({it_h_rst,h_dvi} == 2'b01) it_h_counter <= 2; else it_h_counter <= it_h_counter + 1; reg h_de_reg = 0; always @ (posedge vga_clk) begin if(it_h_counter == h_start) h_de_reg <= 1; if(it_h_counter == h_end) h_de_reg <= 0; end
产生H方向的de,从h_back_porch 后开始 计数 h_active 结束。
reg [11:0] v_start = 0;
reg [11:0] v_end = 0;
always @ (posedge vga_clk)
begin
v_start <= (v_sync_pix + v_back_protch);
v_end <= (v_active + v_start);
end
reg [11:0] it_v_counter = 1;
reg it_v_rst = 0;
always @ (posedge vga_clk)
it_v_rst <= v_dvi;
always @ (posedge vga_clk)
if({it_v_rst,v_dvi} == 2'b01)
it_v_counter <= 0;
else if(h_counter == h_sync_pix)
it_v_counter <= it_v_counter + 1;
reg v_de_reg = 0;
always @ (posedge vga_clk)
begin
if((it_v_counter == v_start) && (it_h_counter == h_sync_pix))
v_de_reg <= 1;
if((it_v_counter == v_end) && (it_h_counter == h_sync_pix) )
v_de_reg <= 0;
end
产生V 方向的de,从v_back_porch 后开始 计数 v_active 结束。
assign hv_de = h_de_reg & v_de_reg;
其中,蓝色框为h_de;棕色框为v_de。最终,将h方向的de 和 V 方向的de 组合(交集), 输出VESA 标准de