【无标题】

基于FPGA的VGA协议实现


一、VGA概述

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

在这里插入图片描述

1.VGA接口

VGA接口共有15针,分成3排,每排5个孔,是显卡上应用最为广泛的接口类型,绝大多数显卡都带有此种接口。它传输红、绿、蓝模拟信号以及同步信号(水平和垂直信号),VGA引脚对应接口定义如下:

1.红基色 red (粉红色线)

2.绿基色 green(淡绿色线)

3.蓝基色blue(淡蓝色线)

4.地址码ID Bit(也有部分是RES,或者为ID2显示器标示位2)

5.自测试( 各家定义不同 )(一般为GND)(黑色线)

6.红地(4,6,7,8,11为屏蔽线,连接在一起)

7.绿地

8.蓝地

9.保留( 各家定义不同 )(黄色线)

10.数字地(红色线)

11.地址码(ID0显示器标示位0)

12.地址码(ID1显示器标示位1)(绿色线)

13.行同步(白色线)

14.场同步(棕色线)

15.地址码 ( ID3或显示器标示位3 )(橙色线)
在这里插入图片描述

2.色彩原理

由于人眼中的三种视锥细胞分别用来感知光中红色、绿色、蓝色的强度,而所有其他颜色都是按照这三种视锥细胞不同的刺激强度组合形成的,所以结合人眼的生物特性,通过 CIE XYZ 色彩空间的计算和定义,将波长为 700nm 的红色(Red)、波长为 546.1 nm 的绿色(Green)以及波长为 435.8 nm 的蓝色(Blue)作为色光三原色引入色彩体系中。

所以以色光三原色为基础构建的色彩模型就被称为 RGB 色彩模型,同时它属于光的加色模式,因为其他颜色都是由三原色光叠加而形成,当三原色一起叠加的时候,就形成了白色。
在这里插入图片描述

设计RGB信号时,既可以R信号、G信号和B信号独⽴的赋值,最后连到端⼝上,也可以直接⽤RGB当做⼀个整体信号,RGB信号在使
⽤时的位宽有三种常见格式,以你的VGA解码芯⽚的配置有关。

  1. RGB_8,R:G:B = 3:3:2,即RGB332
  2. RGB_16,R:G:B = 5:6:5,即RGB565
  3. RGB_24,R:G:B = 8:8:8,即RGB888

3.扫描方式


GA显⽰器扫描⽅式分为逐⾏扫描和隔⾏扫描:逐⾏扫描是扫描从屏幕左上⾓⼀点开始,从左像右逐点扫描,每扫描完⼀⾏,电⼦束回 到屏幕的左边下⼀⾏的起始位置,在这期间,CRT对电⼦束进⾏消隐,每⾏结束时,⽤⾏同步信号进⾏同步;当扫描完所有的⾏,形成⼀ 帧,⽤场同步信号进⾏场同步,并使扫描回到屏幕左上⽅,同时进⾏场消隐,开始下⼀帧。隔⾏扫描是指电⼦束扫描时每隔⼀⾏扫⼀线,完成

⼀屏后在返回来扫描剩下的线,隔⾏扫描的显⽰器闪烁的厉害,会让使⽤者的眼睛疲劳。因此我们⼀般都采⽤逐⾏扫描的⽅式。

扫描原理如下所⽰
在这里插入图片描述

4.行场信号


在这里插入图片描述

⼀开始看这个时序图可能看不懂,它是把⾏场信号绘制在同⼀张图⾥,说明⾏场信号的控制是相似的,只是时间参数不⼀样⽽已。如果展开的话,其实时序是这样的:
在这里插入图片描述

若⼲个HS信号才组合⽽成⼀个VS,如果在⼀副图⽚中,那正确的时序表⽰⽅式应该如下图这样:
在这里插入图片描述

SYNC是“信号同步”,Back proch和Left border常常加在⼀起称为“显⽰后沿”,Addressable video为“显⽰区域”,Right porder和Front porch常常加在⼀起称为“显⽰前沿”,⼀个时序其实就是先拉⾼⼀段较短的“信号同步”时间,然后拉低⼀段很长的时间,这就是⼀个回合。同时需要注意,其实也可以完全相反。即先拉低⼀段时间“信号同步”时间,然后拉⾼⼀段很长的时间。

二、显示彩条和字符


生成点阵字模

代码:
参数:

`define vga_640_480
//`define vga_800_600

