[一看就会]:VGA显示原理(时序分析附Verilog) - 知乎

VGA

简介

VGA(Video Graphics Array)视频图形阵列是IBM于1987年随PS/2机一起推出的一种使用模拟信号的视频传输标准,具有分辨率高、显示速率快、颜色丰富等优点,在彩色显示器领域得到了广泛的应用。不支持热插拔,不支持音频传输。

    • *

色彩原理

由于人的肉眼有感知红、绿、蓝三种不同颜色的锥体细胞,因此色彩空间通常可以由三种基本色来表达。三种基色是相互独立的,任何一种基色都不能有其它两种颜色合成。红绿蓝是三基色,这三种颜色合成的颜色范围最为广泛。我们的RGB信号就是三基色的运用,对这三个信号赋予不同的数值,混合起来便是不同的色彩。

    • *

VGA的驱动板设计

VGA一共有15个针脚,其中红,蓝,绿三路输入为模拟量输入,行,场为数字输入,而FPGA的输出全部为数字信号,所以需要将数字量转为模拟量。具体有以下几种方案。

  • 权电阻网络:RGB565(全电阻网络不需要 VGA_clk 和 VGA_blank 以及vga_sync 信号。)

  • RGB323

  • AD芯片

    • *

VGA显示原理

VGA显示图像使用扫描的方式,从第一行的第一个像素开始,逐渐填充,第一行第一个、第一行第二个、、、、第二行第一个、第二行第二个、、、、第n行最后一个。

通过这种方式构成一帧完整的图像,当扫描速度足够快,加之人眼的视觉暂留特性,我们会看到一幅完整的图片,而不是一个个闪烁的像素点。这就是VGA 显示的原理。

    • *

VGA时序标准

  • VGA有两个非常重要的信号,一个是行同步信号(HSYNC),另一个是场同步信号(VSYNC)。通过这两个信号完成一帧图像的像素点扫描。
  • 在数字电路中,时序是我们进行程序设计的重要依据。
  • 行场同步信号的时序如下

  • 也就是当HSYNC的高电平来临,VGA显示器就知道,我要开始接收这一行要显示的像素信息的,当下一个高电平来临时,那么这一行的图像信息就传输完成了,其中真正要显示的图像信息就蕴含在这一周期中。 - 同理场同步也如此
    • *

那么这两个信号时如何配合的呢?

这就和我们希望VGA显示的模式有关了,VGA可以显示不同分辨率的图像,不同分辨率及帧率对应参数如下:

先搞明白各参数意义以640x480@60为例:

  • 显示模式:640x480@60:640x480 是指 VGA 的分辨率,640 是指有效显示图像每一行有 640 个像素点,480 是指每一帧图像有 480 行,640 * 480 = 307200 ≈ 300000,每一帧图片包含约 30 万个像素点,手机广告上所说的 30 万像素指的就是这个;@60 是指 VGA 显示图像的刷新频率,60 就是指 VGA 显示器每秒刷新图像 60 次,即每秒钟需要显示 60 帧图像。
  • 时钟(MHz):25.175MHz,这是 VGA 显示的工作时钟,像素点扫描频率。
  • 时钟是一个基准,大家都在一个时钟下等待,工作,计数,就像时间一样。
  • 行同步一共800个周期(96+40+8+640+8+8),这个周期是时钟周期,也就是800个上升沿和下降沿(一个上升沿和一个下降沿为一个周期),有效图像在145到785之间,也就是在第145个上升沿到来的时候我们让RGB输出高低电平(不同的高低电平可以组合出不同的颜色,比如RGB888格式下输出11111111110000000000000000,为红色),这样我们第一行第一个像素的颜色信息就确定了,第146个上升沿来临的时候在输出第二个像素信息,147第三个、、、直到第785个时钟周期,第一行的全部图像信息就都发送给VGA显示器了。
  • 场同步一共525个周期,这个周期是指一个行同步周期,也就是行同步走完800个时钟周期,行同步才走一个周期(第801个时钟周期的上升沿来临,行同步和场同步同时进入同步阶段),同理当场同步走到第36个周期时,表示第一行的像素、37周期表示第二行、、、
  • 也就是说行同步每走完800个时钟周期,场同步走完一个周期。
  • 当场同步来到第36个周期时
行同步进入同步阶段96个时钟周期、后沿40、 左边框8 ;
行同步走到第145个时钟周期时,RGB输出数据,屏幕的第1行第1个像素将被点亮;
行同步走到第146个时钟周期时,RGB输出数据,屏幕的第1行第2个像素将被点亮;
。。。
行同步走到第785个时钟周期时,RGB输出数据,屏幕的第1行第640个像素将被点亮;
至此第一行全部图像显示完毕 。
行同步继续走16个时钟周期(右边沿8个+前沿8个),直到一共走完800个时钟周期。
  • 场同步周期来到第37个周期
行同步进入同步阶段96个时钟周期、后沿40 、左边框8 ;
行同步走到第145个时钟周期时,RGB输出数据,屏幕的第2行第1个像素将被点亮;
行同步走到第146个时钟周期时,RGB输出数据,屏幕的第2行第2个像素将被点亮;
。。。
行同步走到第785个时钟周期时,RGB输出数据,屏幕的第2行第640个像素将被点亮;
至此第二行全部图像显示完毕;
行同步继续走16个时钟周期(右边沿8个+前沿8个),直到一共走完800个时钟周期
。。。
    • *

Verilog代码

VGA时序控制模块

  • 我们在设计程序是可以定义一些参数和计数器辅助设计,最终保证hsync,vsync,和RGB的信号能够依据时序的逻辑输出就可以。

FPGA的编程是时序逻辑,会产生延迟一拍的效果,所以会多添加一些信号辅助设计。

代码来自野火,大家可以参照波形进行学习,希望对大家有所帮助!

  • 控制模块(前面说的时序部分)
 `timescale  1ns/1ns
 module  vga_ctrl (     
  input   wire            vga_clk     ,   //输入工作时钟,频率25MHz     
  input   wire            sys_rst_n   ,   //输入复位信号,低电平有效     
  input   wire    [15:0]  pix_data    ,   //输入像素点色彩信息
  output  wire    [9:0]   pix_x       ,   //输出VGA有效显示区域像素点X轴坐标 output  wire    [9:0]   pix_y       ,   //输出VGA有效显示区域像素点Y轴坐标 output  wire            hsync       ,   //输出行同步信号 output  wire            vsync       ,   //输出场同步信号 output  wire    [15:0]  rgb             //输出像素点色彩信息
 );

//parameter define 
parameter H_SYNC    =   10'd96  ,   //行同步时钟周期数           
          H_BACK    =   10'd40  ,   //行时序后沿           
          H_LEFT    =   10'd8   ,   //行时序左边框           
          H_VALID   =   10'd640 ,   //行有效数据           
          H_RIGHT   =   10'd8   ,   //行时序右边框           
          H_FRONT   =   10'd8   ,   //行时序前沿           
          H_TOTAL   =   10'd800 ;   //行扫描周期 
parameter V_SYNC    =   10'd2   ,   //场同步           
          V_BACK    =   10'd25  ,   //场时序后沿     
          V_TOP     =   10'd8   ,   //场时序上边框       
          V_VALID   =   10'd480 ,   //场有效数据
          V_BOTTOM  =   10'd8   ,   //场时序下边框    
          V_FRONT   =   10'd2   ,   //场时序前沿       
          V_TOTAL   =   10'd525 ;   //场扫描周期
 //wire  define 
          wire            rgb_valid       ;   //VGA有效显示区域 
          wire            pix_data_req    ;   //像素点色彩信息请求信号
 //reg   define 
          reg     [9:0]   cnt_h           ;   //行同步信号计数器 
          reg     [9:0]   cnt_v           ;   //场同步信号计数器
//***** Main Code ****//

//cnt_h:行同步信号计数器 
always@(posedge vga_clk or  negedge sys_rst_n)     
if(sys_rst_n == 1'b0)         
   cnt_h   <=  10'd0   ;     
else   if(cnt_h == H_TOTAL - 1'd1)         
   cnt_h   <=  10'd0   ;     
else  
   cnt_h   <=  cnt_h + 1'd1   ;

 //hsync:行同步信号 
assign  hsync = (cnt_h  <=  H_SYNC - 1'd1) ? 1'b1 : 1'b0  ;

 //cnt_v:场同步信号计数器 
always@(posedge vga_clk or  negedge sys_rst_n)     
if(sys_rst_n == 1'b0)      
    cnt_v   <=  10'd0 ;     
else    if((cnt_v == V_TOTAL - 1'd1) &&  (cnt_h == H_TOTAL-1'd1))        
    cnt_v   <=  10'd0 ;    
else    if(cnt_h == H_TOTAL - 1'd1)        
    cnt_v   <=  cnt_v + 1'd1 ;    
else       
    cnt_v   <=  cnt_v ;

 //vsync:场同步信号 
assign  vsync = (cnt_v  <=  V_SYNC - 1'd1) ? 1'b1 : 1'b0  ;

 //rgb_valid:VGA有效显示区域 
assign  rgb_valid = (((cnt_h >= H_SYNC + H_BACK + H_LEFT)
                     && (cnt_h < H_SYNC + H_BACK + H_LEFT + H_VALID)
                     &&((cnt_v >= V_SYNC + V_BACK + V_TOP)                     
                     && (cnt_v < V_SYNC + V_BACK + V_TOP + V_VALID)))       
                     ? 1'b1 : 1'b0;

 //pix_data_req:像素点色彩信息请求信号,超前rgb_valid信号一个时钟周期 
assign  pix_data_req = (((cnt_h >= H_SYNC + H_BACK + H_LEFT - 1'b1)                     
                       && (cnt_h < H_SYNC + H_BACK + H_LEFT + H_VALID - 1'b1))
                       &&((cnt_v >= V_SYNC + V_BACK + V_TOP)
                       && (cnt_v < V_SYNC + V_BACK + V_TOP + V_VALID)))
                       ? 1'b1 : 1'b0;

 //pix_x,pix_y:VGA有效显示区域像素点坐标 
assign  pix_x = (pix_data_req == 1'b1)
                 ? (cnt_h - (H_SYNC + H_BACK + H_LEFT - 1'b1)) : 10'h3ff; 
assign  pix_y = (pix_data_req == 1'b1)
                 ? (cnt_v - (V_SYNC + V_BACK + V_TOP)) : 10'h3ff;

 //rgb:输出像素点色彩信息 
assign  rgb = (rgb_valid == 1'b1) ? pix_data : 16'b0 ;


 endmodule
 
  • 显示图片的数据(彩条)
`timescale  1ns/1ns
 module  vga_pic (     
input   wire            vga_clk     ,   //输入工作时钟,频率25MHz
input   wire            sys_rst_n   ,   //输入复位信号,低电平有效
input   wire    [9:0]   pix_x       ,   //输入VGA有效显示区域像素点X轴坐标     
input   wire    [9:0]   pix_y       ,   //输入VGA有效显示区域像素点Y轴坐标
output  reg     [15:0]  pix_data        //输出像素点色彩信息
 );
//** Parameter and Internal Signal ***// 
parameter   H_VALID =   10'd640 ,   //行有效数据
            V_VALID =   10'd480 ;   //场有效数据
parameter   RED     =   16'hF800,   //红色            
            ORANGE  =   16'hFC00,   //橙色
            YELLOW  =   16'hFFE0,   //黄色
            GREEN   =   16'h07E0,   //绿色 
            CYAN    =   16'h07FF,   //青色 
            BLUE    =   16'h001F,   //蓝色 
            PURPPLE =   16'hF81F,   //紫色  
            BLACK   =   16'h0000,   //黑色 
            WHITE   =   16'hFFFF,   //白色 
            GRAY    =   16'hD69A;   //灰色
 //**********// //***** Main Code ****// //************//
 //pix_data:输出像素点色彩信息,根据当前像素点坐标指定当前像素点颜色数据 
always@(posedge vga_clk or negedge sys_rst_n)     
if(sys_rst_n == 1'b0)         
pix_data    <= 16'd0;     
else    if((pix_x >= 0) && (pix_x < (H_VALID/10)1))         
pix_data    <=  RED;     
else    if((pix_x >= (H_VALID/10)1) && (pix_x < (H_VALID/10)2))         
    pix_data    <=  ORANGE;     
else    if((pix_x >= (H_VALID/10)2) && (pix_x < (H_VALID/10)3))         
    pix_data    <=  YELLOW;     
else    if((pix_x >= (H_VALID/10)3) && (pix_x < (H_VALID/10)4))         
    pix_data    <=  GREEN;     
else    if((pix_x >= (H_VALID/10)4) && (pix_x < (H_VALID/10)5))         
    pix_data    <=  CYAN;     
else    if((pix_x >= (H_VALID/10)5) && (pix_x < (H_VALID/10)6))        
    pix_data    <=  BLUE;     
else    if((pix_x >= (H_VALID/10)6) && (pix_x < (H_VALID/10)7))         
    pix_data    <=  PURPPLE;    
 else    if((pix_x >= (H_VALID/10)7) && (pix_x < (H_VALID/10)8))         
    pix_data    <=  BLACK;     
else    if((pix_x >= (H_VALID/10)8) && (pix_x < (H_VALID/10)9))        
    pix_data    <=  WHITE;    
 else    if((pix_x >= (H_VALID/10)9) && (pix_x < H_VALID))        
    pix_data    <=  GRAY;     
else         
    pix_data    <=  BLACK;
 endmodule
 
  • 顶层模块(例化上面两个模块,并调用IP核产生25Mhz时钟)
 `timescale  1ns/1ns module  
vga_colorbar (     
input   wire            sys_clk     ,   //输入工作时钟,频率50MHz     
input   wire            sys_rst_n   ,   //输入复位信号,低电平有效
 
output  wire            hsync       ,  //输出行同步信号 
output  wire            vsync       ,  //输出场同步信号 
output  wire    [15:0]  rgb            //输出像素信息
 );
 //**********// //** Parameter and Internal Signal ***// //**********// //wire define
 wire            vga_clk ;   //VGA工作时钟,频率25MHz
 wire            locked  ;   //PLL locked信号
 wire            rst_n   ;   //VGA模块复位信号
 wire    [9:0]   pix_x   ;   //VGA有效显示区域X轴坐标
 wire    [9:0]   pix_y   ;   //VGA有效显示区域Y轴坐标
 wire    [15:0]  pix_data;   //VGA像素点色彩信息

 //rst_n:VGA模块复位信号 
assign  rst_n = (sys_rst_n & locked);
 //**********// //**** Instantiation ***// //************//
 //------------- clk_gen_inst ------------- 
clk_gen clk_gen_inst 
(
     .areset     (~sys_rst_n ),  //输入复位信号,高电平有效,1bit
     .inclk0     (sys_clk    ),  //输入50MHz晶振时钟,1bit

     .c0         (vga_clk    ),  //输出VGA工作时钟,频率25Mhz,1bit
     .locked     (locked     )   //输出pll locked信号,1bit
 );
 //------------- vga_ctrl_inst ------------- 
vga_ctrl  vga_ctrl_inst
 (     
     .vga_clk    (vga_clk    ),  //输入工作时钟,频率25MHz,1bit     
     .sys_rst_n  (rst_n      ),  //输入复位信号,低电平有效,1bit
     .pix_data   (pix_data   ),  //输入像素点色彩信息,16bit
     .pix_x      (pix_x      ),  //输出VGA有效显示区域像素点X轴坐标,10bit
     .pix_y      (pix_y      ),  //输出VGA有效显示区域像素点Y轴坐标,10bit
     .hsync      (hsync      ),  //输出行同步信号,1bit
     .vsync      (vsync      ),  //输出场同步信号,1bit 
     .rgb        (rgb        )   //输出像素点色彩信息,16bit
 );
 //------------- vga_pic_inst ------------- 
vga_pic vga_pic_inst 
(     .vga_clk    (vga_clk    ),  //输入工作时钟,频率25MHz,1bit
      .sys_rst_n  (rst_n      ),  //输入复位信号,低电平有效,1bit
      .pix_x      (pix_x      ),  //输入VGA有效显示区域像素点X轴坐标,10bit
      .pix_y      (pix_y      ),  //输入VGA有效显示区域像素点Y轴坐标,10bit
      .pix_data   (pix_data   )   //输出像素点色彩信息,16bit
 );

 endmodule
 

原网址: 访问
创建于: 2023-08-16 18:30:37
目录: default
标签: 无

请先后发表评论
  • 最新评论
  • 总共0条评论