在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


