VGA系列文章目录:
(1)VGA成像原理与简单实现
(2)VGA显示板级验证
(3)VGA显示-多分辨率输入
(4)串口发送+RAM+VGA传图


前言

本篇文章记录使用ACX720开发板实现VGA板级验证,将8中颜色通过VGA接口输出到指定位置。


提示:以下是本篇文章正文内容,下面案例可供参考

一、板级验证功能设计

我们设计一个测试工程,该工程中我们测试上述提到的8种颜色,通过颜色的位置,不但能确定是否能够正确输出指定颜色的图像,还能间接确定是否能够精确指定像素位置。 因此,我们对屏幕进行划分,将屏幕划分成4行2列总共八个像素阵列,每个阵列分别显示一种颜色。据此,我们可以首先定义每种顔色的具体数据编码,然后再定义每个像素阵列的基本显示颜色,这里首先使用 parameter定义每种顔色的具体数据编码。
代码如下(示例):

1.设置颜色参数

parameter 
      BLACK = 24'h000000,    //黑色   
      BLUE  = 24'h0000FF,    //蓝色   
      RED   = 24'hFF0000,   //红色    
      PURPPLE = 24'hFF00FF,  //紫色   
      GREEN = 24'h00FF00,    //绿色   
      CYAN = 24'h00FFFF,     //青色   
      YELLOW = 24'hFFFF00,   //黄色   
      WHITE = 24'hFFFFFF;    //白色   
  parameter 
      R0_C0 = BLACK  ,   //第0行0列像素块   
      R0_C1 = BLUE   ,   //第0行1列像素块   
      R1_C0 = RED    ,   //第1行0列像素块   
      R1_C1 = PURPPLE ,  //第1行1列像素块   
      R2_C0 = GREEN  ,   //第2行0列像素块   
      R2_C1 = CYAN   ,   //第2行1列像素块   
      R3_C0 = YELLOW ,   //第3行0列像素块   
      R3_C1 = WHITE  ;   //第3行1列像素块   

2.确定位置区间

代码如下(示例):

 wire C0_act,C1_act;   
   assign C0_act = (H_count >= 0)    && (H_count < 320);//正在扫描第0列  
   assign C1_act = (H_count >= 320 ) && (H_count < 640);  //正在扫描第1列 
   
   wire R0_act,R1_act,R2_act,R3_act;
   assign R0_act = (V_count >= 0)   && (V_count < 120);      //正在扫描第0行
   assign R1_act = (V_count >= 120) && (V_count < 240);    //正在扫描第1行
   assign R2_act = (V_count >= 240) &&  (V_count < 360);   //正在扫描第2行
   assign R3_act = (V_count >= 360) && (V_count < 480);    //正在扫描第3行
  

   wire R0_C0_ACT,R0_C1_ACT,R1_C0_ACT,R1_C1_ACT,R2_C0_ACT,R2_C1_ACT,R3_C0_ACT,R3_C1_ACT;
   assign R0_C0_ACT = R0_act & C0_act;       //第0行0列像素块处于被扫描中标志信号 
   assign R0_C1_ACT = R0_act & C1_act;       //第0行1列像素块处于被扫描中标志信号 
   assign R1_C0_ACT = R1_act & C0_act;       //第1行0列像素块处于被扫描中标志信号 
   assign R1_C1_ACT = R1_act & C1_act;       //第1行1列像素块处于被扫描中标志信号 
   assign R2_C0_ACT = R2_act & C0_act;       //第2行0列像素块处于被扫描中标志信号 
   assign R2_C1_ACT = R2_act & C1_act;       //第2行1列像素块处于被扫描中标志信号 
   assign R3_C0_ACT = R3_act & C0_act;       //第3行0列像素块处于被扫描中标志信号 
   assign R3_C1_ACT = R3_act & C1_act;       //第3行1列像素块处于被扫描中标志信号 
   

3.确定VGA输出颜色

代码如下(示例):

