[FPGA] VGA driver: line synchronization timing + field synchronization timing

The lines are all the same, the only difference is the length of the timing

The following instructions are based on the resolution of 640 * 480:

Synchronize in line

  1. When the line counter counts to a-96, the line enable output is pulled high
  2. The line count will then keep counting up to 800, and when it reaches 0, the line enable can be pulled low
  3. At this time, the field counter is increased by 1 from 0 to get 1
  4. After another round of 800 line counters, the field counter will automatically increase to 2, then the condition is met, and the field enable output is pulled high
  5. Wait until the field counter has been added to 35 before starting to transmit data
  6. However, it is not transmitted as soon as the field count reaches 35. It must wait until the line counter reaches the display delay.

Overall: Divide into segments

  1. The field enable is pulled high by low , and then output: the timing used: 800 * 2 = 1600
  2. The display delay of the line field, the buffer stage: during the time sequence: 800 * 33 = 26400
  3. In the display phase , the clock cycle is: 480 * 640 = . . . .
  4. display lag ,

VGA driver code:

module vga_driver(
    input           vga_clk,      //VGA驱动时钟
    input           sys_rst_n,    //复位信号
    //VGA接口                          
    output          vga_hs,       //行同步信号
    output          vga_vs,       //场同步信号
    output  [15:0]  vga_rgb,      //红绿蓝三原色输出
    
    input   [15:0]  pixel_data,   //像素点数据
    output  [ 9:0]  pixel_xpos,   //像素点横坐标
    output  [ 9:0]  pixel_ypos    //像素点纵坐标    
    );                             
                                                        
//parameter define  
parameter  H_SYNC   =  10'd96;    //行同步
parameter  H_BACK   =  10'd48;    //行显示后沿
parameter  H_DISP   =  10'd640;   //行有效数据
parameter  H_FRONT  =  10'd16;    //行显示前沿
parameter  H_TOTAL  =  10'd800;   //行扫描周期

parameter  V_SYNC   =  10'd2;     //场同步
parameter  V_BACK   =  10'd33;    //场显示后沿
parameter  V_DISP   =  10'd480;   //场有效数据
parameter  V_FRONT  =  10'd10;    //场显示前沿
parameter  V_TOTAL  =  10'd525;   //场扫描周期
          
//reg define                                     
reg  [9:0] cnt_h;
reg  [9:0] cnt_v;

//wire define
wire       vga_en;
wire       data_req; 

//*****************************************************
//**                    main code
//*****************************************************
//VGA行场同步信号
assign vga_hs  = (cnt_h <= H_SYNC - 1'b1) ? 1'b0 : 1'b1;
assign vga_vs  = (cnt_v <= V_SYNC - 1'b1) ? 1'b0 : 1'b1;

//使能RGB565数据输出,颜色输出的开关
assign vga_en  = (((cnt_h >= H_SYNC+H_BACK) && (cnt_h < H_SYNC+H_BACK+H_DISP))		// 判断行信号在有效数据段内
                 &&((cnt_v >= V_SYNC+V_BACK) && (cnt_v < V_SYNC+V_BACK+V_DISP)))		// 判断场信号在有效数据段内
                 ?  1'b1 : 1'b0;
                 
//RGB565数据输出                 
assign vga_rgb = vga_en ? pixel_data : 16'd0;		// 如果满足要求则能输出颜色信号

//请求像素点颜色数据输入,颜色位置的开关     
assign data_req = (((cnt_h >= H_SYNC+H_BACK-1'b1) && (cnt_h < H_SYNC+H_BACK+H_DISP-1'b1))
                  && ((cnt_v >= V_SYNC+V_BACK) && (cnt_v < V_SYNC+V_BACK+V_DISP)))
                  ?  1'b1 : 1'b0;

//像素点坐标                
assign pixel_xpos = data_req ? (cnt_h - (H_SYNC + H_BACK - 1'b1)) : 10'd0;		// 如果满足条件则输出像素对应的位置
assign pixel_ypos = data_req ? (cnt_v - (V_SYNC + V_BACK - 1'b1)) : 10'd0;		// 如果满足条件则输出像素对应的位置

/*
	上述是设计两个开关来控制输出信号
	
*/

//行计数器对像素时钟计数
always @(posedge vga_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n)
        cnt_h <= 10'd0;                                  
    else begin
        if(cnt_h < H_TOTAL - 1'b1)                                               
            cnt_h <= cnt_h + 1'b1;                               
        else 
            cnt_h <= 10'd0;  
    end
end

//场计数器对行计数
always @(posedge vga_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n)
        cnt_v <= 10'd0;                                  
    else if(cnt_h == H_TOTAL - 1'b1) begin
        if(cnt_v < V_TOTAL - 1'b1)                                               
            cnt_v <= cnt_v + 1'b1;                               
        else 
            cnt_v <= 10'd0;  
    end
end

endmodule 

Drive test code:

`timescale 1ns/1ps

`define clock_period 20

module VGA_driver_tb;

	reg				sys_clk		;
	reg				sys_rst_n	;
	reg	[15:0]	pixel_data	;
	
	
	wire				vga_hs			;
	wire				vga_vs			;
	wire	[15:0]	vga_rgb		;
	
	wire	[ 9:0]	xpos			;
	wire	[ 9:0]	ypos			;
	
	
	
	vga_driver a1(
    .vga_clk	(sys_clk),      //VGA驱动时钟
    .sys_rst_n	(sys_rst_n),    //复位信号
                      
    .vga_hs		(vga_hs),       //行同步信号
    .vga_vs		(vga_vs),       //场同步信号
    .vga_rgb	(vga_rgb),      //红绿蓝三原色输出
    
    .pixel_data(pixel_data),   //像素点数据
    .pixel_xpos	(xpos),   //像素点横坐标
    .pixel_ypos 	(ypos)   //像素点纵坐标    
    );    

	initial sys_clk = 1;	
	always #(`clock_period / 2) sys_clk = ~sys_clk;
	
	initial begin
		sys_rst_n = 0 ;
		pixel_data = 0;
		
		#(`clock_period * 20 +1);
		sys_rst_n = 1 ;
		pixel_data = 16'h1234;
		
		#(`clock_period * 500_000);
		#20;
		
		
		
		$stop;	
	end

endmodule


Summarize:

It can be seen that the functions of the VGA driver module are:

1. Receive 16 pixel data

2. Operation, line + field synchronization timing

        2.1 Send timing in line + field, pixel data, send out

        2.2 In the sending timing of row + field, send out the horizontal and vertical coordinates at this moment

 that's probably it

Guess you like

Origin blog.csdn.net/qq_42792802/article/details/127032032