Menu Close

HDMI FPGA 工程设计2(VESA h,v,de)

在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标准。

 

%title插图%num

 

%title插图%num

这里我们可以看出,所有的参数都是按照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;

%title插图%num

其中,蓝色框为h_de;棕色框为v_de。最终,将h方向的de 和 V 方向的de 组合(交集), 输出VESA 标准de

 

 

Posted in FPGA, FPGA, Verilog, Verilog, Verilog语言编程与FPGA, 教材与教案, 文章

发表评论

相关链接