always @ (*)
     case ({R0_C0_ACT,R0_C1_ACT,R1_C0_ACT,R1_C1_ACT,
            R2_C0_ACT,R2_C1_ACT,R3_C0_ACT,R3_C1_ACT})
         8'b1000_0000  : disp_data =R3_C1;
         8'b0100_0000  : disp_data =R0_C1;
         8'b0010_0000  : disp_data =R1_C0;
         8'b0001_0000  : disp_data =R1_C1;
         8'b0000_1000  : disp_data =R2_C0;
         8'b0000_0100  : disp_data =R2_C1;
         8'b0000_0010  : disp_data =R3_C0;
         8'b0000_0001  : disp_data =R0_C0;
         default       : disp_data =R3_C1;
     endcase 

二、V_count、H_count产生

根据上面的描述需要首先产生H_count、V_count来确定扫描位置。于是对上篇文章《VGA成像原理与简单实现》代码稍作修改,产生H_count、V_count。


    always @ (posedge clk) 
        VGA_BLK <= Data_request;
        
    always @ (posedge clk)
        H_count <= (Data_request) ?(H_cnt-Hdata_begin):0;
        
    always @ (posedge clk)
        V_count <= (Data_request) ?(V_cnt-Vdata_begin):0;     

三、时钟IP核

由于VGA成像显示为640480分辨率,实际所用60帧刷新率为800525*60 = 25.175Mhz,于是需要产生25Mhz的时钟频率。更多标准可参考(分辨率VES标准)。


产生方式可以参考《DDS结构的FPGA实现》。

1.将搜索内容ROM换为Clocking。

2.双击蓝色部分进入IP配置

clk_in1为开发板输入时钟频率(我的ACX720为50MHZ)。


设置clk_out1为想要的输出时钟25Mhz。


四、TOP文件设计

