在HDMI 图像显示项目中vga_driver 模块负责产生,输出VESA 标准相关的h,v,de信号(1920 x 1080 @Hz)。在这个模块中, 并没有产生,输出视频数据信号。在vga_driver 模块中采用参数化设计, 使得我们只要更改很少的参数,就可以形成其他的VESA 标准。
vga_driver 模块代码:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
`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 |
|
1 2 3 4 5 6 7 8 9 10 11 |
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 标准给出的。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
reg [12:0] <span style="color: #0000ff;">h_counter</span> = 1; reg [11:0] <span style="color: #0000ff;">v_counter</span> = 0; wire h_rst = (h_counter == <span style="color: #333333;">h_pixels</span>) ? 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 定义为一帧有多少行。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
//h_sync reg <span style="color: #0000ff;">h_dvi</span> = 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 <span style="color: #0000ff;">v_dvi</span> = 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。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
//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] <span style="color: #0000ff;">it_h_counter</span> = 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 <span style="color: #0000ff;">h_de_reg</span> = 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 结束。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
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 <span style="color: #0000ff;">v_de_reg</span> = 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 结束。
|
1 |
assign hv_de = h_de_reg & v_de_reg; |
其中,蓝色框为h_de;棕色框为v_de。最终,将h方向的de 和 V 方向的de 组合(交集), 输出VESA 标准de


