【FPGA】VGA彩条显示-FPGA常见问题社区-FPGA CPLD-ChipDebug

【FPGA】VGA彩条显示


前言

        随着社会的飞速发展,很多电子设备为了方便观察性能和实现更多的功能,都会为其配备一块显示屏,这也促进了显示设备的发展与迭代。到现在为止,图像显示技术的发展已经非常完善了,但在大型图像处理速度上还有提升的空间,还得去研究创造。

FPGA在图像显示领域的应用也十分的广泛,其中的一些视频传输接口便是FPGA与显示设备连接的桥梁,常见的图像传输接口有VGA接口、HDMI接口、DVI接口、DP接口等,本次实验我们就来简单地讲解一下VGA接口的功能与实现,对其他接口感兴趣的小伙伴们可以自行去了解,这里就不过多赘述了。


一、VGA简介

        VGA的全称是Video Graphics Array,即视频图形阵列,是一个使用模拟信号进行视频传输的标准。VGA在1987年被IBM公司推出以来,因其具有分辨率高、显示速度快、显示色彩丰富等优点,在彩色显示器领域得到了广泛的应用。

图片[1]-【FPGA】VGA彩条显示-FPGA常见问题社区-FPGA CPLD-ChipDebug

         如图所示就是VGA接口,由两部分组成,其中小孔的部分叫做母口,另一个叫做公口。由于接口体积较大的原因,现在我们的笔记本上已经逐渐淘汰掉了这种接口,但在我们的台式机显示器上,仍然有许多显示器在使用VGA接口进行图像的传输显示。

VGA接口定义及各引脚功能说明如下图所示,我们一般只用到其中的1(RED)、2(GREEN)、3(BLUE)、13(HSYNC)、14(VSYNC)信号。引脚1、2、3分别输出红、绿、蓝三原色模拟信号,电压变化范围为0~0.714V,0V表示无色,0.714V代表满色;引脚13、14输出TTL电平标准的行/场同步信号,其他引脚功能见下图。

图片[2]-【FPGA】VGA彩条显示-FPGA常见问题社区-FPGA CPLD-ChipDebug

         在VGA视频传输标准中,视频图像被分解成红、绿、蓝三原色信号,经过数模转换后,在行同步和场同步信号的同步下分别在三个独立的通道内传输。行/场同步信号时序如下图所示:

图片[3]-【FPGA】VGA彩条显示-FPGA常见问题社区-FPGA CPLD-ChipDebug

图片[4]-【FPGA】VGA彩条显示-FPGA常见问题社区-FPGA CPLD-ChipDebug

图片[5]-【FPGA】VGA彩条显示-FPGA常见问题社区-FPGA CPLD-ChipDebug

         在有了行同步信号和场同步信号的时序图以后,根据不同的时序参数,我们就可以来设计VGA显示的项目工程了。


二、VGA彩条显示实验

1、实验任务

        在经过前面对VGA工作原理的学习以后,这里我们就按照VGA的时序来完成彩条显示的实验设计,要求如下:

分辨率:640*480@60

在显示器上显示等宽的红、橙、黄、绿、青、蓝、紫、黑、白、灰彩条。

2、程序设计

① vga顶层模块:

/*====================================*
    filename    : vga_colorbar_top.v
    description : VGA彩条显示顶层模块
    time        : 2022-12-29
    author      : 卡夫卡与海
*=====================================*/
 
module vga_colorbar_top(
    input           clk        ,//系统时钟
    input           rst_n      ,//复位
 
    output          vga_hsync ,//行同步信号
    output          vga_vsync ,//场同步信号
    output  [15:0]  vga_rgb    //数据输出(红绿蓝)
);
 
//信号定义
wire          vga_clk   ;//vga工作时钟  25MHZ
wire          locked    ;
wire          vga_reset ;
wire   [9:0]  pix_x     ;
wire   [9:0]  pix_y     ;
wire   [15:0] pix_data  ;
 
assign vga_reset = rst_n && locked;
 
//模块例化
//PLL
CLK_PLL	CLK_PLL_inst (
	.areset    (~rst_n ),
	.inclk0    (clk    ),
	.c0        (vga_clk),
	.locked    (locked )
);
 