`timescale 1ns / 1ps
//
// Create Date: 2022/12/05 17:00:16
// Module Name: VGA_CTRL_TOP
// Tool Versions:Vivado 2018.3 
// Revision 0.01 - File Created
// NAME: 小王在努力...
//
module VGA_CTRL_TOP(
    clk,  
    reset,
    HS_YS,
    VS_YS,
    VGA_BLK,
    clk25M,
    RGB_output
    );
    input clk;  //50MHZ
    input reset;
    output  HS_YS;           //行同步脉冲信号
    output  VS_YS;           //场同步脉冲信号
    output  VGA_BLK;         //VGA有效数据显示脉冲信号
    output  clk25M;          //系统输入时钟25MHZ
    output  [23:0]RGB_output;      //RGB输出值 
    
    wire [23:0]disp_data;
    wire [11:0]H_count;
    wire [11:0]V_count;
    wire Data_request;
    
    
    
    CLK25M_pll CLK25M_pll(
    .clk_out1(clk25M),     // output clk_out1
    .clk_in1(clk)      // input clk_in1
    );
     
    
    VGA_CTRL_640x480 VGA_CTRL_640x480(
   .clk(clk25M),    //系统输入时钟25MHZ
   .reset(reset),
   .Data(disp_data),
   .Data_request(Data_request),
   .HS_YS(HS_YS),
   .VS_YS(VS_YS),
   .H_count(H_count),
   .V_count(V_count),
   .VGA_BLK(VGA_BLK),
   .RGB_output(RGB_output)
    );
    
    
    
    VGA_CTRL_TEST VGA_CTRL_TEST(
    .H_count(H_count),
    .V_count(V_count),
    .disp_data(disp_data)
    );
endmodule

五、VGA_CTRL_TEST模块设计

module VGA_CTRL_TEST(
    H_count,
    V_count,
    disp_data
    );
    
    
    input [11:0]H_count;
    input [11:0]V_count;
    output reg [23:0]disp_data;
    

  parameter 
      BLACK = 24'h000000,    //黑色   
      BLUE  = 24'h0000FF,    //蓝色   
      RED   = 24'hFF0000,   //红色    
      PURPPLE = 24'hFF00FF,  //紫色   
      GREEN = 24'h00FF00,    //绿色   
      CYAN = 24'h00FFFF,     //青色   
      YELLOW = 24'hFFFF00,   //黄色   
      WHITE = 24'hFFFFFF;    //白色   
  parameter 
      R0_C0 = BLACK  ,   //第0行0列像素块   
      R0_C1 = BLUE   ,   //第0行1列像素块   
      R1_C0 = RED    ,   //第1行0列像素块   
      R1_C1 = PURPPLE ,  //第1行1列像素块   
      R2_C0 = GREEN  ,   //第2行0列像素块   
      R2_C1 = CYAN   ,   //第2行1列像素块   
      R3_C0 = YELLOW ,   //第3行0列像素块   
      R3_C1 = WHITE  ;   //第3行1列像素块   
      
      
   `include "vga_parameter.v" 

    wire R0_act = (vcount >= 0                 && vcount < `V_Data_Time/4);  //正在扫描第0行
    wire R1_act = (vcount >= `V_Data_Time/4    && vcount < `V_Data_Time/2);//正在扫描第1行
    wire R2_act = (vcount >= `V_Data_Time/2    && vcount < `V_Data_Time*3/4);//正在扫描第2行
    wire R3_act = (vcount >= `V_Data_Time*3/4  && vcount < `V_Data_Time);//正在扫描第3行
    
    wire C0_act = (hcount >= 0                 && hcount < `H_Data_Time/2); //正在扫描第0列
    wire C1_act = (hcount >= `H_Data_Time/2    && hcount < `H_Data_Time);//正在扫描第1列 
  

   wire R0_C0_ACT,R0_C1_ACT,R1_C0_ACT,R1_C1_ACT,R2_C0_ACT,R2_C1_ACT,R3_C0_ACT,R3_C1_ACT;
   assign R0_C0_ACT = R0_act & C0_act;       //第0行0列像素块处于被扫描中标志信号 
   assign R0_C1_ACT = R0_act & C1_act;       //第0行1列像素块处于被扫描中标志信号 
   assign R1_C0_ACT = R1_act & C0_act;       //第1行0列像素块处于被扫描中标志信号 
   assign R1_C1_ACT = R1_act & C1_act;       //第1行1列像素块处于被扫描中标志信号 
   assign R2_C0_ACT = R2_act & C0_act;       //第2行0列像素块处于被扫描中标志信号 
   assign R2_C1_ACT = R2_act & C1_act;       //第2行1列像素块处于被扫描中标志信号 
   assign R3_C0_ACT = R3_act & C0_act;       //第3行0列像素块处于被扫描中标志信号 
   assign R3_C1_ACT = R3_act & C1_act;       //第3行1列像素块处于被扫描中标志信号 
   
 
   always @ (*)
     case ({R0_C0_ACT,R0_C1_ACT,R1_C0_ACT,R1_C1_ACT,
            R2_C0_ACT,R2_C1_ACT,R3_C0_ACT,R3_C1_ACT})
         8'b1000_0000  : disp_data =R3_C1;
         8'b0100_0000  : disp_data =R0_C1;
         8'b0010_0000  : disp_data =R1_C0;
         8'b0001_0000  : disp_data =R1_C1;
         8'b0000_1000  : disp_data =R2_C0;
         8'b0000_0100  : disp_data =R2_C1;
         8'b0000_0010  : disp_data =R3_C0;
         8'b0000_0001  : disp_data =R0_C0;
         default       : disp_data =R3_C1;
     endcase 
            
endmodule

六、VGA_CTRL_640x480模块设计