`ifdef vga_640_480
    `define  h_right_border  8
    `define  h_front_porch   8
    `define  h_sync_time     96
    `define  h_back_porch    40
    `define  h_left_border   8
    `define  h_data_time     640
    `define  h_total_time    800

    `define  v_bottom_border 8
    `define  v_front_porch   2
    `define  v_sync_time     2
    `define  v_back_porch    25
    `define  v_top_border    8
    `define  v_data_time     480
    `define  v_total_time    525
`elsif vga_1280_720
    `define  h_right_border  0
    `define  h_front_porch   110
    `define  h_sync_time     40
    `define  h_back_porch    220
    `define  h_left_border   0
    `define  h_data_time     1280
    `define  h_total_time    1650

    `define  v_bottom_border 0
    `define  v_front_porch   5
    `define  v_sync_time     5
    `define  v_back_porch    20
    `define  v_top_border    0
    `define  v_data_time     720
    `define  v_total_time    750
`elsif vga_1920_1080
    `define  h_right_border  0
    `define  h_front_porch   88
    `define  h_sync_time     44
    `define  h_back_porch    148
    `define  h_left_border   0
    `define  h_data_time     1920
    `define  h_total_time    2200

    `define  v_bottom_border 0
    `define  v_front_porch   4
    `define  v_sync_time     5
    `define  v_back_porch    36
    `define  v_top_border    0
    `define  v_data_time     1080
    `define  v_total_time    1125
`elsif vga_800_600
    `define  h_right_border  0
    `define  h_front_porch   40
    `define  h_sync_time     128
    `define  h_back_porch    88
    `define  h_left_border   0
    `define  h_data_time     800
    `define  h_total_time    1056

    `define  v_bottom_border 0
    `define  v_front_porch   1
    `define  v_sync_time     4
    `define  v_back_porch    23
    `define  v_top_border    0
    `define  v_data_time     600
    `define  v_total_time    628
`endif 

VGA驱动:

`include "vga_par.v" 

module vga_ctrl(
    input   wire                  clk         ,//VGA时钟25.2MHz
    input   wire                  rst_n       ,//复位信号
    input   wire [23:00]          data_dis    ,//

    output  reg [10:00]           h_addr      ,//数据有效显示区域行地址
    output  reg [10:00]           v_addr      ,//数据有效显示区域场地址

    output  reg                   hsync       ,//
    output  reg                   vsync       ,//

    output  reg  [07:00]          vga_r       ,//
    output  reg  [07:00]          vga_g       ,//
    output  reg  [07:00]          vga_b       , //
    output  reg                   vga_blk     ,//vga消隐信号
    output  wire                  vga_clk      //
);

//参数定义
    
    parameter  h_sync_sta =  1,
               h_sync_sto = `h_sync_time,
               h_data_sta = `h_left_border  + `h_front_porch +`h_sync_time,
               h_data_sto = `h_left_border  + `h_front_porch +`h_sync_time + `h_data_time,

               v_sync_sta = 1,
               v_sync_sto = `v_sync_time,
               v_data_sta = `v_top_border + `v_back_porch +`v_sync_time,
               v_data_sto = `v_top_border + `v_back_porch +`v_sync_time + `v_data_time;

//信号定义
    reg     [11:0]  cnt_h_addr;//行地址计数器
    wire            add_h_addr;
    wire            end_h_addr;

    reg     [11:0]  cnt_v_addr;//场地址计数器
    wire            add_v_addr;
    wire            end_v_addr;
