[X]关闭
1

(AXI4)S02- CH02 基于 FDMA 实现多缓存视频构架

摘要: 很多学习FPGA编程的人都想走捷径,然而捷径就是一步一个脚印,才能迈向最终的成功,否则即便是你刚开始跑的快一点,但是你还是失败,得不偿失。这是正是所谓磨刀不误砍柴工。对于小编原创的FDMA没有经过充分验证就去 ...

软件版本:VIVADO2017.4

操作系统:WIN10 64bit

硬件平台:ARTIX系列

米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!!

2.1概述

      很多学习FPGA编程的人都想走捷径,然而捷径就是一步一个脚印,才能迈向最终的成功,否则即便是你刚开始跑的快一点,但是你还是失败,得不偿失。这是正是所谓磨刀不误砍柴工。对于小编原创的FDMA没有经过充分验证就去跑应用,万一那里出了问题,到底是硬件的问题,还是软件的问题,还是FDMA的问题,那就难排查了。所以我们还是要做一些准备工作。在这节课中,我们将用FPGA代码产生一个1080P60HZ的测试图像,然后经过FDMA进入DDR缓存3帧后再从FDMA读出来,经过HDMI显示器显示。做完这个实验下一节课我们就加入HDMI输入视频信号再经过3次缓存后输出到HDMI显示器。

       另外从本章开始,不提供详细的VIVADO软件使用或者配置步骤,除非一些新IP的出现有必要讲解的情况下才说明。

2.2基于FDMA搭建的BD工程

       这个BD文件和前面一节课的基本一样。但是有个IP换了,换成了axi_interconnect IP。有人可能会问,为什么要换这个IP,一开始我也不知道。但是可以肯定的是用上一课的IP无法达到FDMA和MIG之间AXI4的最大带宽。导致1080P视频不能正常传输。所以小编就尝试换了这个IP而且把这个IP里面的几个参数修改了。

这样修改完成后,带宽就能最大化,在开发板上完美传输1080P@60fps的视频。

为了最大带宽,我们还要修改FDMA的IP参数如下图。

      这里把BURST LEN设置为256 DATA WIDTH设置为128。为什么这样设置呢?假设100M时钟,如果设置128bit理论上有1600MB/S的带宽能力(实际不可能达到,效率一般在75%左右)。如下面图所示。


2.3基于FDMA多缓存视频构架fdma_controller

       一个优秀的工程,必然有一个优秀的构架。优秀的构架具备通用、简洁、高可靠、易维护等优秀属性。小编见过很多人写的代码,只在一个特定的工程里面可以很好的工作,但是如果要换个环境,几乎要推到重来。这种代码就是比较垃圾的代码。我们在做一件事情的时候一定要注重效率,注重可重复利用性。这就要求我们对现在的使用环境,以及对将来的使用环境有一个认知。然后构建一个比较通用的代码构架。虽然小编也是半路出道,人算不上聪明,而且具备一定的懒惰性。小编喜欢做一些重复性的工作,最喜欢修改个参数就能实现一些新的功能。基于以上目标,即便是我不是一个优秀的程序要,但是我依然要懂得偷懒,尽最大努力从一个小小的视频缓存构架开始,努力设计好这个简单的构架。那么对于正在阅读小编写的教程的初级程序猿,自然也要时刻考虑如何偷懒,如果你写的一个代码被成千上万,到几百万的人重复利用了,你一定成功了。

       对于本课内容,小编绘制了如下框图。可以看image_data_gen产生了测试图片,之后进入过W0 FIFO进行视频缓存。每次缓存1024个像素,就往通过FDMA往DDR里面搬运数据。另外VS信号经过滤波采集后用于启动一次写状态机。同理对于图像的输出部分采用HDMI输出,用Vga_lcd_driver产生输出的时序。视频经过R0 FIFO缓存后输出。R0 FIFO也是每次缓存1024个像素数据。


        为了进行图像的多缓存,一般非同步信号至少要满足3缓存才能最大减少图片的延迟,撕裂,丢帧问题。本构架只要DDR够大,理论上可以进行无限次缓存。

2.4代码叠层结构