`timescale 1ns / 1ps
//

// Create Date: 2022/11/30 15:18:34
// Module Name: VGA_CTRL_640x480
// Project Name: 640x480图像输出
// Revision: VIVADO 2018.3
// Name:小王在努力...
//


module VGA_CTRL_640x480(
    clk,
    reset,
    Data,
    Data_request,
    HS_YS,
    VS_YS,
    H_count,
    V_count,
    VGA_BLK,
    RGB_output
    );
    input clk;
    input reset;
    input [23:0]Data;             //输入数据
    output  reg Data_request;     //数据请求脉冲信号
    output reg HS_YS;           //行同步脉冲信号
    output reg VS_YS;           //场同步脉冲信号
    output reg [11:0]H_count;             //行有效输出值(实际行像素有效值)
    output reg [11:0]V_count;             //场有效输出值(实际场像素有效值)
    output reg VGA_BLK;         //VGA有效数据显示脉冲信号
    output  RGB_output;      //RGB输出值 
      
    `include "vga_parameter.v" 
    parameter Hsync_end = `H_Total_Time; 
    parameter HS_END = `H_Sync_Time;
    parameter Vsync_end = `V_Total_Time;
    parameter VS_END = `V_Sync_Time;
    parameter Hdata_begin = `H_Sync_Time + `H_Back_Porch + `H_Left_Border;
    parameter Hdata_end = `H_Sync_Time + `H_Left_Border + `H_Back_Porch + `H_Data_Time;
    parameter Vdata_begin = `V_Sync_Time + `V_Back_Porch + `V_Top_Border;
    parameter Vdata_end = `V_Sync_Time + `V_Back_Porch + `V_Top_Border + `V_Data_Time; 
    
    reg [11:0]H_cnt;  //行扫描计数器
    always @ (posedge clk or negedge reset)
        if(!reset)
            H_cnt <= 0;
        else if(H_cnt >= Hsync_end -1 )
            H_cnt <= 0;
        else 
            H_cnt <= H_cnt + 1'b1;
    //  行同步脉冲信号      
    always @ (posedge clk)
        HS_YS <= (H_cnt <= HS_END-1 )?0:1;
        
        
     reg [11:0]V_cnt;//场扫描计数器
    always @ (posedge clk or negedge reset)
        if(!reset)
            V_cnt <= 0;
        else if( H_cnt == Hsync_end -1)begin
            if(V_cnt >= Vsync_end-1)
                V_cnt <= 0;
            else 
                V_cnt <= V_cnt + 1;
            end
        else 
             V_cnt <= V_cnt ;
    //场同步脉冲信号         
    always @ (posedge clk)
        VS_YS <= (V_cnt <= VS_END-1 )?0:1; 
        
    always @ (posedge clk) 
        Data_request <= (H_cnt >= Hdata_begin - 1 )&&(H_cnt <= Hdata_end - 2)&&(V_cnt >= Vdata_begin)&&(V_cnt <= Vdata_end -1);
     
    always @ (posedge clk) 
        VGA_BLK <= Data_request;
        
    always @ (posedge clk)
        H_count <= (Data_request) ?(H_cnt-Hdata_begin):0;
        
    always @ (posedge clk)
        V_count <= (Data_request) ?(V_cnt-Vdata_begin):0;     
        
    //always @ (posedge clk)
    wire [23:0]RGB_output;
    assign   RGB_output = (VGA_BLK) ?(Data):0;
     
endmodule

七、vga_parameter.v



//`define Resolution_480x272 1	//刷新率为60Hz时像素时钟为9MHz
//`define Resolution_640x480 1	//刷新率为60Hz时像素时钟为25.175MHz
`define Resolution_800x480 1	//刷新率为60Hz时像素时钟为33MHz
//`define Resolution_800x600 1	//刷新率为60Hz时像素时钟为40MHz
//`define Resolution_1024x768 1	//刷新率为60Hz时像素时钟为65MHz
//`define Resolution_1280x720 1	//刷新率为60Hz时像素时钟为74.25MHz
//`define Resolution_1920x1080 1	//刷新率为60Hz时像素时钟为148.5MHz

`ifdef Resolution_480x272    
    `define H_Right_Border 0
    `define H_Front_Porch 2
    `define H_Sync_Time 41
    `define H_Back_Porch 2
    `define H_Left_Border 0
    `define H_Data_Time 480
    `define H_Total_Time 525
    `define V_Bottom_Border 0
    `define V_Front_Porch 2
    `define V_Sync_Time 10
    `define V_Back_Porch 2
    `define V_Top_Border 0
    `define V_Data_Time 272
    `define V_Total_Time 286
    
`elsif Resolution_640x480
	`define H_Total_Time  12'd800
	`define H_Right_Border  12'd8
	`define H_Front_Porch  12'd8
	`define H_Sync_Time  12'd96
	`define H_Data_Time 12'd640
	`define H_Back_Porch  12'd40
	`define H_Left_Border  12'd8
	`define V_Total_Time  12'd525
	`define V_Bottom_Border  12'd8
	`define V_Front_Porch  12'd2
	`define V_Sync_Time  12'd2
	`define V_Data_Time 12'd480
	`define V_Back_Porch  12'd25
	`define V_Top_Border  12'd8
	