//
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            cnt_h_addr <= 12'd0;
        end
        else if (add_h_addr) begin
            if (end_h_addr) begin
                cnt_h_addr <= 12'd0;
            end
            else begin
                cnt_h_addr <= cnt_h_addr + 12'd1;
            end
        end
        else begin
          cnt_h_addr <= cnt_h_addr;
        end
    end

    assign add_h_addr = 1'b1;
    assign end_h_addr = add_h_addr && cnt_h_addr >= `h_total_time - 1;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            cnt_v_addr <= 12'd0;
        end
        else if (add_v_addr) begin
            if (end_v_addr) begin
                cnt_v_addr <= 12'd0;
            end
            else begin
                cnt_v_addr <= cnt_v_addr + 12'd1;
            end
        end
        else begin
          cnt_v_addr <= cnt_v_addr;
        end
    end

    assign add_v_addr = end_h_addr;
    assign end_v_addr = add_v_addr && cnt_v_addr >= `v_total_time - 1;

    //行场同步信号
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            hsync <= 1'b1;
        end
        else if(cnt_h_addr == h_sync_sta -1) begin  
            hsync <= 1'd0;
        end
        else if(cnt_h_addr == h_sync_sto -1)begin
            hsync <= 1'b1;
        end
        else begin
            hsync <= hsync;
        end
    end

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            vsync <= 1'b1;
        end
        else if(cnt_v_addr == v_sync_sta -1) begin  
            vsync <= 1'd0;
        end
        else if(cnt_v_addr == v_sync_sto -1)begin
            vsync <= 1'b1;
        end
        else begin
            vsync <= vsync;
        end
    end

    assign vga_clk = ~clk;

    //数据有效显示区域定义
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            h_addr <= 11'd0;
        end
        else if((cnt_h_addr >= h_data_sta ) && (cnt_h_addr <= h_data_sto) )begin
            h_addr <= cnt_h_addr - h_data_sta;
        end
        else begin
            h_addr <= 11'd0;
        end
    end

   always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            v_addr <= 11'd0;
        end
        else if((cnt_v_addr >= v_data_sta ) && (cnt_v_addr <= v_data_sto))begin
            v_addr <= cnt_v_addr - v_data_sta;
        end
        else begin
            v_addr <= 11'd0;
        end
    end

    //显示数据
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            vga_r   <= 8'd0;
            vga_g   <= 8'd0;
            vga_b   <= 8'd0;
            vga_blk <= 1'b0;
        end
        else if((cnt_h_addr >= h_data_sta -1    ) 
            &&  (cnt_h_addr <= h_data_sto -1    ) 
            &&  (cnt_v_addr >= v_data_sta -1    ) 
            &&  (cnt_v_addr <= v_data_sto -1    ))begin
            vga_r <= data_dis[23-:08];
            vga_g <= data_dis[15-:08];
            vga_b <= data_dis[07-:08];
           vga_blk <= 1'b1;

        end
        else begin
            vga_r <= 8'd0;
            vga_g <= 8'd0;
            vga_b <= 8'd0;
            vga_blk <= 1'b0;
        end
    end

    //assign sync = 1'b0;
endmodule

顶层文件:

module vga_top(
    input   wire                    clk         ,
    input   wire                    rst_n       ,
    output  wire                    hsync       ,//
    output  wire                    vsync       ,
    output  wire  [07:00]           vga_r       ,//
    output  wire  [07:00]           vga_g       ,//
    output  wire  [07:00]           vga_b       ,//
    output  wire                    vga_blk     ,
    output  wire                    vga_clk      //
);

wire [10:00]          h_addr      ;
wire [10:00]          v_addr      ;
wire [23:00]          data_dis    ;

pll1	pll1_inst (
	.areset ( ~rst_n ),
	.inclk0 ( clk ),
	.c0 ( vga_clk ),
	.c1 ( clk1 )
	);

data_gen u_data_gen(
    .clk         (vga_clk  ),//VGA时钟25.2MHz
    .rst_n       (rst_n    ),//复位信号
    .h_addr      (h_addr   ),//数据有效显示区域行地址
    .v_addr      (v_addr   ),//数据有效显示区域场地址
    .vga_blk     (vga_blk  ),
    .data_dis    (data_dis )//
);

vga_ctrl u_vga_ctrl(
    .clk         (vga_clk  ),//VGA时钟25.2MHz
    .rst_n       (rst_n    ),//复位信号
    .data_dis    (data_dis ),//
    .h_addr      (h_addr   ),//数据有效显示区域行地址
    .v_addr      (v_addr   ),//数据有效显示区域场地址
    .hsync       (hsync    ),//
    .vsync       (vsync    ),//
    .vga_r       (vga_r    ),//
    .vga_g       (vga_g    ),//
    .vga_b       (vga_b    ), //
    .vga_blk     (vga_blk  )
);
endmodule

1.彩条