2.5 fdma_controller

      当然针对上图还无法完全展示fdma_controller控制器的全部功能。下面贴出代码

module fdma_controller#

(

parameter  integer  ADDR_OFFSET = 0,

parameter  integer  BUF_SIZE = 3,

parameter  integer  H_CNT = 640,

parameter  integer  V_CNT = 480

)

(

    input           ui_clk,

    input           ui_rstn,

//sensor input -W0_FIFO--------------

    input           W0_FS_i,

    input           W0_wclk_i,

    input           W0_wren_i,

    input  [31:0]   W0_data_i,

//hdmi output -R0_FIFO---------------

    input           R0_FS_i,

    input           R0_rclk_i,

    input           R0_rden_i,

    output[31:0]    R0_data_o,

//----------fdma signals write-------       

    output  reg     pkg_wr_areq,       

    input           pkg_wr_en,

    input           pkg_wr_last,

    output  [31:0]  pkg_wr_addr,

    output  [127:0] pkg_wr_data,

    output  [31:0]  pkg_wr_size,

//----------fdma signals read---------       

    output  reg     pkg_rd_areq,

    input           pkg_rd_en,   

    input           pkg_rd_last,         

    output  [31:0]  pkg_rd_addr,

    input   [127:0] pkg_rd_data,

    output  [31:0]  pkg_rd_size    

    );

    

parameter FBUF_SIZE = BUF_SIZE -1'b1;

parameter BURST_SIZE  = 1024*4;// one time 4KB

parameter BURST_TIMES = H_CNT*V_CNT/1024;// one frame burst times

parameter PKG_SIZE    = 256;

assign pkg_wr_size = PKG_SIZE;

assign pkg_rd_size = PKG_SIZE;


//------------vs 滤波---------------

reg  W0_FIFO_Rst;

reg  R0_FIFO_Rst;


wire W0_FS;

wire R0_FS;  


reg [6:0] W0_Fbuf;

reg [6:0] R0_Fbuf;


reg W0_s_rdy;

reg R0_s_rdy;


fs_cap fs_cap_W0(

  .clk_i(ui_clk),

  .rstn_i(ui_rstn),

  .vs_i(W0_FS_i),

  .s_rdy_i(W0_s_rdy),

  .fs_cap_o(W0_FS)

);

fs_cap fs_cap_R0(

  .clk_i(ui_clk),

  .rstn_i(ui_rstn),

  .vs_i(R0_FS_i),

  .s_rdy_i(R0_s_rdy),

  .fs_cap_o(R0_FS)

);

parameter S_IDLE  =  2'd0;  

parameter S_RST   =  2'd1;  

parameter S_DATA1 =  2'd2;   

parameter S_DATA2 =  2'd3;


reg [1  :0]  W_MS;

reg [22:0]  W0_addr;

reg [31 :0]  W0_fcnt;

reg [10  :0] W0_bcnt;

wire [10:0]  W0_rcnt;

reg W0_REQ;

reg [1 :0]  R_MS;

reg [22 :0] R0_addr;

reg [31 :0] R0_fcnt;

reg [10 :0] R0_bcnt;

wire [10:0] R0_wcnt;

reg R0_REQ;


assign pkg_wr_addr = {W0_Fbuf,W0_addr}+ ADDR_OFFSET;

assign pkg_rd_addr = {R0_Fbuf,R0_addr}+ ADDR_OFFSET;

//assign pkg_wr_data = W0_fcnt;

