采用DB15的及接口,主要5根VGA信号线,两根I2C通讯线。5根VGA信号线是V_SYN,H_SYN分别是场同步和行同步走的是3.3V的信号,R,G,B分别是红绿蓝三基色信号。R,G,B三基色信号走的是模拟电平,峰峰值规定在0-0.714V,输入阻抗是75欧。另外两根I2C通讯线就是用来和VGA显示器协调所支持的分辨率。
DA转换用 电阻网络进行分压达到DAC效果。
1,R,G,B分别对应4个BIT,总共12位,所以分辨率是12位。
2. 由于R有4个位, 在0-0.714V 之间分成了16个等级。
3,H_SYN和V_SYN分别是标示一行的结束,以及一屏的结束,是数字信号。
注意FRONT_PORCH和BACK_PORCH分别是在同步信号的之前和之后。
以上时序可以变换成下面的时序:好处是便于地址从0开始计,编程非常方便。依据是VGA支持即插即用,显示器会自动寻找同步信号。
两个频率,一个是显示的频率,比方我们这里的1024768像素点,刷新率是60HZ,显示的频率就是 102476860=47.18M . 这个频率表达了对图像数据的进行处理和传输的要求。就是说实际应用这个VGA控制器时候,我们需要保证以47.18M显示位数 的速率给他提供显示数据。如果需要用一个DMA传数的话,这是DMA的最低速率要求。
一个频率是像素频率,我们这个1024768个像素点,扫描屏幕实际用了1344806个像素时钟,因此刷新率为60HZ就要求像素频率是134480660=64.99M。这个频率是我们做VGA控制器时需要设置的像素点频率,即产生vga时序的VGA控制器的输入频率。
通过修改宏定义、改像素频率,实现不同像素尺寸和频率的的显示。
// 1024 X 768 @ 60Hz with a 65.000MHz pixel clock
`define H_ACTIVE 1024
`define H_FRONT_PORCH 24
`define H_SYNCH 136
`define H_BACK_PORCH 160
`define H_TOTAL ( `H_SYNCH + `H_BACK_PORCH + `H_ACTIVE + `H_FRONT_PORCH )
//1344 // pixels
`define V_ACTIVE 768
`define V_FRONT_PORCH 3
`define V_SYNCH 6
`define V_BACK_PORCH 29
`define V_TOTAL (`V_SYNCH + `V_BACK_PORCH + `V_ACTIVE +`V_FRONT_PORCH )
//806 // lines
module my_vga_syn (
input pixel_clock, rst_i,
output reg h_synch, v_synch,
output reg dp_en,
output reg [10:0] line_count ,
output reg [10:0] pixel_count
);
/*
1),做2个计数器,一个用来记录行内的像素点时钟数,
一个用来记录行数。
这两个计数器除了复位信号外不受别的因素影响,
在一直自己循环累加。
*/
always @(posedge pixel_clock)
if ( rst_i )pixel_count<=0;
else if (pixel_count == (`H_TOTAL-1))pixel_count<=0;
else pixel_count<=pixel_count+1;
always @(posedge pixel_clock)
if (rst_i)line_count<=0;
else if (pixel_count==(`H_TOTAL-1)) begin
if ( line_count==(`V_TOTAL-1))line_count<=0;
else line_count<=line_count+1;
end
/*
2),两个计数器的数值就对应上图的所处的位置。
我们找到实际要显示区域对应的像素计数器和行计数器
的数值,只要两个计数器满足在这个区域,
就允许显示,否则进行消音输出(R,G,B都输出为0)。
*/
reg h_en ;
always@(posedge pixel_clock)
if (pixel_count == (`H_TOTAL-1) )h_en<=1;
else if (pixel_count==(`H_ACTIVE-1))h_en<=0;
reg v_en ;
always@(posedge pixel_clock)
if (pixel_count == (`H_TOTAL-1) )begin
if (line_count==(`V_TOTAL-1))v_en<=1;
else if (line_count==(`V_ACTIVE-1))v_en<=0;
end
always@(posedge pixel_clock)
dp_en <= v_en & h_en ;
/*
if (
(pixel_count <= (`H_ACTIVE-1))
&&
(line_count<=(`V_ACTIVE-1))
)
dp_en <= 1 ;
else
dp_en <= 0 ;
*/
//3),从图中找到H_SYN的时间段和V_SYN的时间段,
//将这个时间段同步信号对应设置为低电平。
always@(posedge pixel_clock)
if ( pixel_count ==(`H_ACTIVE+`H_FRONT_PORCH-1))
h_synch<=0;
else if ( pixel_count ==(`H_ACTIVE+`H_FRONT_PORCH+`H_SYNCH-1))
h_synch<=1;
always@(posedge pixel_clock)
if ( pixel_count ==(`H_TOTAL-1))
begin
if (line_count==(`V_ACTIVE+`V_FRONT_PORCH-1))
v_synch<=0;
else if ( line_count ==(`V_ACTIVE+`V_FRONT_PORCH + `V_SYNCH-1))
v_synch<=1;
end
endmodule
line_count ,pixel_count可以看做二维数组的行列序号下标,输出行列的对应位置,根据位置进行赋值(0~1023, 0 ~757),即可显示图像。
`timescale 1ns/1ns
module vga_sim_top;
reg pixel_clock ,rst_i;
wire dp_en ;
wire h_synch,v_synch;
wire [9:0] line_count;
wire [10:0] pixel_count ;
reg [9:0] line_countr ;
reg [10:0] pixel_countr ;
wire [9:0] line_countro ;
wire [10:0] pixel_countro ;
assign pixel_countro = (dp_en==0)? 0 : pixel_countr ;
assign line_countro = (dp_en==0)? 0 : line_countr ;
always@(posedge pixel_clock)
begin
line_countr <= line_count ;
pixel_countr <= pixel_count ;
end
always #30 pixel_clock = ~pixel_clock ;
initial begin
pixel_clock=0;rst_i=1;
#100 rst_i=0 ;
end
my_vga_syn my_vga_syn(
.pixel_clock(pixel_clock ),
.rst_i( rst_i ),
.h_synch( h_synch ),
.v_synch( v_synch ),
.dp_en( dp_en),
.line_count(line_count ),
.pixel_count ( pixel_count )
);
endmodule
一帧
module vga_test (
output [3:0] R,G,B,
output h_synch,v_synch,
input clk_i,rst_i
);
wire clk65M ;
wire dp_en ;
design_1 DCM (
.clk_in1(clk_i),
.clk_out1(clk65M),
.locked(),
.reset(1'b0)
);
wire [9:0]line_count ;
wire [10:0]pixel_count ;
my_vga_syn my_vga_syn(
.pixel_clock( clk65M ),
.rst_i( rst_i ),
.h_synch( h_synch ),
.v_synch( v_synch ),
.dp_en( dp_en ),
.line_count( line_count ),
.pixel_count ( pixel_count )
);
reg[3:0] Rr , Gr , Br ;
always@ (posedge clk65M)
case ( pixel_count )
128*4 : { Rr , Gr , Br } <={ 4'b0000 , 4'b0000 , 4'b0000 } ;
128*1 : { Rr , Gr , Br } <={ 4'b0000 , 4'b0000 , 4'b1111 } ;
128*2 : { Rr , Gr , Br } <={ 4'b0000 , 4'b1111 , 4'b0000 } ;
128*3 : { Rr , Gr , Br } <={ 4'b0000 , 4'b1111 , 4'b1111 } ;
128*0 : { Rr , Gr , Br } <={ 4'b1111 , 4'b0000 , 4'b0000 } ;
128*5 : { Rr , Gr , Br } <={ 4'b1111 , 4'b0000 , 4'b1111 } ;
128*6 : { Rr , Gr , Br } <={ 4'b1111 , 4'b1111 , 4'b0000 } ;
128*7 : { Rr , Gr , Br } <={ 4'b1111 , 4'b1111 , 4'b1111 } ;
endcase
assign B = ( dp_en == 0 ) ? 0 : Br ;
assign G = ( dp_en == 0 ) ? 0 : Gr ;
assign R = ( dp_en == 0 ) ? 0 : Rr ;
endmodule