微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > FPGA和CPLD > 玩转VGA

玩转VGA

时间:01-29 来源:互联网 点击:
  一、VGA的诱惑
  首先,VGA的驱动,这事,一般的单片机是办不到的;由于FPGA的速度,以及并行的优势,加上可现场配置的优势,VGA的配置,只有俺们FPGA可以胜任,也只有FPGA可以随心所欲地配置(当然ARM也可以,应用比较高吧)。
  初学者就是喜欢看炫的效果,往往会忍不住想玩。尤其玩FPGA的,没玩VGA就感到跟单片机没啥提升,因此VGA的驱动也不得不讲。Bingo当年也是如此。挡不住VGA的诱惑,初学者问Bingo VGA问题的人也是灰常的多,也许一般教科书理论太强,实际应用不是很身后,在此Bingo用浅显易懂的语言来讲述VGA的驱动原理,以及通过设计一个可移植模块的应用来讲述。
  二、VGA驱动原理
  此处Bingo不参考任何资料,用当年已学的知识,用浅显易懂的语言讲述。
  1、VGA接口
  


  最主要的几根线:
  


  更详细的资料,请看 http://baike.baidu.com/view/10346.htm
  2、VGA时序
  VGA其实就是相当于一块芯片,跟单片机驱动IC一样,满足一定的时序,便能驱动起来。
  (1)扫描轨迹
  VGA的扫描其实很简单,大致轨迹如下所示:
  


  没扫描完一行,从新开始下一行;每扫完一场,重新开始下一场。相信你应该看的懂。
  (2)行场扫描
  以下是行扫描,场扫描HS,VS时序图
  


  如上如所示:VGA一直在扫描,没一场的扫描包括了若干行扫描,如此循环。
  (3)VS时序深入分析
  VS时序如下所示:
  


  可见时序的循环,可被划分为a,b,c,d4个时期。这四个时期定义如下:
  A~B:场消隐期 即同步,相当于还原扫描坐标吧
  B~C:场消隐后肩 相当于准备开始扫描吧
  C~D:场显示期 扫描中,数据有效区域
  D~E:场消隐前肩 完成扫描,相当于准备同步
  (4)HS时序深入分析
  可见时序的循环,可被划分为a,b,c,d4个时期。这四个时期定义如下:
  A~B:行消隐期 即同步,相当于还原扫描坐标吧
  B~C:行消隐后肩 相当于准备开始扫描吧
  C~D:行显示期 扫描中,数据有效区域
  D~E:行消隐前肩 完成扫描,相当于准备同步
  


  综上描述,我们只要知道每个时期的时间,便可以表示出VGA的时序。而FPGA的工作是由固定频率的时钟触发的,因此某固定时间可以用n次触发来表示。因此我们很容易就想到了FPGA常用的计数方法:比如说行扫描,我们计数0~H_total-1。用另一个进程将其划分为4个时期,安标注分配。其实这相当于状态机。
  以下是固定分辨率1024*768 60fps下HS,VS的标准:
  


  用代码表示4个时期,如下:
  // VGA_1024_768_60fps_65MHz
  // Horizontal Parameter( Pixel )
  parameter H_DISP = 11'd1024,
  parameter H_FRONT = 11'd24,
  parameter H_SYNC = 11'd136,
  parameter H_BACK = 11'd160,
  parameter H_TOTAL = 11'd1344,
  // Virtical Parameter( Line )
  parameter V_DISP = 10'd768,
  parameter V_FRONT = 10'd3,
  parameter V_SYNC = 10'd6,
  parameter V_BACK = 10'd29,
  parameter V_TOTAL = 10'd806
  3、VGA电路
  (1)三原色
  VGA接口:R,G,B三通道,直接赋给数字信号,RGB,最多产生8种色彩。这是最基本的。电路如下所示:
  


  (2)真彩显示
  a) 电阻网络
  考虑到成本意识实现的简易方案,用R-2R电阻网络分流模拟DAC替换ADV7123视频转换芯片。见以下几个方案:
  


  DE1 VGA模拟电路
  


  小马哥电路图
  具体设计参考Bingo当年总结:
  http://www.cnblogs.com/crazybingo/archive/2010/07/31/1789323.html
  或者参考小马哥设计:
  http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=3582675&bbs_page_no=1&search_mode=2&search_text=VGA&bbs_id=9999
  b) 专用视频转换芯片
  利用专用视频转换芯片,ADV7120等,将数字信号转换为VGA RGB的模拟信号。ADV7120为高速D/A芯片,将数字信号转换为模拟信号输给VGA,电路如下:
  


  三、可移植VGA模块设计
  Bingo玩VGA也算是比较早了,当年也是视觉的诱惑,以及唯FPGA独尊的优势。于是之后一发而不可收拾。本章Bingo将自己这些年最终优化的VGA驱动模块,发布至此。本模块所有代码均Bingo独家创造,请尊重版权哈。
  本设计已经封装成模块,只要修改时序参数、扫描时钟参数以及在vga_display.v中添加显示电路,即可。方便移植,希望对大家有用。
  1、模块划分
  


  (1)vga_design.v
  工程顶层文件,例化各个模块。
  (2)sys_ctrl.v
  PLL时钟分配电路。
  (3)vga_display.v
  显示电路,根据时序,用于描述VGA的显示电路。
  (4)vga_driver.v
  VGA驱动电路,对时序,状态的约束。
  RTL图如下所示:
  


                               
                2、代码设计
  Bingo例程以16bit RGB VGA驱动为例,不同位数的显示只要改一下vga_data即可。
  前文以及代码讲述了那么多,此处不再贴完整代码,而是对代码中部分结构进行解析。
  代码下载地址:http://blog.chinaaet.com/detail/21606.html
  (1)vga_driver.v代码分析
  a) 参数例化列表
  #(
  // VGA_1024_768_60fps_65MHz
  // Horizontal Parameter ( Pixel )
  parameter H_DISP = 11'd1024,
  parameter H_FRONT = 11'd24,
  parameter H_SYNC = 11'd136,
  parameter H_BACK = 11'd160,
  parameter H_TOTAL = 11'd1344,
  // Virtical Parameter ( Line )
  parameter V_DISP = 10'd768,
  parameter V_FRONT = 10'd3,
  parameter V_SYNC = 10'd6,
  parameter V_BACK = 10'd29,
  parameter V_TOTAL = 10'd806
  )
  这样写的目的是为了软件封装性,能够在例化的时候修改法分辨率,同时电路结构保持不变。
  DISP,FRONT ,SYNC,BACK,TOTAL分别为显示期,消隐前肩,消音期,消隐后肩,总时间,各自对应各自的行场信号。
  b) 行同步信号设计
  //------------------------------------------
  // 行同步信号发生器
  reg [10:0] hcnt;
  always @ (posedge clk_vga or negedge rst_n)
  begin
  if (!rst_n)
  hcnt = H_DISP+H_FRONT-1'b1) && (hcnt VGA时序不是完全吻合。但是VGA时序是一个循环,顺推H_BACK个时终域便可以得到以上时期划分,但是这样更方便后续坐标计数,因为Bingo此处这样设计,当然实际证明是完全可行的。
  注意:(hcnt >= H_DISP+H_FRONT-1'b1) && (hcnt = 0 && vga_xpos = (H_DISP>>3)*1 && vga_xpos


  本来可空锁相环PLL设计,Bingo想单独成章来讲述的,但觉得可能别的地方实际应用价值不是很大,最后便在此处阐明这样设计的原因。
  由于VGA不同分辨率的扫描时钟不同,因此分辨率变化的时候,PLL的输出时钟是必要跟随着变化。但是Bingo觉得好麻烦,于是想了偷懒的一招:PLL IP定义,无非是用Quartus II GUI对PLL参数的设定,最后生成pll.v这个文件。而这个文件相当于是锁相环的驱动电路,故势必包含着参数的定义。实际如下:
  altpll_component.clk0_divide_by = 1,
  altpll_component.clk0_duty_cycle = 50,
  altpll_component.clk0_multiply_by = 1,
  如上图所示,每次修改参数,这三个变量会相应的发生变化。因此,何不把这三个参数作为例化的参数,可以再顶层直接修改代码来实现固定频率的输出?这样岂不是很方便?
  因此设计参数例化接口如下:
  #(
  parameter DUTY_CYCLE = 50,
  parameter divIDE_DATA = 1,
  parameter MULTIPLY_DATA = 1
  )
  理论上是完全行得通的,这样设计的另一个好处就是电路的封装性更好Bingo实践证明,完全可行,因此在此处说明,要学会正确的偷懒呵呵。
  (4)Vga_design.v顶层文件代码解析
  a) Vga接口定义
  //vga interface
  output vga_adv_clk,
  output vga_blank_n,
  output vga_sync_n,
  output vga_hs,
  output vga_vs,
  output [15:0] vga_rgb
  如上所示,上面三个信号线是在使用adv712x视频转换芯片的时候才会出现,一般的电阻模拟电路,或者直接RGB3线驱动,可以直接删除相关信号以及电路。
  b) 进一步偷懒法则
  根据常用的几种分辨率,Bingo进行了总结,以下三种应用较多,因此进一步偷懒法则,围绕他们三者来(不在这三种以内的话,自己模仿着再写一个):
  VGA_640_480_60FPS_25MHz
  VGA_800_600_72FPS_50MHz
  VGA_1024_768_60FPS_65MHz
  Verilog语法也有define的用法,是否还记得C语言中,大工程的调试经常对相关变量的注释,注销来调整整个工程变量的应用,因此此处Bingo套用这种思维模式,定义以上三种模式的变量,通过修改注释define便可以轻松修改全局。具体如下所示:
  //----------------------------------------
  //vga parameter define
  //`define VGA_640_480_60FPS_25MHz
  //`define VGA_800_600_72FPS_50MHz
  `define VGA_1024_768_60FPS_65MHz
  `ifdef VGA_640_480_60FPS_25MHz
  parameter DUTY_CYCLE = 50;
  parameter divIDE_DATA = 2;
  parameter MULTIPLY_DATA = 1;
  parameter H_DISP = 11'd640;
  parameter H_FRONT = 11'd16;
  parameter H_SYNC = 11'd96;
  parameter H_BACK = 11'd48;
  parameter H_TOTAL = 11'd800;
  parameter V_DISP = 10'd480;
  parameter V_FRONT = 10'd10;
  parameter V_SYNC = 10'd2;
  parameter V_BACK = 10'd33;
  parameter V_TOTAL = 10'd525;
  `endif
  `ifdef VGA_800_600_72FPS_50MHz
  parameter DUTY_CYCLE = 50;
  parameter divIDE_DATA = 1;
  parameter MULTIPLY_DATA = 1;
  parameter H_DISP = 11'd800;
  parameter H_FRONT = 11'd56;
  parameter H_SYNC = 11'd120;
  parameter H_BACK = 11'd64;
  parameter H_TOTAL = 11'd1040;
  parameter V_DISP = 10'd600;
  parameter V_FRONT = 10'd37;
  parameter V_SYNC = 10'd6;
  parameter V_BACK = 10'd23;
  parameter V_TOTAL = 10'd666;
  `endif
  `ifdef VGA_1024_768_60FPS_65MHz
  parameter DUTY_CYCLE = 50;
  parameter divIDE_DATA = 10;
  parameter MULTIPLY_DATA = 13;
  parameter H_DISP = 11'd1024;
  parameter H_FRONT = 11'd24;
  parameter H_SYNC = 11'd136;
  parameter H_BACK = 11'd160;
  parameter H_TOTAL = 11'd1344;
  parameter V_DISP = 10'd768;
  parameter V_FRONT = 10'd3;
  parameter V_SYNC = 10'd6;
  parameter V_BACK = 10'd29;
  parameter V_TOTAL = 10'd806;
  `endif

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top