VGA的缩写来自Video Graphics Array,视频图形阵列,一种使用模拟信号进行视频传输的标准,DE2-115开发板上的VGA接口如下:
VGA的引脚定义如下:
pin 1 2 3 是模拟输入,输入范围是0v到0.714v,pin 13 pin14是数字信号输入(TTL电平):
行同步时序:
图像由一个个像素点组成, 从左到右进行扫描。一行扫描结束以后,回到下一行继续扫描。每扫描一行所需的时间称为一个行扫描周期。
场同步时序:
每扫描一帧,是一个场扫描周期。
总结:
- 行同步时序的基本单位是完成一个像素点显示所需要的时间, a、b、c、d、e 的基本单位 是一个像素的扫描周期。
- 场同步时序的基本单位是完成一行图像显示所需要的时间, o、p、q、r、d 的基本单位 是一个完整的行扫描周期。
分辨率:
640x480@60的解释:
640是指VGA显示器每一行有640个像素点;
480是指VGA显示器每一帧有640行;
60 是VGA 显示器每秒钟刷新60次,也就是每秒显示60帧图像。
像素时钟的计算:
从分辨率和行同步时序以及场同步时序我们可以计算得到像素的时钟, 比如640*480@60分辨率的像素时钟是800*525*60=25.2M。
VGA传输的是模拟信号, 所以视频信号需要通过数模转换的过程然后才能输出到 外部的VGA接口上去,这个过程可以用专门的视频转换芯片ADV7123去实现,也可以用更简单的方案:使用一系列的电阻将数字信号转换撑模拟信号(权电阻网络)。
权电阻网络:
采用权电阻网络实现DAC转换过程:
电阻的阻值 成倍数关系。 电阻越大,权值越小。
为啥DE10-Lite 和 DE0-CV 上的权电阻网络选用的是2K排阻和1K排组呢?
首先,因为VGA显示器的VGA接口内部有一个 75ohm的电阻 用于阻抗匹配 :
根据权电阻网络要求电阻值成倍数关系,我们可以计算如下:
(因为贴片电阻没有一模一样阻值的电阻, 所以我们选择阻值相近的电阻即可,2037ohm 就近似选择2K的贴片电阻)
DE2-115的VGA 硬件:
top文件代码:
module vga( input wire clk, //板载50M时钟输入 input wire rst_n, //可以选择key0作为复位信号的输入 output wire [11:0] vga_rgb, output wire vga_hs, //行同步信号 output wire vga_vs, //场同步信号
output wire VGA_CLK,
output wire VGA_BLANK_N,
output wire VGA_SYNC_N
); wire clk_25m; //根据前面表格得知640x480@60的像素时钟是25M,所以用一个PLL 将50M分频得到25M wire pll_locked;//当PLL稳定输出时该信号为高 pll pll_inst ( //用来将50M分频得到25M的像素时钟 .areset ( ~rst_n ), .inclk0 ( clk ), .c0 ( clk_25m), .locked ( pll_locked) ); vga_ctrl vga_ctrl_inst ( .clk clk_25m ), .rst_n (pll_locked), .vga_rgb (vga_rgb), .vga_hs (vga_hs ), .vga_vs (vga_vs ) );
assign VGA_SYNC_N=1'b0; //Ifnot SOG, Sync input should be tied to 0;
assign VGA_CLK=clk_25m;
endmodule
VGA控制代码:
`define VGA_640x480x60 // choose different video standard,revise PLL clk ,alter cnt WIDTH
//`define VGA_640X480X75 //`define VGA_800X600X60 //`define VGA_800X600X75 //`define VGA_1024X768X60 //`define VGA_1024X768X75 //`define VGA_1280X1024X60 //`define VGA_1280X800X60 //`define VGA_1440X900X60 module vga_ctrl ( input wire clk, input wire rst_n, output reg [11:0] vga_rgb,//定义为12位是因为DE0-CV和DE10-Lite的VGA 都是RGB444 output reg vga_hs, output reg vga_vs,
output wire vga_blanck_n
); //================ VGA_640X480X60 ========================================================= `ifdef VGA_640x480x60 // PLL clk = 25M = 640x480x60 localparam HS_A = 96; // synchronous pulse, horizontal localparam HS_B = 48; // back porch pulse localparam HS_C = 640; // display interval localparam HS_D = 16; // Front porch localparam HS_E = 800; // horizontal cycles localparam VS_A = 2; // synchronous pulse, vertical localparam VS_B = 33; localparam VS_C = 480; localparam VS_D = 10; localparam VS_E = 525; localparam HS_WIDTH = 10; localparam VS_WIDTH = 10; `endif parameter CNT_VS_R = 195; // 195 = 2+33+160, 35~195 is red 有效数据q段是480行,第一个160行是红 parameter CNT_VS_G = 355; // 195~355 is green 第二个160行是绿,剩下的就是蓝了 reg [HS_WIDTH - 1:0] cnt_hs; // counter for vertical synchronous signal reg [VS_WIDTH - 1:0] cnt_vs; // counter for horizontal synchrous signal wire en_hs; // dsiplay horizontal enable wire en_vs; // display vertical enable wire en; // effective display zone wire en_vs_r; // red stripe enable wire en_vs_g; // green stripe enable
assign vga_blanck_n=h_blank||v_blank;
always @ (posedge clk, negedge rst_n) if (!rst_n) cnt_hs <= 0; else if (cnt_hs < HS_E - 1) cnt_hs <= cnt_hs + 1'b1; else cnt_hs <= 0; always @ (posedge clk, negedge rst_n) if (!rst_n) cnt_vs <= 0; else if (cnt_hs == HS_E - 1) if (cnt_vs < VS_E - 1) cnt_vs <= cnt_vs + 1'b1; else cnt_vs <= 0; else cnt_vs <= cnt_vs; always @ (posedge clk, negedge rst_n) if (!rst_n) vga_hs <= 1'b1; else if (cnt_hs < HS_A - 1) //同步之前vga_hs信号都是低, 同步之后(a)vga_hs信号是高 vga_hs <= 1'b0; else vga_hs <= 1'b1; always @ (posedge clk, negedge rst_n) if (!rst_n) vga_vs <= 1'b1; else if (cnt_vs < VS_A - 1) //同步之前vga_vs 信号都是低, 同步之后(a)vga_vs 信号是高 vga_vs <= 1'b0; else vga_vs <= 1'b1; assign en_hs = (cnt_hs > HS_A + HS_B - 1)&& (cnt_hs < HS_E - HS_D);//en_hs 将有效数据c段标出来了,有效数据c段en_hs 才为高,否则为低 assign en_vs = (cnt_vs > VS_A + VS_B - 1) && (cnt_vs < VS_E - VS_D);//en_vs 将有效数据q段标出来了,有效数据q段en_hs 才为高,否则为低 assign en_vs_r = (cnt_vs > VS_A + VS_B - 1) && (cnt_vs < CNT_VS_R);//场同步的第一个160行 assign en_vs_g = (cnt_vs > CNT_VS_R - 1) && (cnt_vs < CNT_VS_G); //场同步的第二个160行 assign en = en_hs && en_vs;//将vga显示的有效像素点位置全部标注出来了 always @ (posedge clk, negedge rst_n) if (!rst_n) vga_rgb <= 12'b0000_0000_0000; else if (en) if (en_vs_r) vga_rgb <= 12'b0000_0000_1111; // 红 else if (en_vs_g) vga_rgb <= 12'b0000_1111_0000; // 绿 else vga_rgb <= 12'b1111_0000_0000; // 蓝 else vga_rgb <= 12'b0000_0000_0000; endmodule
PLL IP 设置:
管脚分配:
DE10-Standard的VGA 管脚分配:
DE2-115的VGA 管脚分配:
与权电阻网络相比, ADV7123多了VGA_CLK和VGA_BLANK_N和VGA_SYNC_N三个信号,这三个信号根据ADV7123手册定义:
所以我们在代码控制里面将像素时钟赋给VGA_CLK, 将VGA_SYNC_N直接拉低,将VGA_BLANK_N信号设计为VGA显示图像以外空白的范围。
下板验证:
DE10-Standard: