FPGA VGA图片显示(vga_top)

一、VGA简介

关于VGA的一些基础知识可以参考这篇文章:VGA介绍

二、程序设计

  • FMC_apt模块存储着图像数据
  • vga_top模块发送rom_rd_en信号请求图像数据vga_data,并且例化vga_driver模块输出vga显示所需的时序。
    在这里插入图片描述

顶层模块的代码如下:

module vga_top(pclk,
			   rst_n,
			   vga_data,
			   rom_rd_en,
			   hsync, 
			   vsync, 
			   vga_r, 
			   vga_g, 
			   vga_b);
   input              pclk;
   input              rst_n;
   input     [15:0]   vga_data;//存储图像数据的地方输入的16bit的图像数据

   output          rom_rd_en;//向存储图像数据的地方发出的读使能信号,
   							 //表示请求vga_data输入
   output          hsync;//vga的接口
   output          vsync;
   output [4:0]    vga_r;
   output [5:0]    vga_g;
   output [4:0]    vga_b;
               
   reg      rom_valid;                     
   wire     [10:0] pixel_xpos;          
   wire     [10:0] pixel_ypos;              
   wire     [15:0] pixel_data ;          
   wire     [15:0] vga_rgb;
 
    localparam POS_X  = 10'd100;                //图片区域起始点横坐标
	localparam POS_Y  = 10'd100;                //图片区域起始点纵坐标
	localparam WIDTH  = 10'd512;                //图片区域宽度
	localparam HEIGHT = 10'd512;                //图片区域高度
	localparam TOTAL  = 19'd262144;              //图案区域总像素数
	localparam WHITE  = 16'b1111_1111_1111_1111; //屏幕背景
   

   assign vga_r = vga_rgb[15:11];
   assign vga_g = vga_rgb[15:10];
   assign vga_b = vga_rgb[15:11];
   
   assign rom_rd_en = (pixel_xpos >= POS_X) && (pixel_xpos < POS_X + WIDTH)
                    && (pixel_ypos >= POS_Y) && (pixel_ypos < POS_Y + HEIGHT)
                     ? 1'b1 : 1'b0;
                                     
   
   always @(posedge pclk ) 
	   begin         
		    if (!rst_n) 
		        rom_valid <= 1'b0;
		    else
		        rom_valid <= rom_rd_en;
		end
   
   assign pixel_data = rom_valid ? vga_data : WHITE; 
   
 
vga_driver u_vga_driver(
    .vga_clk            (pclk),    
    .sys_rst_n          (rst_n),    
    
    .vga_hs             (hsync),       
    .vga_vs             (vsync),       
    .vga_rgb            (vga_rgb),      
        
    .pixel_data         (pixel_data),                  
    .pixel_xpos         (pixel_xpos), 
    .pixel_ypos         (pixel_ypos)
    ); 
	
endmodule

VGA驱动模块的代码如下所示:

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 

程序中第14至25行通过变量声明定义了分辨率为640*480、刷新速率为60hz时VGA时序中的各个参数。

程序第59至69行通过行计数器cnt_h对像素时钟计数,计满一个行扫描周期后清零并重新开始计数。程序第71至81行通过场计数器cnt_v对行进行计数,即扫描完一行后cnt_v加1,计满一个场扫描周期后清零并重新开始计数。

将行场计数器的值与VGA时序中的参数作比较,我们就可以判断行场同步信号何时处于低电平同步状态,以及何时输出RGB565格式的图像数据(38~48行)。程序50至57行输出当前像素点的纵横坐标值,由于坐标输出后下一个时钟周期才能接收到像素点的颜色数据,因此数据请求信号data_req比数据输出使能信号vga_en提前一个时钟周期。

posted @ 2021-01-27 18:28  耐心的小黑  阅读(108)  评论(0编辑  收藏  举报