FPGA中级项目6——VGA 2part

FPGA中级项目6------VGA 2part

VGA板级验证

在上篇文章中,我们讲解了VGA的Verilog设计与显示原理。

这次的第一个任务便是进行VGA的板级验证 ,主要是验证以下三个方面:
1. 能够正确的全屏点亮,显示稳定
2. 能否正确的显示颜色,也就是按照用户需求来实现需要显示的目标颜色(赤橙黄绿青蓝紫)
**3.**能否正确的定位坐标,也就是在对应的屏幕位置显示对应的数据


同样为了更好的显示验证效果,我们创建Verilog代码来实行。

其中必须要事先说明的是;RGB三色分量可以组成不同的颜色,当某一个分量全满或全0,可以组成相应的8种颜色。例如:R分量和B分量全满,G分量全0时,便构成了紫色。相应代码表示为24'hFF00FF。

其次要分割相应区域,来定义不同的颜色像素点坐标范围 ,如下所示,然后将相应区域上显示想要显示颜色即可。

在实际的FPGA开发板上的VGA测试文件代码如下:

复制代码
//定义输入输出端口
module VGA_TEXT(
        clk_50M,
        reset_n,
        VGA_HS,//行同步信号
        VGA_VS,//场同步信号
        VGA_BLK,//数据输出时间段
        VGA_CLK,
        data_out
    );
        input clk_50M;
        input reset_n;
        output VGA_HS;
        output VGA_VS;
        output VGA_BLK;
        output VGA_CLK;
        output [23:0]data_out;
 
        
//定义相关信号        
        reg [23:0]data_in;
        wire locked;
        wire clk;
        wire [11:0]hcount;
        wire [11:0]vcount;
 
        
//定义计数器counter0
        reg [31:0]counter0;
always@(posedge clk_50M or negedge reset_n)
if(!reset_n)
        counter0 <= 0;
else if(counter0 == 99_999_999)
        counter0 <= 0;
else
        counter0 <= counter0 + 1'd1;
        
        
//定义使能信号
        reg en;
always@(posedge clk_50M or negedge reset_n)
if(!reset_n)
        en <= 0;
else if(counter0 >= 49_999_999)
        en <= 1;
else
        en <= 0;
                        
//定义颜色代码
localparam   black = 24'h000000,
             blue = 24'h0000FF,
             red = 24'hFF0000,
             purpple = 24'hFF00FF,
             green = 24'h00FF00,
             cyan = 24'h00FFFF,
             yellow = 24'hFFFF00,
             white = 24'hFFFFFF;
             
             
//例化时钟IP核 33M                         
               clk clk_33M
             (
              // Clock out ports
              .clk_out1(clk),     // output clk_out1
              // Status and control signals
              .reset(!reset_n), // input reset
              .locked(locked),       // output locked
             // Clock in ports
              .clk_50M(clk_50M));  



//例化已经写好的VGA模块
         VGA(
                 .clk(clk),
                 .reset_n(reset_n),
                 .data_in(data_in),//用户输入数据
                 .VGA_HS(VGA_HS),//行同步信号
                 .VGA_VS(VGA_VS),//场同步信号
                 .hcount(hcount),//行扫描位置
                 .vcount(vcount),//场扫描位置
                 .VGA_BLK(VGA_BLK),//数据输出时间段
                 .VGA_CLK(VGA_CLK),
                 .data_out(data_out)
             );
         



//定义扫描像素块
        wire c0_act = hcount >= 0 && hcount <400;//扫描第0列
        wire c1_act = hcount >= 400 && hcount <800;//扫描第1列
        wire r0_act = vcount >= 0 && vcount < 120;//扫描第0行
        wire r1_act = vcount >= 120 && vcount < 240;//扫描第1行
        wire r2_act = vcount >= 240 && vcount < 360;//扫描第2行
        wire r3_act = vcount >= 360 && vcount < 480;//扫描第3行
        wire r0_c0_act = r0_act & c0_act;//定位第0列,第0行像素块扫描
        wire r0_c1_act = r0_act & c1_act;//定位第0列,第1行像素块扫描
        wire r1_c0_act = r1_act & c0_act;//定位第1列,第0行像素块扫描
        wire r1_c1_act = r1_act & c1_act;//定位第1列,第1行像素块扫描
        wire r2_c0_act = r2_act & c0_act;//定位第2列,第0行像素块扫描
        wire r2_c1_act = r2_act & c1_act;//定位第2列,第1行像素块扫描
        wire r3_c0_act = r3_act & c0_act;//定位第3列,第0行像素块扫描
        wire r3_c1_act = r3_act & c1_act;//定位第3列,第1行像素块扫描
        
        
//定义像素块显示颜色
always@(posedge clk)
if(en == 1) begin
case({r3_c1_act, r3_c0_act,r2_c1_act,r2_c0_act,r1_c1_act,r1_c0_act,r0_c1_act,r0_c0_act})
        8'b0000_0001 :  data_in <= black;
        8'b0000_0010 :  data_in <= blue;    
        8'b0000_0100 :  data_in <= red;    
        8'b0000_1000 :  data_in <= purpple;    
        8'b0001_0000 :  data_in <= green;    
        8'b0010_0000 :  data_in <= cyan;    
        8'b0100_0000 :  data_in <= yellow;    
        8'b1000_0000 :  data_in <= white;            
        endcase
        end
else
        data_in <= 24'h000000;        
        

endmodule

在上述代码中,我们还定义了一个33M的时钟IP核 ,主要是由于由于分辨率不同导致时钟(像素时钟)不同。例如我们本项目所要显示的800*480的分辨率,扫描完成一幅图像所用时间为(在1秒之内,时钟震动33M次)恰好完成一幅图像的扫描。实现1056*525(*60hz)像素点(存在水平和垂直消隐期,因此像素点会扩大)的刷新。

刷新率 60Hz 表示每秒更新 60 帧图像,每帧需要传输完整的像素数据。


多分辨率VGA控制器设计

为了满足不同分辨率的需求,使得应用于不同的应用场景 。我们需要对已经设计好的VGA模块进行优化。在进行这第二个任务之前,我们首先要补充一种新的语法:条件编译

条件编译简介

1. ifdef、else 和 endif
ifdef指令用来检查某个宏是否已经被定义。若宏已定义,就编译 ifdef 和 else(如果存在)之间的代码;若未定义,则编译 else 和 endif 之间的代码。

复制代码
`define DEBUG // 定义一个宏

module test_module;
    initial begin
        `ifdef DEBUG
            $display("Debug mode is enabled.");
        `else
            $display("Debug mode is disabled.");
        `endif
    end
endmodule

在这个例子中,由于定义了 DEBUG 宏,所以会打印出 "Debug mode is enabled."。要是去掉 define DEBUG 这一行,就会打印 "Debug mode is disabled."。

2. ifndef
ifndef 指令和 ifdef 相反,它检查某个宏是否未被定义。若宏未定义,就编译 ifndef 和 else(如果存在)之间的代码;若已定义,则编译 else 和 endif 之间的代码。

复制代码
// 不定义宏
// `define RELEASE

module test_module;
    initial begin
        `ifndef RELEASE
            $display("This is not a release version.");
        `else
            $display("This is a release version.");
        `endif
    end
end

因为没有定义 RELEASE 宏,所以会打印 "This is not a release version."。

3. ``define 和 undef
define 指令用于定义一个宏,而 undef 指令用于取消定义一个宏。

复制代码
`define VERSION 2

module test_module;
    initial begin
        `ifdef VERSION
            if (`VERSION == 1) begin
                $display("Version 1 is selected.");
            end else if (`VERSION == 2) begin
                $display("Version 2 is selected.");
            end
        `endif
    end
endmodule

// 在其他地方取消定义
`undef VERSION

在这个例子中,由于定义了 VERSION 宏且其值为 2,所以会打印 "Version 2 is selected."。之后使用 undef VERSION 取消了宏的定义。

4. elsif

elsif 指令用于在 ifdef 或者 ifndef 块里添加更多的条件判断。

复制代码
`define SIMULATION

module test_module;
    initial begin
        `ifdef SIMULATION
            $display("Simulation mode is enabled.");
        `elsif SYNTHESIS
            $display("Synthesis mode is enabled.");
        `else
            $display("Unknown mode.");
        `endif
    end
endmodule

在这个例子中,由于定义了 SIMULATION 宏,所以会打印 "Simulation mode is enabled."。若定义了 SYNTHESIS 宏,就会打印 "Synthesis mode is enabled.";若两个宏都未定义,就会打印 "Unknown mode."。


代码展示

我们可以对VGA时序中的必要参数进行定义,列举所有情况,类似原先的parameter和if语句综合。这样便可方便的修改参数。如以下VGA代码所示:

复制代码
//定义不同的分辨率
`define resolution_480x272 1//时钟为9hz
`define resolution_640x480 1//时钟为25hz
`define resolution_800x480 1//时钟为33hz
`define resolution_800x600 1//时钟为40hz
`define resolution_1024x600 1//时钟为51hz
`define resolution_1024x768 1//时钟为65hz
`define resolution_1280x720 1//时钟为74.25hz
`define resolution_1920x1080 1//时钟为148.5hz


`ifdef resolution_480x272
        `define h_right_border 0
        `define h_front_porch 2
        `define h_sync_time 41
        `define h_back_porch 2
        `define h_left_border 0
        `define h_data_time 480
        `define h_total_time 525
        
        
        `define v_bottom_border 0
        `define v_front_porch 2
        `define v_sync_time 10
        `define v_back_porch 2
        `define v_top_border 0
        `define v_data_time 272
        `define v_total_time 286
        
 
 
`elsif resolution_1280x720
        `define h_right_border 12'd0
        `define h_front_porch 12'd110
        `define h_sync_time 12'd40
        `define h_back_porch 12'd220
        `define h_left_border 12'd0
        `define h_data_time 12'd1280
        `define h_total_time 12'd1650
        
        
        `define v_bottom_border 12'd0
        `define v_front_porch 12'd5
        `define v_sync_time 12'd5
        `define v_back_porch 12'd36
        `define v_top_border 12'd0
        `define v_data_time 12'd720
        `define v_total_time 12'd750        
        
      
        
`elsif resolution_1920x1080
        `define h_right_border 12'd0
        `define h_front_porch 12'd88
        `define h_sync_time 12'd44
        `define h_back_porch 12'd148
        `define h_left_border 12'd0
        `define h_data_time 12'd1920
        `define h_total_time 12'd2200
        
        
        `define v_bottom_border 12'd0
        `define v_front_porch 12'd4
        `define v_sync_time 12'd5
        `define v_back_porch 12'd36
        `define v_top_border 12'd0
        `define v_data_time 12'd1080
        `define v_total_time 12'd1125

//仅输入部分例子,其余可查询手册或VGA标准自行计算

`endif

同时在原先的顶层设计VGA中,也要进行相应的参数定义! 以达到一致便于分辨率适配。

复制代码
//定义时序中相关信号       
        //parameter VGA_HS_end =  11'd127;
        //parameter hdat_begin = 11'd216;//行数据开始输出位置
        //parameter hdat_end = 11'd1016;//行数据停止输出位置
        //parameter hpixel_end = 11'd1055;//行扫描的最大位置处
        
        //parameter VGA_VS_end =  11'd1;
        //parameter vdat_begin = 11'd35;
        //parameter vdat_end = 11'd515;
        //parameter vline_end = 11'd524; 
                   
//将上述的parameter定义改为参数定义,便于适配
        parameter  VGA_HS_end = `h_sync_time - 1,
                    hdat_begin = `h_sync_time + `h_back_porch + `h_left_border,
                    hdat_end = `h_sync_time + `h_back_porch + `h_left_border + `h_data_time,
                    hpixel_end = `h_total_time - 1,
                    VGA_VS_end = `v_sync_time - 1,
                    vdat_begin = `v_sync_time + `v_back_porch + `v_top_border,
                    vdat_end = `v_sync_time + `v_back_porch + `v_top_border + `v_data_time,
                    vpixel_end = `v_total_time - 1;

到此,我们的VGA控制显示便生成!!!可生成自己想要实现的图像,例如:

相关推荐
学习永无止境@5 小时前
FPGA设计中时间单位科普
fpga开发·fpga·时钟约束
jiemidashi5 小时前
前沿技术一览科技改变生活新趋势
经验分享·科技·生活
Mazy.v6 小时前
FPGA 以太网通信(一)
fpga开发
知行合一←_←7 小时前
FPGA时钟约束
fpga开发
CQU_JIAKE8 小时前
3.16[A]FPGA
fpga开发
lindaakk8 小时前
从设计到量产:MHO5000如何实现电源EMIEMC测试全流程自动化?
人工智能·驱动开发·fpga开发·硬件工程·dsp开发·射频工程
Mazy.v9 小时前
FPGA 以太网通信(二)
fpga开发
计算机-秋大田9 小时前
基于Spring Boot的红色革命文物征集管理系统的设计与实现(LW+源码+讲解)
java·vue.js·spring boot·后端·课程设计
灏瀚星空11 小时前
移动端医疗AI诊断系统的设计思路与技术展望——多模态生理数据分析的理论框架探讨
人工智能·经验分享·数据挖掘·数据分析