module data_gen(
    input   wire                  clk         ,//VGA时钟25.2MHz
    input   wire                  rst_n       ,//复位信号
    input   wire [10:00]          h_addr      ,//数据有效显示区域行地址
    input   wire [10:00]          v_addr      ,//数据有效显示区域场地址
    input   wire                  vga_blk     ,

    output  reg [23:00]           data_dis     //
);
    parameter 
        BLACK       = 24'H000000,
        RED         = 24'HFF0000,
        GREEN       = 24'H00FF00,
        BLUE        = 24'H0000FF,
        YELLOW      = 24'HFFFF00,
        SKY_BULE    = 24'H00FFFF,
        PURPLE      = 24'HFF00FF,
        GRAY        = 24'HC0C0C0,
        WHITE       = 24'HFFFFFF;
    parameter 
        h_vld       = 640,
        v_vld       = 480,

        pic_w       =272,
        pic_h       =16,

        x_start     =   (h_vld - pic_w >>1 ) -1,
        y_start     =   (v_vld - pic_h >>1 ) -1;
    reg [10:00] pix_x,pix_y;
    reg [ 271:0 ] char_line[ 15:0 ];   //272*16
    reg [15:00]     rom_address;

//彩条
always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            data_dis <= WHITE; 
        end
        else  begin
            case (h_addr)
                0       :   data_dis <= BLACK   ;
                80      :   data_dis <= RED     ;
                160     :   data_dis <= GREEN   ;    
                240     :   data_dis <= BLUE    ;    
                320     :   data_dis <= YELLOW  ;    
                400     :   data_dis <= SKY_BULE;        
                480     :   data_dis <= PURPLE  ;    
                560     :   data_dis <= GRAY    ;    
                default :   data_dis <= data_dis;        
            endcase
        end
    end
endmodule


2.点阵输出


//初始化显示文字
always@( posedge clk or negedge rst_n ) begin
    if ( !rst_n ) begin
      char_line[ 0 ]  = 272'h00000000000000000000000000000000000000000000000010004000;
      char_line[ 1 ]  = 272'h00000000000000000000000000000000000000000000000011f84dfe;
      char_line[ 2 ]  = 272'h00000000000000000000000000000000000000000000000010107020;
      char_line[ 3 ]  = 272'h18003c000800380018007e0018001800180008003c00180010204440;
      char_line[ 4 ]  = 272'h240042003800440024004200240024002400380042002400fc4045fc;
      char_line[ 5 ]  = 272'h40004200080042004200040042004000420008004200400010803d04;
      char_line[ 6 ]  = 272'h40000200080042004200040042004000420008004200400031fe0124;
      char_line[ 7 ]  = 272'h5c000400080042004200080042005c004200080002005c0038920d24;
      char_line[ 8 ]  = 272'h62001800080046004200080042006200420008000400620054927124;
      char_line[ 9 ]  = 272'h4200040008003a004200100042004200420008000800420054921124;
      char_line[ 10 ] = 272'h4200020008000200420010004200420042000800100042009112ff24;
      char_line[ 11 ] = 272'h42004200080002004200100042004200420008002000420011221144;
      char_line[ 12 ] = 272'h22004200080024002400100024002200240008004200220012223850;
      char_line[ 13 ] = 272'h1c003c003e0018001800100018001c0018003e007e001c0014425488;
      char_line[ 14 ] = 272'h00000000000000000000000000000000000000000000000010949104;
      char_line[ 15 ] = 272'h00000000000000000000000000000000000000000000000011081202;
    end
end

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        pix_x <= 11'd0;
        pix_y <= 11'd0;
    end
    else if ((h_addr >= x_start && h_addr < x_start +pic_w)
           &&(v_addr >= y_start && v_addr < y_start + pic_h)) begin
        pix_x <= h_addr - x_start;
        pix_y <= v_addr - y_start;
    end
    else begin
        pix_x <= 11'h7ff;
        pix_y <= 11'h7ff;
    end
end

always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            data_dis <= BLACK; 
        end
        else if (pix_x != 11'h7FF && pix_y != 11'h7FF) begin
            if(char_line[pix_y][271 - pix_x]== 1'b1)begin
                data_dis <= WHITE;
            end
            else begin
                data_dis <= BLUE;
            end
        end 
        else begin
        data_dis <= data_dis;
        end
end


三、实现效果

1.引脚


使用的是EP4CE115F29C7开发板
在这里插入图片描述

2.结果


在这里插入图片描述

修改分辨率为800*600 时钟改为40MHz:

在这里插入图片描述

可以看到图形整体左移

汉字点阵:
请添加图片描述

四、总结


通过这次作业了解了VGA协议,实现了屏幕显示彩色条纹和字符,过程的实现很有意思。

五、参考链接


协议——VGA

FPGA零基础学习:VGA协议驱动设计

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值