FPGA项目,进入FPGA与VGA的黑白棋盘世界

 本篇主要讨论基于FPGA的VGA驱动设计--第一版(全屏一个颜色、黑白棋盘)。

       VGA(Video Graphics Array)视频图形阵列是IBM公司于20世纪80年代提出的一个使用模拟信号的显示标准。

      VGA 接口有15 针孔,分成三排,每排五个针孔。其中比较重要的是3 根RGB(红绿蓝)彩色分量信号和2 根扫描同步信号HSYNC(水平同步信号)和VSYNC(垂直同步信号) 针。其母头插座引脚编号图如下图所示:

图片

图片

     三基色是指RGB三色,大多数的颜色可以通过RGB三色按照不同的比例合成产生。同样绝大多数单色光也可以分解成RGB三种色光。这是色度学的最基本原理,即三基色原理。RGB三基色按照不同的比例相加合成混色称为相加混色,除了相加混色法之外还有相减混色法。可根据需要相加相减调配颜色。

      VGA 接口中,表示颜色分量的只有红绿蓝三种基色。由于VGA 接口的三基色为模拟信号值,FPGA(FPGA为数字电路) 无法输出,所以在FPGA 的IO 到VGA 接口中间要有对应的数字量转模拟量的电路。

      有些板卡在设计时,利用电阻网络来完成数字量到模拟量的转换。

图片

       有些板卡在设计时,利用AD芯片来完成这个数字量到模拟量的转换。

图片

      图片在数字设备中,都是由像素点构成。

      像素是指由图像的小方格组成的,这些小方块都有一个明确的位置和被分配的色彩数值,小方格颜色和位置就决定该图像所呈现出来的样子。可以将像素视为整个图像中不可分割的单位或者是元素。不可分割的意思是它不能够再切割成更小单位,它是以一个单一颜色的小格存在。每一个点阵图像包含了一定量的像素,这些像素决定图像在屏幕上所呈现的大小。

      VGA 显示器上每一个像素点可以很多种颜色,由R、G、B 三种颜色构成。如果每个像素点采用3 位二进制数表示,即R 用1bit 表示,G 用1bit 表示,B 用1bit 表示,则此像素点一共可以显示8 中颜色;如果每个像素点采用16位二进制数表示,即R 用5bit 表示,G 用6bit 表示,B 用5bit 表示,则此像素点一共可以显示65536种颜色。

      笔者的本次设计采用RGB565的板卡、数字量转模拟量是采用电路网络。

      在VGA 显示器中,像素点RGB 的二进制数越多,能够表示的颜色就越多,此时,显示的图像就会越清晰。

      在VGA 显示器中,像素点的个数也是一个非常重要的一个指标。

      我们可以打开自己电脑的显示分辨率。

图片

      分频率有各种模式,但是基本都是固定好的。分辨率都是长乘宽,前面的数为长,后面的数为宽。长表示屏幕横向可以有多少个像素点;宽表示屏幕纵向可以用多少个像素点。一般来说屏幕都是扁平的,所以长一般都会比宽大。

      像素的多少不改变实际物理的尺寸大小,只是呈现的清晰度不同。可以对比500 万像素的相机拍的图片和2000 万像素的相机拍的图片,大小相同的情况下,清晰度是不同的。

       只要我们按照显示器能够支持的分辨率的长和宽,将对应的像素点传输给VGA 接口就可以了。但是VGA 协议中,要求进行传输像素点的同时,还需要去传输一部分的同步信号。

      显示器扫描方式分为逐行扫描和隔行扫描:逐行扫描是扫描从屏幕左上角一点开始,从左像右逐点扫描,每扫描完一行,电子束回到屏幕的左边下一行的起始位置,在这期间,每行结束时,用行同步信号进行同步;当扫描完所有的行,形成一帧,用场同步信号进行场同步,并使扫描回到屏幕左上方,开始下一帧。隔行扫描是指电子束扫描时每隔一行扫一线,完成一屏后在返回来扫描剩下的线,隔行扫描的显示器闪烁的厉害,会让使用者的眼睛疲劳。在此我们选择逐行扫描的方式。

图片

      VGA 的时序主要包括行时序与场时序两个部分。其中行时序主要包括:行同步(Hor Sync) 、行消隐(Hor Back Porch) 、行视频有效(Hor Active Video)和行前肩(Hor Front Porch)这四个参数,行时序的时序图如下图所示:

图片

      场时序主要包括:场同步(Ver Sync) 、场消隐(Ver BackPorch) 、场视频有效(Ver Active Video)和场前肩(Ver Front Porch)这四个参数,场时序的时序图如下图所示:

图片

需要注意的有三点:

1、行时序是以”像素”为单位的, 场时序是以”行”为单位的。

2、VGA 工业标准显示模式要求:行同步,场同步都为负极性,即同步脉冲要求是负脉冲。

3、VGA 行时序对行同步时间、 消隐时间、 行视频有效时间和行前肩时间有特定的规范, 场时序也是如此。 常用VGA 分辨率时序参数如下表所示:

图片

      本实验中选择640x480@60Hz。时钟的速率为25.175MHz,我们在设计时,时钟速率选择为25MHz 即可。

功能说明:

  1.   利用条件编译的方式,实现显示三基色(红、绿、蓝)以及黑白棋         盘。

  2.   选择分辨率为640x480@60Hz。

  3.   RGB为5:6:5,共计16bit。

  4.   黑白棋盘的小方块为边长为40像素。