//--------一帧图像写入DDR------------

 always @(posedge ui_clk) begin

    if(!ui_rstn)begin

        W_MS <= S_IDLE;

        W0_addr <= 21'd0;

        pkg_wr_areq <= 1'd0;

        W0_FIFO_Rst <= 1'b1;

        W0_fcnt <= 0;

        W0_bcnt <= 0;

        W0_s_rdy <= 1'b0;

        W0_Fbuf <= 7'd0;

    end

    else begin

      case(W_MS)

       S_IDLE:begin

          W0_addr <= 21'd0;

          W0_fcnt <= 0;

          W0_bcnt <= 11'd0;

          W0_s_rdy <= 1'b1;

          if(W0_FS) W_MS <= S_RST;

       end

       S_RST:begin

           W0_s_rdy <= 1'b0;  

          if(W0_fcnt > 8'd30 ) W_MS <= S_DATA1;

          W0_FIFO_Rst <= (W0_fcnt < 8'd20);

          W0_fcnt <= W0_fcnt +1'd1;

        end          

        S_DATA1:begin

            if(W0_bcnt == BURST_TIMES) begin

                if(W0_Fbuf == FBUF_SIZE)

                    W0_Fbuf <= 7'd0;

                 else

                    W0_Fbuf <= W0_Fbuf + 1'b1;

                 W_MS <= S_IDLE;

            end

            else if(W0_REQ) begin

                W0_fcnt <=0;

                pkg_wr_areq <= 1'b1;

                W_MS <= S_DATA2;  

            end           

         end

         S_DATA2:begin

            pkg_wr_areq <= 1'b0;

            if(pkg_wr_last)begin

                W_MS <= S_DATA1;

                W0_bcnt <= W0_bcnt + 1'd1;

                W0_addr <= W0_addr + BURST_SIZE;

            end

         end

       endcase

    end

 end


//--------一帧图像读出DDR------------

 always @(posedge ui_clk) begin

   if(!ui_rstn)begin

       R_MS <= S_IDLE;

       R0_addr <= 21'd0;

       pkg_rd_areq <= 1'd0;

       R0_fcnt <=0;

       R0_bcnt <=0;

       R0_FIFO_Rst <= 1'b1;

       R0_s_rdy <= 1'b0;

       R0_Fbuf <= 7'd0;       

   end

   else begin

     case(R_MS)

       S_IDLE:begin

         R0_addr <= 21'd0;

         R0_fcnt <=0;

         R0_bcnt <=0;

         R0_s_rdy <= 1'b1;

         if(R0_FS) R_MS <= S_RST;

       end

       S_RST:begin

         R0_s_rdy <= 1'b0;

         if(R0_fcnt > 8'd30 ) R_MS <= S_DATA1;

         R0_FIFO_Rst <= (R0_fcnt < 8'd20);

         R0_fcnt <= R0_fcnt + 1'd1;

       end  

       S_DATA1:begin

           if(R0_bcnt == BURST_TIMES ) begin

               R_MS <= S_IDLE;

               if(W0_Fbuf == 7'd0)

                    R0_Fbuf <= FBUF_SIZE;

                else

                    R0_Fbuf <= W0_Fbuf - 1'b1;   

           end

           else if(R0_REQ) begin

               pkg_rd_areq <= 1'b1;

               R_MS <= S_DATA2;  

           end           

        end

        S_DATA2:begin

           pkg_rd_areq <= 1'b0;   

           if(pkg_rd_last)begin

               R_MS <= S_DATA1;

               R0_bcnt <= R0_bcnt + 1'd1;

               R0_addr <= R0_addr + BURST_SIZE;

           end

        end

      endcase

   end

end


 always@(posedge ui_clk)

 begin     

     W0_REQ    <= (W0_rcnt    >= PKG_SIZE);

     R0_REQ    <= (R0_wcnt    <= PKG_SIZE);

 end


W0_FIFO W0_FIFO_0 (

  .rst(W0_FIFO_Rst),  // input wire rst

  .wr_clk(W0_wclk_i),  // input wire wr_clk

  .din(W0_data_i),        // input wire [31 : 0] din

  .wr_en(W0_wren_i),    // input wire wr_en

  .rd_clk(ui_clk),  // input wire rd_clk

  .rd_en(pkg_wr_en),    // input wire rd_en

  .dout(pkg_wr_data),      // output wire [63 : 0] dout

  .rd_data_count(W0_rcnt)  // output wire [10 : 0] wr_data_count

);


 R0_FIFO R0_FIFO_0 (

  .rst(R0_FIFO_Rst),  // input wire rst

  .wr_clk(ui_clk),  // input wire wr_clk

  .din(pkg_rd_data),        // input wire [63 : 0] din

  .wr_en(pkg_rd_en),    // input wire wr_en

  .wr_data_count(R0_wcnt),  // output wire [6 : 0] rd_data_count

  .rd_clk(R0_rclk_i),  // input wire rd_clk

  .rd_en(R0_rden_i),    // input wire rd_en

  .dout(R0_data_o)      // output wire [31 : 0] dout

);


endmodule

截取上面完整代码中部分代码如下,可以看到小编通过控制高地址,轻松完成缓存地址切换。

assign pkg_wr_addr = {W0_Fbuf,W0_addr}+ ADDR_OFFSET;

assign pkg_rd_addr = {R0_Fbuf,R0_addr}+ ADDR_OFFSET;

再来看下顶层接口,这里面4个参数分辨率代表内存地址的偏移,帧缓存数量,图像的水平像素 和垂直像素。

module fdma_controller#

(

parameter  integer  ADDR_OFFSET = 0,

parameter  integer  BUF_SIZE = 3,

parameter  integer  H_CNT = 640,

parameter  integer  V_CNT = 480

)


最后看下我们如何如何调用fdma_controller,并且设置1080P的分辨率的。可以看到小编这里设置的偏移地址为0,缓存为3缓存,分辨率为1920X1080。就是这么简单。目前fdma_controller不修改源码的情况下支持任意是1024个像素的整数倍的图像。比如1280X720/640X800/1024X600,如果不是整数倍那就需要你自己修改fdma_controller和FDMA的参数了。

//---------------fdma image buf controller---------------------------  

fdma_controller # (

.ADDR_OFFSET(0),

.BUF_SIZE(3),

.H_CNT (1920),

.V_CNT (1080)

) fdma_controller_u0

(

      //FDAM signals

      .ui_clk(ui_clk),

      .ui_rstn(ui_rstn),

//Sensor video

      .W0_FS_i(W0_FS_i),

      .W0_wclk_i(W0_wclk_i),

      .W0_wren_i(W0_wren_i),

      .W0_data_i(W0_data_i),

      //vga/hdmi output -CH6_FIFO

      .R0_FS_i(R0_FS_i),

      .R0_rclk_i(R0_rclk_i),

      .R0_rden_i(R0_rden_i),

      .R0_data_o(R0_data_o),

        

      .pkg_wr_areq(pkg_wr_areq),    

      .pkg_wr_en(pkg_wr_en),

      .pkg_wr_last(pkg_wr_last),

      .pkg_wr_addr(pkg_wr_addr),

      .pkg_wr_data(pkg_wr_data),

      .pkg_wr_size(pkg_wr_size),

    

      .pkg_rd_areq(pkg_rd_areq),

      .pkg_rd_en(pkg_rd_en),      

      .pkg_rd_last(pkg_rd_last),

      .pkg_rd_addr(pkg_rd_addr),

      .pkg_rd_data(pkg_rd_data),

      .pkg_rd_size(pkg_rd_size)  

 );

其他部分的代码比较简单,只给出代码源码,如果有不清楚的可以给我留言。

2.6 sensor_data_gen

module  sensor_data_gen (

    input  clk,

    output [23:0]rgb,

    output de,

    output vsync,

    output hsync

    );


   reg  [23:0] colour=24'd0;

   reg  [11:0] hcounter=12'd0;

   reg  [11:0] vcounter=12'd0;

    

// Colours converted using The RGB -> YCbCr converter app found on Google Gadgets

                                //   Y    Cb   Cr

   `define C_BLACK 24'h000000;  //  16   128  128

   `define C_RED   24'hFF0000;  //  81   90   240

   `define C_GREEN 24'h00FF00;  //  172  42   27

   `define C_BLUE  24'h0000FF;  //  32   240  118

   `define C_WHITE 24'hFFFFFF;  //  234  128  128



// -- Set the video mode to 1920x1080x60Hz (150MHz pixel clock needed)

   parameter hVisible  = 1920;

   parameter hStartSync = 1920+88;

   parameter hEndSync   = 1920+88+44;

   parameter hMax       = 1920+88+44+148; //2200

   

   parameter vVisible    = 1080;

   parameter vStartSync  = 1080+4;

   parameter vEndSync    = 1080+4+5;

   parameter vMax        = 1080+4+5+36; //1125

 /**/


// -- Set the video mode to 1440x900x60Hz (106.47MHz pixel clock needed)

/*   parameter hVisible   = 1440;

   parameter hStartSync = 1440+80;

   parameter hEndSync   = 1440+80+152;

   parameter hMax       = 1440+80+152+232; //1904

   

   parameter vVisible    = 900;

   parameter vStartSync  = 900+1;

   parameter vEndSync    = 900+1+3;

   parameter vMax        = 900+1+3+28; //932

   */


    

// -- Set the video mode to 1280x720x60Hz (75MHz pixel clock needed)

 /*  parameter hVisible   = 1280;

   parameter hStartSync = 1280+72;

   parameter hEndSync   = 1280+72+80;

   parameter hMax       = 1280+72+80+216; //1647

   

   parameter vVisible    = 720;

   parameter vStartSync  = 720+3;

   parameter vEndSync    = 720+3+5;

   parameter vMax        = 720+3+5+22; //749

*/


// -- Set the video mode to 800x600x60Hz (40MHz pixel clock needed)

/*   parameter hVisible   = 800;

   parameter hStartSync = 840; //800+40

   parameter hEndSync   = 968; //800+40+128

   parameter hMax       = 1056; //800+40+128+88

   

   parameter vVisible    = 600;

   parameter vStartSync  = 601; //600+1

   parameter vEndSync    = 605; //600+1+4

   parameter vMax        = 628; //600+1+4+23      




// -- Set the video mode to 640x480x60Hz (25MHz pixel clock needed)


   parameter hVisible   = 640;

   parameter hStartSync = 656; //640+16

   parameter hEndSync   = 752; //640+16+96

   parameter hMax       = 800; //640+16+96+48

   

   parameter vVisible    = 480;

   parameter vStartSync  = 490; //480+10

   parameter vEndSync    = 492; //480+10+2

   parameter vMax        = 525; //480+10+2+33

*/

//------------------------------------------

//v_sync counter & generator


always@(posedge clk) begin

if(hcounter < hMax - 12'd1)        //line over

hcounter <= hcounter + 12'd1;

else

hcounter <= 12'd0;

end


always@(posedge clk) begin

if(hcounter == hMax - 12'd1) begin

if(vcounter < vMax - 12'd1)  //frame over

vcounter <= vcounter + 12'd1;

else

vcounter <= 12'd0;

end

end



        

 always@(posedge clk) begin

    if (hcounter <= hVisible/5) begin colour <= `C_RED; end

    else if(hcounter <= 2*hVisible/5) begin colour <= `C_GREEN; end

    else if(hcounter <= 3*hVisible/5) begin colour <= `C_BLUE; end

    else if(hcounter <= 4*hVisible/5) begin colour <= `C_WHITE; end

    else  begin colour <= `C_BLACK; end

 end

/*  

  assign r = colour[23:16];

  assign g = colour[15:8];

  assign b = colour[7:0];

  */


reg [7:0]VGA_R_reg;

reg [7:0]VGA_G_reg;

reg [7:0]VGA_B_reg;

reg [10:0] dis_mode;

always @(posedge clk) begin

    if((vcounter == vMax - 12'd1)&&(hcounter == hMax - 12'd1))

        dis_mode <= dis_mode +1'b1;


end


reg[7:0] grid_data_1;

reg[7:0] grid_data_2;

always @(posedge clk) //格子图像

begin

if((hcounter[4]==1'b1)^(vcounter[4]==1'b1))

grid_data_1 <= 8'h00;

else

grid_data_1 <= 8'hff;


if((hcounter[6]==1'b1)^(vcounter[6]==1'b1))

grid_data_2 <= 8'h00;

else

grid_data_2 <= 8'hff;

end


reg[23:0] color_bar;

always @(posedge clk)

begin

if(hcounter==260)

color_bar <= 24'hff0000;

else if(hcounter==420)

color_bar <= 24'h00ff00;

else if(hcounter==580)

color_bar <= 24'h0000ff;

else if(hcounter==740)

color_bar <= 24'hff00ff;

else if(hcounter==900)

color_bar <= 24'hffff00;

else if(hcounter==1060)

color_bar <= 24'h00ffff;

else if(hcounter==1220)

color_bar <= 24'hffffff;

else if(hcounter==1380)

color_bar <= 24'h000000;

else

color_bar <= color_bar;

end


always @(posedge clk)

begin  

if(1'b0)

begin

   VGA_R_reg<=0;

   VGA_G_reg<=0;

   VGA_B_reg<=0;  

end

   else

     case(dis_mode[10:7])

         4'd0:begin

     VGA_R_reg<=0;            //LCD显示彩色条

                 VGA_G_reg<=0;

                 VGA_B_reg<=0;

end

4'd1:begin

     VGA_R_reg<=8'b11111111;                 //LCD显示全白

                 VGA_G_reg<=8'b11111111;

                 VGA_B_reg<=8'b11111111;

end

4'd2:begin

     VGA_R_reg<=8'b11111111;                //LCD显示全红

                 VGA_G_reg<=0;

                 VGA_B_reg<=0;  

             end   

       4'd3:begin

     VGA_R_reg<=0;                          //LCD显示全绿

                 VGA_G_reg<=8'b11111111;

                 VGA_B_reg<=0;

            end   

             4'd4:begin     

     VGA_R_reg<=0;                         //LCD显示全蓝

                 VGA_G_reg<=0;

                 VGA_B_reg<=8'b11111111;

end

             4'd5:begin     

     VGA_R_reg<=grid_data_1;               // LCD显示方格1

                 VGA_G_reg<=grid_data_1;

                 VGA_B_reg<=grid_data_1;

            end   

            4'd6:begin     

     VGA_R_reg<=grid_data_2;               // LCD显示方格2

                 VGA_G_reg<=grid_data_2;

                 VGA_B_reg<=grid_data_2;

end

    4'd7:begin     

     VGA_R_reg<=hcounter[7:0];                //LCD显示水平渐变色

                 VGA_G_reg<=hcounter[7:0];

                 VGA_B_reg<=hcounter[7:0];

 end

     4'd8:begin     

     VGA_R_reg<=vcounter[8:1];                 //LCD显示垂直渐变色

                 VGA_G_reg<=hcounter[8:1];

                 VGA_B_reg<=hcounter[8:1];

end

     4'd9:begin     

     VGA_R_reg<=hcounter[7:0];                 //LCD显示红水平渐变色

                 VGA_G_reg<=0;

                 VGA_B_reg<=0;

end

     4'd10:begin     

     VGA_R_reg<=0;                          //LCD显示绿水平渐变色

                 VGA_G_reg<=hcounter[7:0];

                 VGA_B_reg<=0;

end

     4'd11:begin     

     VGA_R_reg<=0;                          //LCD显示蓝水平渐变色

                 VGA_G_reg<=0;

                 VGA_B_reg<=hcounter[7:0];

end

     4'd12:begin     

     VGA_R_reg<=color_bar[23:16];            //LCD显示彩色条

                 VGA_G_reg<=color_bar[15:8];

                 VGA_B_reg<=color_bar[7:0];

end

   default:begin

     VGA_R_reg<=8'b11111111;                //LCD显示全白

                 VGA_G_reg<=8'b11111111;

                 VGA_B_reg<=8'b11111111;

end   

         endcase

end


assign hsync = ((hcounter >= (hStartSync - 2'd2))&&(hcounter < (hEndSync - 2'd2)))? 1'b0:1'b1;  //Generate the hSync Pulses

assign vsync = ((vcounter >= (vStartSync - 1'b1))&&(vcounter < (vEndSync - 1'b1)))? 1'b0:1'b1; //Generate the vSync Pulses

assign de =    (vcounter >= vVisible || hcounter >= hVisible) ? 1'b0 : 1'b1;

assign rgb = {VGA_R_reg,VGA_G_reg,VGA_B_reg};  

  

 endmodule

2.7 vga_lcd_driver.v

module vga_lcd_driver(

    input  clk,

    input  [7:0]  r_i,

    input  [7:0]  g_i,

    input  [7:0]  b_i,

    output [7:0]  r_o,

    output [7:0]  g_o,

    output [7:0]  b_o,

    output de,

    output vsync,

    output hsync

    );


   reg  [11:0] hcounter;

   reg  [11:0] vcounter;

    

// Colours converted using The RGB


// -- Set the video mode to 1920x1080x60Hz (150MHz pixel clock needed)

   parameter hVisible  = 1920;

   parameter hStartSync = 1920+88;

   parameter hEndSync   = 1920+88+44;

   parameter hMax       = 1920+88+44+148; //2200

   

   parameter vVisible    = 1080;

   parameter vStartSync  = 1080+4;

   parameter vEndSync    = 1080+4+5;

   parameter vMax        = 1080+4+5+36; //1125

/* */


// -- Set the video mode to 1440x900x60Hz (106.47MHz pixel clock needed)

/*   parameter hVisible   = 1440;

   parameter hStartSync = 1440+80;

   parameter hEndSync   = 1440+80+152;

   parameter hMax       = 1440+80+152+232; //1904

   

   parameter vVisible    = 900;

   parameter vStartSync  = 900+1;

   parameter vEndSync    = 900+1+3;

   parameter vMax        = 900+1+3+28; //932

   */


    

// -- Set the video mode to 1280x720x60Hz (75MHz pixel clock needed)

  /*parameter hVisible   = 1280;

   parameter hStartSync = 1280+72;

   parameter hEndSync   = 1280+72+80;

   parameter hMax       = 1280+72+80+216; //1647

   

   parameter vVisible    = 720;

   parameter vStartSync  = 720+3;

   parameter vEndSync    = 720+3+5;

   parameter vMax        = 720+3+5+22; //749

*/


// -- Set the video mode to 800x600x60Hz (40MHz pixel clock needed)

/*   parameter hVisible   = 800;

   parameter hStartSync = 840; //800+40

   parameter hEndSync   = 968; //800+40+128

   parameter hMax       = 1056; //800+40+128+88

   

   parameter vVisible    = 600;

   parameter vStartSync  = 601; //600+1

   parameter vEndSync    = 605; //600+1+4

   parameter vMax        = 628; //600+1+4+23      


// -- Set the video mode to 640x480x60Hz (25MHz pixel clock needed)


   parameter hVisible   = 640;

   parameter hStartSync = 656; //640+16

   parameter hEndSync   = 752; //640+16+96

   parameter hMax       = 800; //640+16+96+48

   

   parameter vVisible    = 480;

   parameter vStartSync  = 490; //480+10

   parameter vEndSync    = 492; //480+10+2

   parameter vMax        = 525; //480+10+2+33

*/


//------------------------------------------

//v_sync counter & generator


always@(posedge clk) begin

if(hcounter < hMax - 12'd1)        //line over

hcounter <= hcounter + 12'd1;

else

hcounter <= 12'd0;

end


always@(posedge clk) begin

if(hcounter == hMax - 12'd1) begin

if(vcounter < vMax - 12'd1)  //frame over

vcounter <= vcounter + 12'd1;

else

vcounter <= 12'd0;

end

end


assign hsync = ((hcounter >= (hStartSync - 2'd2))&&(hcounter < (hEndSync - 2'd2)))? 1'b0:1'b1;  //Generate the hSync Pulses

assign vsync = ((vcounter >= (vStartSync - 1'b1))&&(vcounter < (vEndSync - 1'b1)))? 1'b0:1'b1; //Generate the vSync Pulses

  

        

  assign de = (vcounter >= vVisible || hcounter >= hVisible) ? 1'b0 : 1'b1;

  assign r_o = r_i;

  assign g_o = g_i;

  assign b_o = b_i;  

endmodule

这个模块实际上和 image_data_gen 模块的代码几乎一样,只是这里的 RGB 数据是采用经过 DDR 缓存 后输入进来的 RGB 数据输出出去。

2.8测试结果


路过

雷人

握手

鲜花

鸡蛋
发表评论

最新评论

引用 clong 2020-12-2 23:02
fdma资料在哪里呢

查看全部评论(1)

本文作者
2019-10-18 09:47
  • 1
    粉丝
  • 2948
    阅读
  • 1
    回复

米联客UIsrc

独家课程 硬核科技

销售电话:18921033576
EMAIL:tjy@uisrc.com
地址:常州溧阳市天目云谷3号楼北楼
热门评论
排行榜