`elsif Resolution_800x480
	`define H_Total_Time 12'd1056
	`define H_Right_Border 12'd0
	`define H_Front_Porch 12'd40
	`define H_Sync_Time 12'd128
	`define H_Data_Time 12'd800
	`define H_Back_Porch 12'd88
	`define H_Left_Border 12'd0

	`define V_Total_Time 12'd525
	`define V_Bottom_Border 12'd8
	`define V_Front_Porch 12'd2
	`define V_Sync_Time 12'd2
	`define V_Data_Time 12'd480
	`define V_Back_Porch 12'd25
	`define V_Top_Border 12'd8

`elsif Resolution_800x600
	`define H_Total_Time 12'd1056
	`define H_Right_Border 12'd0
	`define H_Front_Porch 12'd40
	`define H_Sync_Time 12'd128
	`define H_Data_Time 12'd800
	`define H_Back_Porch 12'd88
	`define H_Left_Border 12'd0

	`define V_Total_Time 12'd628
	`define V_Bottom_Border 12'd0
	`define V_Front_Porch 12'd1
	`define V_Sync_Time 12'd4
	`define V_Data_Time 12'd600
	`define V_Back_Porch 12'd23
	`define V_Top_Border 12'd0

`elsif Resolution_1024x768
	`define H_Total_Time 12'd1344
	`define H_Right_Border 12'd0
	`define H_Front_Porch 12'd24
	`define H_Sync_Time 12'd136
	`define H_Data_Time 12'd1024
	`define H_Back_Porch 12'd160
	`define H_Left_Border 12'd0

	`define V_Total_Time 12'd806
	`define V_Bottom_Border 12'd0
	`define V_Front_Porch 12'd3
	`define V_Sync_Time 12'd6
	`define V_Data_Time 12'd768
	`define V_Back_Porch 12'd29
	`define V_Top_Border 12'd0

`elsif Resolution_1280x720
	`define H_Total_Time 12'd1650
	`define H_Right_Border 12'd0
	`define H_Front_Porch 12'd110
	`define H_Sync_Time 12'd40
	`define H_Data_Time 12'd1280
	`define H_Back_Porch 12'd220
	`define H_Left_Border 12'd0

	`define V_Total_Time 12'd750
	`define V_Bottom_Border 12'd0
	`define V_Front_Porch 12'd5
	`define V_Sync_Time 12'd5
	`define V_Data_Time 12'd720
	`define V_Back_Porch 12'd20
	`define V_Top_Border 12'd0
		
`elsif Resolution_1920x1080
	`define H_Total_Time 12'd2200
	`define H_Right_Border 12'd0
	`define H_Front_Porch 12'd88
	`define H_Sync_Time 12'd44
	`define H_Data_Time 12'd1920
	`define H_Back_Porch 12'd148
	`define H_Left_Border 12'd0

	`define V_Total_Time 12'd1125
	`define V_Bottom_Border 12'd0
	`define V_Front_Porch 12'd4
	`define V_Sync_Time 12'd5
	`define V_Data_Time 12'd1080
	`define V_Back_Porch 12'd36
	`define V_Top_Border 12'd0	
	
`endif

八、TB模块展示

`timescale 1ns / 1ps
//
// Create Date: 2022/11/30 16:07:54
// Design Name: VGA_CTRL
// Module Name: VGA_CTRL_TB
// Project Name: VGA_CTRL
// Revision:2018.3
// Revision 0.01 - File Created
// Name:小王在努力...
//


module VGA_CTRL_TB();
    reg clk;
    reg reset;
    wire  HS_YS;           //行同步脉冲信号
    wire  VS_YS;           //场同步脉冲信号
    wire  VGA_BLK;         //VGA有效数据显示脉冲信号
    wire  clk25M;
    wire  [23:0]RGB_output;      //RGB输出值 
    
  VGA_CTRL_TOP VGA_CTRL_TOP(
    clk,  
    reset,
    HS_YS,
    VS_YS,
    VGA_BLK,
    clk25M,
    RGB_output
    );

    initial clk = 1;
    always #10 clk = ~clk;
    
    initial begin
        reset = 0;
        #201;
        reset = 1;
        #20000000;
        $stop;
    end

    
endmodule

九、仿真结果展示

1.全局展示

2.细节展示

可以看出在V_count = 120时RGB_output数据发生改变,更多细节可以动手仿真测试。

【附件:】链接:https://pan.baidu.com/s/1InHtHoJm-U3Kt9YSqk1oAw?pwd=2t8y
提取码:2t8y