使用平台:本次设计应用Altera的平台设计(芯片:EP4CE10F17C8N)。

仿真平台:Modelsim。

作者QQ:746833924

说明:本篇设计中涉及到ip电路(PLL),rtl代码在其他平台依然可以适用(需要调用其他平台的时钟管理单元);当其他板卡电路不同时,会导致不同的现象出现,如有需要修改代码请联系作者;如需作者使用的板卡,请联系作者;

设计思想如下:

图片

pll_vga模块是一个ip电路(PLL),负责利用外部的50MHz的时钟产生25MHz的时钟。

vga_ctrl模块产生vga同步时序,并且控制像素点的输出。

下图为在quaruts中,pll的配置界面。

图片

vga_ctrl模块设计思想如下:

条件编译说明如下:

需要显示那种模式,就把那个解注释,把其他三个注释掉。例:下图为显示全屏绿色。

//`define       RED`define       GREEN//`define       BLUE//`define       CHECKERBOARD

     当我们选择640x480@60Hz 的标准后,根据对应格式可以发现,此标准的一行为800 个像素值,共有525 行。也就是说并不是所有的像素值都可以显示出来,显示出来的只有中间的640 列和480 行,其他的像素值不显示(要求其他的像素值为黑色,即RGB 全部给0)。

      扫描方式为逐行扫描,从左上角开始。定义一个列坐标计数器(cnt_hs),每个驱动时钟周期加1,当一行结束后,计数器也同时清零。一行为800 个像素值,所以计数器将会在0 到799 无限循环。HSYNC 信号在此计数器的前96 的计数值拉低,其他时间拉高即可。

  always @ (posedge clk, negedge rst_n) begin    if (rst_n == 1'b0)      cnt_hs <= 10'd0;    else      if (cnt_hs < HS_E - 1'b1)        cnt_hs <= cnt_hs + 1'b1;      else        cnt_hs <= 10'd0;  end    always @ (posedge clk, negedge rst_n) begin    if (rst_n == 1'b0)      vga_hs <= 1'b1;    else      if (cnt_hs < HS_A)        vga_hs <= 1'b0;      else        vga_hs <= 1'b1;  end

       定义一个行坐标计数器(cnt_vs),扫描完一行后,进行加一,当一帧图片结束后,计数器清零。一行为800 个像素值,所以等cnt_hs 为799 时,cnt_vs 进行加一或者清零,由于一帧图片共有525 行,所以计数器在0 到524 之间无限循环。VSYNC 信号在此计数器的前两个计数器拉低,其他时间拉高即可。

  always @ (posedge clk, negedge rst_n) begin    if (rst_n == 1'b0)      cnt_vs <= 10'd0;    else      if (cnt_hs == HS_E - 1'b1)        if (cnt_vs < VS_E - 1'b1)          cnt_vs <= cnt_vs + 1'b1;        else          cnt_vs <= 10'd0;      else        cnt_vs <= cnt_vs;  end    always @ (posedge clk, negedge rst_n) begin    if (rst_n == 1'b0)      vga_vs <= 1'b1;    else      if (cnt_vs < VS_A)          vga_vs <= 1'b0;      else        vga_vs <= 1'b1;  end

根据cnt_hs 和cnt_vs,按照对应的标准,就可以得出显示的640 列和480 行的具体位置。

列显示的范围为:HS_A + HS_B + HS_C>cnt_hs>HS_A + HS_B - 1'b1.

行显示的范围为:VS_A + VS_B + VS_C>cnt_vs>VS_A + VS_B - 1'b1.

同时在两个有效显示区范围内,就可以显示出来。

 assign hs_en = (cnt_hs > HS_A + HS_B - 1'b1) && (cnt_hs < HS_A + HS_B + HS_C);
 assign vs_en = (cnt_vs > VS_A + VS_B - 1'b1) && (cnt_vs < VS_A + VS_B + VS_C);

`ifdef RED    always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      vga_rgb <= 16'd0;
    else  
      if (hs_en == 1'b1 && vs_en == 1'b1)
        vga_rgb <= 16'b11111_000000_00000;
      else
        vga_rgb <= 16'd0;
  end
`endif  
  
`ifdef GREEN  
  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      vga_rgb <= 16'd0;
    else  
      if (hs_en == 1'b1 && vs_en == 1'b1)
        vga_rgb <= 16'b00000_111111_00000;
      else
        vga_rgb <= 16'd0;
  end
`endif

`ifdef BLUE 
  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      vga_rgb <= 16'd0;
    else  
      if (hs_en == 1'b1 && vs_en == 1'b1)
        vga_rgb <= 16'b00000_000000_11111;
      else
        vga_rgb <= 16'd0;
  end
`endif

红色显示如下:

图片

绿色显示如下:

图片

有兴趣的小伙伴,可以自己调整rgb的输出值,例:红色和绿色分量都写1(16'b11111_111111_00000),看看是什么颜色。

棋盘显示的设计原理:

我们设计的棋盘为边长为40像素的方块,正好横着可以放下16个(640),竖着可以放下12行(480)。首先计算每一个方格的横纵坐标,然后将横纵坐标加起来,奇数显示白色,偶数显示黑色。这样正好是黑白棋盘。

图片

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值