//vga控制模块
vga_control u_vga_control(
    /*input            */.clk_25     (vga_clk  ),//时钟  25MHZ
    /*input            */.rst_n      (vga_reset),//复位
    /*input   [15:0]   */.pix_data   (pix_data ),//输入图像数据
    /*output  [9:0]    */.pix_x      (pix_x    ),//横坐标
    /*output  [9:0]    */.pix_y      (pix_y    ),//纵坐标
    /*output           */.hsync      (vga_hsync),//行同步信号
    /*output           */.vsync      (vga_vsync),//场同步信号
    /*output  [15:0]   */.vga_rgb    (vga_rgb  ) //输出图像数据(RGB565格式)
);
 
//vga显示模块
vga_display u_vga_display(
    /*input             */.clk_25    (vga_clk  ),//VGA驱动时钟
    /*input             */.rst_n     (vga_reset),//复位
    /*input      [9:0]  */.pix_x     (pix_x    ),//横坐标
    /*input      [9:0]  */.pix_y     (pix_y    ),//纵坐标
    /*output reg [15:0] */.pix_data  (pix_data ) //数据
);
 
 
endmodule

② vga控制模块:

/*===============================*
    filename    : vga_control.v
    description : VGA控制模块
    time        : 2022-12-28
    author      : 卡夫卡与海
*================================*/
 
module vga_control(
    input            clk_25    ,//时钟  25MHZ
    input            rst_n     ,//复位
 
    input   [15:0]   pix_data  ,//输入图像数据
 
    output  [9:0]    pix_x     ,//横坐标
    output  [9:0]    pix_y     ,//纵坐标
    output           hsync     ,//行同步信号
    output           vsync     ,//场同步信号
    output  [15:0]   vga_rgb    //输出图像数据(RGB565格式)
);
//参数定义
//显示模式:640*480@60
parameter   H_SYNC   = 96 ,//行同步
            H_BACK   = 48 ,//行显示后沿
            H_DISP   = 640,//行有效数据
            H_FRONT  = 16 ,//行显示前沿
            H_TOTAL  = 800;//行扫描周期
 
parameter   V_SYNC   = 2  ,//场同步
            V_BACK   = 33 ,//场显示后沿
            V_DISP   = 480,//场有效数据
            V_FRONT  = 10 ,//场显示前沿
            V_TOTAL  = 525;//场扫描周期
 
//信号定义
reg    [9:0]    cnt_h     ;//行计数器
reg    [9:0]    cnt_v     ;//场计数器
 
wire             rgb_vaild ;//数据有效信号
wire             data_req  ;//数据请求信号
 
//cnt_h
always @(posedge clk_25 or negedge rst_n)begin
    if(!rst_n)begin
        cnt_h <= 10'd0;
    end
    else begin
        if(cnt_h < H_TOTAL - 1)begin
            cnt_h <= cnt_h + 1'b1;
        end
        else begin
            cnt_h <= 10'd0;
        end
    end
end
//cnt_v
always @(posedge clk_25 or negedge rst_n)begin
    if(!rst_n)begin
        cnt_v <= 10'd0;
    end
    else if(cnt_h == H_TOTAL - 1)begin
        if(cnt_v < V_TOTAL - 1)begin
            cnt_v <= cnt_v + 1'b1;
        end
        else begin
            cnt_v <= 10'd0;
        end
    end
end
 
