FPGA学习笔记1——VGA显示

VGA显示实验

VGA时序主要包括两条信号线(HS,VS)的输出——行扫描和场扫描。VGA采用逐行扫描,每个像素对应的点扫描。行与行之间存在消隐以及显示时期,场与场之间也类似。行扫描可分为以下几个阶段:同步、消隐后肩、显示期、消隐前肩再到下个周期同步为一个循环,对应的是屏幕上的一行。场同步类似,对应为屏幕显示的一帧。标准的VGA屏幕比例为4:3(笔者找了好久没找到16:9的显示周期),有固定的帧率以及扫描场频率的标准。


在此科普一下帧率的概念,因为在显示动态图像的时候,实际屏幕都是一张图一张图地切换显示,帧率对应的就是每秒图片的刷新频率。一般当帧率小于30fps的时候能感觉到画面卡顿。


网上找的VGA常见刷新时序表:
FPGA学习笔记1——VGA显示_第1张图片

网上找的行场时序图:
FPGA学习笔记1——VGA显示_第2张图片


本次实现的平台是 ALTERA 的DE2-115,板上搭载ADV7123芯片,RGB24bit输出给DAC视频转换芯片,实现一个黄蓝绿的三色的显示。

根据上表的VGA刷新表定好本地参数,此处采用 VGA_800*600_60fps_40MHz:

#(parameter H_DISP =10'd800,//分辨率
      parameter V_DISP =10'd600,
      parameter H_SYNC=10'd128,//行同步
      parameter H_BACK=10'd88,//行消隐后肩
      parameter H_FRONT=10'd40,//行消隐前肩
      parameter H_TOTAL=11'd1056,//行总周期
      parameter V_SYNC=10'd4,//场同步
      parameter V_BACK=10'd23,//场消隐后肩
      parameter V_FRONT=10'd1,//场消隐前肩
      parameter V_TOTAL=10'd628)//场总周期

接下来进行行场扫描时序的实现,vcnt为场计数器,hcnt为行计数器

//行扫描
    always@(posedge vga_clk or negedge rst_n)begin
        if(!rst_n)begin
            hcnt<=0;
            vga_hs<=1;
            vga_blank_n<=1;
            vga_syns_n<=0;
        end
        else begin
            hcnt<=hcnt+1;
            if(hcnt0;
            else if(hcnt1;
            else if(hcntbegin
                vga_hs<=1;//显示数据时间段
            end
            else if(hcntbegin
                vga_hs<=1;
            end
            else begin  
                hcnt<=0;
            end
        end
    end

    //场扫描
    always@(posedge vga_clk or negedge rst_n)begin
        if(!rst_n)begin
            vcnt<=0;
            vga_vs<=1;
        end
        else begin
            if(hcnt==(H_SYNC+H_DISP+H_BACK+H_FRONT)) vcnt<=vcnt+1;
            if(vcnt0;
            else if(vcnt1;
            else if(vcntbegin
                vga_vs<=1;//显示数据时间段
            end
            else if(vcntbegin 
                vga_vs<=1;
            end
            else begin  
                vcnt<=0;
            end
        end
    end

为了更直观的显示图像在显示器的坐标,对坐标x和y进行了定义:


assign x=(hcnt>H_SYNC+H_BACK-1'b1)&&(hcnt1'b1):32'd0;//(1~800) screen x coordinate
assign y=(vcnt>V_SYNC+V_BACK-1'b1)&&(vcnt1'b1):32'd0;//(1~600) screen y coordinate

最后根据坐标的值,给屏幕像素RGB颜色:

//输入图像像素
        always@(posedge vga_clk or negedge rst_n)begin
            if(!rst_n)begin
            vga_R<=0;
            vga_G<=0;
            vga_B<=0;
            end
            else begin
                if(x==0)begin
                    vga_R<=0;
                    vga_G<=0;
                    vga_B<=0;
                end
                else if(x3)begin//黄色
                    vga_R<=8'd255;
                    vga_G<=8'd255;
                    vga_B<=8'd0;
                end
                else if(x2/3)begin//蓝色
                    vga_R<=8'd0;
                    vga_G<=8'd255;
                    vga_B<=8'd255;
                end
                else begin//绿色
                    vga_R<=8'd0;
                    vga_G<=8'd255;
                    vga_B<=8'd0;
                end
            end
       end

用手机拍的屏幕的照片:
FPGA学习笔记1——VGA显示_第3张图片


实现过程注意的要点:
1、使用pll产生固定的频率,用计数器按照上表对每个时间段进行计数,完成时序
2、现在使用的宽屏显示器一般带有自动调节的功能,所以先把显示器设置成不要拉成宽屏。笔者在实现的过程中,发现在宽屏自动拉伸图像会往右偏移,在x和y坐标去除消隐后肩后显示正常。实际上在标准的4:3显示器图像这样设置会出现偏移的情况,加上消隐后肩后显示正常。

你可能感兴趣的:(FPGA学习笔记)