//rgb_vaild  数据输出有效信号
assign rgb_vaild = ((cnt_h >= H_BACK + H_SYNC)
                    &&(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;
 
//data_req 像素点颜色数据输入请求信号
assign data_req = (((cnt_h >= H_SYNC + H_BACK - 1)
                    && (cnt_h < H_SYNC + H_BACK + H_DISP - 1))
                    && ((cnt_v >= V_SYNC + V_BACK)
                    && (cnt_v < V_SYNC + V_BACK + V_DISP)))
                    ? 1'b1 : 1'b0;
 
//输出
//pix_x  横坐标
assign pix_x = (data_req==1'b1)?(cnt_h - (H_SYNC+H_BACK-1)):10'h3ff;
 
//pix_y  纵坐标
assign pix_y = (data_req==1'b1)?(cnt_v - (V_SYNC+V_BACK-1)):10'h3ff;
 
//hsync  
assign hsync = (cnt_h <= H_SYNC - 1) ? 1'b0 : 1'b1;
 
//vsync  
assign vsync = (cnt_v <= V_SYNC - 1) ? 1'b0 : 1'b1;
 
//vga_rgb
assign vga_rgb = (rgb_vaild == 1'b1) ? pix_data : 16'd0;
 
 
endmodule

  ③ vga显示模块:

/*===============================*
    filename    : vga_display.v
    description : VGA显示模块
    time        : 2022-12-29
    author      : 卡夫卡与海
*================================*/
 
module vga_display(
    input             clk_25  ,//VGA驱动时钟
    input             rst_n   ,//复位
 
    input      [9:0]  pix_x   ,//横坐标
    input      [9:0]  pix_y   ,//纵坐标
    output reg [15:0] pix_data //数据
);
//参数定义
parameter   H_DISP = 10'd640,//分辨率一行
            V_DISP = 10'd480;//分辨率一列
 
//颜色参数  RGB565格式
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;//灰
 
always @(posedge clk_25 or negedge rst_n)begin
    if(!rst_n)begin
        pix_data <= BLACK;
    end
    else if(pix_x >= 0 && pix_x <((H_DISP/10) * 1))begin
        pix_data <= RED;//红
    end
    else if(pix_x >= ((H_DISP/10) * 1) && pix_x <((H_DISP/10) * 2))begin
        pix_data <= ORANGE;//橙
    end
    else if(pix_x >= ((H_DISP/10) * 2) && pix_x <((H_DISP/10) * 3))begin
        pix_data <= YELLOW;//黄
    end
    else if(pix_x >= ((H_DISP/10) * 3) && pix_x <((H_DISP/10) * 4))begin
        pix_data <= GREEN;//绿
    end
    else if(pix_x >= ((H_DISP/10) * 4) && pix_x <((H_DISP/10) * 5))begin
        pix_data <= CYAN;//青
    end
    else if(pix_x >= ((H_DISP/10) * 5) && pix_x <((H_DISP/10) * 6))begin
        pix_data <= BLUE;//蓝
    end
    else if(pix_x >= ((H_DISP/10) * 6) && pix_x <((H_DISP/10) * 7))begin
        pix_data <= PURPPLE;//紫
    end
    else if(pix_x >= ((H_DISP/10) * 7) && pix_x <((H_DISP/10) * 8))begin
        pix_data <= BLACK;//黑
    end
    else if(pix_x >= ((H_DISP/10) * 8) && pix_x <((H_DISP/10) * 9))begin
        pix_data <= WHITE;//白
    end
    else if(pix_x >= ((H_DISP/10) * 9) && pix_x < H_DISP)begin
        pix_data <= GRAY;//灰
    end
    else begin
        pix_data <= BLACK;
    end
end
 
 
endmodule

④ vga仿真模块:

/*==================================*
    filename    : vga_top_tb.v
    description : VGA顶层模块仿真
    time        : 2022-12-28
    author      : 卡夫卡与海
*===================================*/
`timescale 1ns/1ns 
 
module vga_top_tb();
    reg           clk      ;//50MHZ
    reg           rst_n    ;
 
    wire          hsync    ;
    wire          vsync    ;
    wire  [15:0]  vga_rgb  ;
 
//产生时钟、复位
initial begin
    clk = 1'b1;
    rst_n = 1'b0;
    #20
    rst_n = 1'b1;
end
always #10 clk = ~clk;
//模块例化
vga_colorbar_top u_vga_colorbar_top(
    /*input           */.clk        (clk    ),//系统时钟
    /*input           */.rst_n      (rst_n  ),//复位
    /*output          */.vga_hsync  (hsync  ),//行同步信号
    /*output          */.vga_vsync  (vsync  ),//场同步信号
    /*output  [15:0]  */.vga_rgb    (vga_rgb) //数据输出(红绿蓝)
);
endmodule

注:

在VGA顶层模块中有一个PLL的IP核,这是因为我们板子的晶振时钟是50MHZ,而我们VGA需要的时钟是25MHZ,这里就调用了一个锁相环IP核。当然,这里的时钟分频也可以用代码来实现,只不过调用IP核快一点罢了。

⑤ 板极验证:

图片[6]-【FPGA】VGA彩条显示-FPGA常见问题社区-FPGA CPLD-ChipDebug

         板极验证效果如上图所示,屏幕上显示等宽的红、橙、黄、绿、青、蓝、紫、黑、白、灰共10跟彩条,说明上板验证成功。


总结

        VGA接口的逻辑还是比较简单的,主要是要弄清楚它的显示时序以及那些参数设置,不然图像显示出来是不对的。我们这次是用的RGB565的格式进行显示的,除此之外还有RGB332,RGB888等显示格式,通道数越多,说明可以显示的色彩越丰富。

除了进行彩条显示之外,还可以尝试着去利用VGA接口显示文字、表情包等其它图像,大概的操作就是将图像数据存储到ROM中,然后从ROM中取出数据赋值给相应的RGB通道就可以了,感兴趣的可以去尝试一下!!!

请登录后发表评论

    没有回复内容