【ZYNQ-7000开发之十一】VGA RLT代码封装成AXI Stream

21 篇文章 2 订阅
17 篇文章 6 订阅

本编文章将对VGA的RTL代码,封装成AXI Stream,并且在vivado 里用TPG进行测试

本篇文章的VGA RTL代码在【ZYNQ-7000开发之一】基础上修改,封装好的VGA Stream可以方便我们实现视频图像处理

TGP 等的规范说明可以到官网下载最新版本

本文所使用的开发板是Miz702(兼容zedboard)
PC 开发环境版本:Vivado 2015.2 Xilinx SDK 2015.2
其它:VGA显示器

AXI Stream原理

首先这里列出axi stream的信号,红框里的是要用到的
这里写图片描述
核心的信号是,TVALID,TREADY,TLAST,TUSER

TVALID和TREADY握手信号

这里写图片描述
在TVALID和TREADY同时有效的时候,数据才有效。对于TPG来说,大部分时间TVALID是有效的,TREADY由我们自己控制。
TUSER(SOF,Start Of Frame),代表每一帧的开始。TLAST(EOL,End Of Line),代表每一行的结束。
这里给出TPG的时序图,比较简洁,要理解之后才好把RTL封装成AXI Stream
这里写图片描述
这里写图片描述

封装AXI Stream

打开vivado,建立一个工程(选择zed)
选择Tools->Create and Package IP

这里写图片描述

点击NEXT,选择Create AXI4,如图所示

这里写图片描述

输入好name和路径后,点击NEXT

这里写图片描述

按照如下配置

这里写图片描述

点击NEXT,选择Edit IP,然后点击Finish
这时会弹出一个新的IP 编辑界面,这个可以看到VIVADO已经自动生成了一些必要的AXI Stream相关的代码,我们在这个基础上修改很方便
把VGA_AXI_Stream_v1_0.v文件里的代码,修改如下
`timescale 1 ns / 1 ps

    module myip_v1_0 #
    (
        // Users to add parameters here

        // User parameters ends
        // Do not modify the parameters beyond this line


        // Parameters of Axi Slave Bus Interface S00_AXIS_VGA
        parameter integer C_S00_AXIS_VGA_TDATA_WIDTH    = 32
    )
    (
        // Users to add ports here
        input   wire            clk_25mhz,
        output  wire            hsync,
        output  wire            vsync,
        output  wire   [11:0]   rgb,
        output  reg             led,
        // User ports ends
        // Do not modify the ports beyond this line

        // Ports of Axi Slave Bus Interface S00_AXIS_VGA
        input wire  s00_axis_vga_aclk,
        input wire  s00_axis_vga_aresetn,
        output wire  s00_axis_vga_tready,
        input wire [C_S00_AXIS_VGA_TDATA_WIDTH-1 : 0] s00_axis_vga_tdata,
        input wire [(C_S00_AXIS_VGA_TDATA_WIDTH/8)-1 : 0] s00_axis_vga_tstrb,
        input wire  s00_axis_vga_tlast,
        input wire  s00_axis_vga_tvalid,
        input wire  s00_axis_vga_tuser
    );
// Instantiation of Axi Bus Interface S00_AXIS_VGA
    myip_v1_0_S00_AXIS_VGA # ( 
        .C_S_AXIS_TDATA_WIDTH(C_S00_AXIS_VGA_TDATA_WIDTH)
    ) myip_v1_0_S00_AXIS_VGA_inst (
        .S_AXIS_ACLK(s00_axis_vga_aclk),
        .S_AXIS_ARESETN(s00_axis_vga_aresetn),
        .S_AXIS_TREADY(s00_axis_vga_tready),
        .S_AXIS_TDATA(s00_axis_vga_tdata),
        .S_AXIS_TSTRB(s00_axis_vga_tstrb),
        .S_AXIS_TLAST(s00_axis_vga_tlast),
        .S_AXIS_TVALID(s00_axis_vga_tvalid),
        .S_AXIS_TUSER(s00_axis_vga_tuser),
        .clk            (clk_25mhz),
        .rst_n          (s00_axis_vga_aresetn),
        .video_en       (video_en),
        .hsync          (hsync),
        .vsync          (vsync),
        .pixel_x        (pixel_x),
        .pixel_y        (pixel_y)
    );

    // Add user logic here

    wire    [9:0]   pixel_x;
    wire    [9:0]   pixel_y;
    wire            clk_25mhz;
    reg     [11:0]  rgb_reg;


    //显示静态图像640*480
    reg        [23:0] cnt;
    always @(posedge clk_25mhz or negedge s00_axis_vga_aresetn)
        if(!s00_axis_vga_aresetn)
            begin
                cnt <= 0;
                led <= 0;
            end 
        else
            begin
                cnt <= cnt + 1'b1;
                if(cnt == 24'd12500000)
                    begin 
                        cnt <= 24'b0;
                        led <= ~led;
                    end 
            end 
    always @ (posedge clk_25mhz or negedge s00_axis_vga_aresetn)
        if(!s00_axis_vga_aresetn)
            begin
                rgb_reg <= 12'b0;
            end 
        else if(s00_axis_vga_tvalid == 1'b1 && s00_axis_vga_tready == 1'b1)
            begin                //显示图像         
                rgb_reg[3:0] <= s00_axis_vga_tdata[7:4];
                rgb_reg[7:4] <= s00_axis_vga_tdata[15:12];
                rgb_reg[11:8] <= s00_axis_vga_tdata[23:20];    
            end        
   /*         
    always @ (posedge clk_25mhz or negedge s00_axis_vga_aresetn)
        if(!s00_axis_vga_aresetn)
            begin
                address_sig <= 19'b0;
            end 
        else
            begin                
                if(pixel_x>=0 && pixel_x<= 639 && pixel_y>=0 && pixel_y<=479)
                    address_sig = (pixel_x + 640*pixel_y);
            end    
*/
    //        
    assign rgb = (video_en == 1'b1) ? rgb_reg:12'b0;          

    // User logic ends

    endmodule
把VGA_AXI_Stream_v1_0_S00_AXI_VgA.v文件里的代码,修改如下

// Users to add ports here
        input   wire            clk,
        input   wire            rst_n,
        output  wire            video_en,
        output  reg             hsync,
        output  reg             vsync,
        output  wire    [9:0]   pixel_x,
        output  wire    [9:0]   pixel_y,  
        // User ports ends
        // Do not modify the ports beyond this line

        // AXI4Stream sink: Clock
        input wire  S_AXIS_ACLK,
        // AXI4Stream sink: Reset
        input wire  S_AXIS_ARESETN,
        // Ready to accept data in
        output wire  S_AXIS_TREADY,
        // Data in
        input wire [C_S_AXIS_TDATA_WIDTH-1 : 0] S_AXIS_TDATA,
        // Byte qualifier
        input wire [(C_S_AXIS_TDATA_WIDTH/8)-1 : 0] S_AXIS_TSTRB,
        // Indicates boundary of last packet
        input wire  S_AXIS_TLAST,
        // Data is in valid
        input wire  S_AXIS_TVALID,
        input wire S_AXIS_TUSER
    );
    // function called clogb2 that returns an integer which has the 
    // value of the ceiling of the log base 2.
    function integer clogb2 (input integer bit_depth);
      begin
        for(clogb2=0; bit_depth>0; clogb2=clogb2+1)
          bit_depth = bit_depth >> 1;
      end
    endfunction

    // Total number of input data.
    localparam NUMBER_OF_INPUT_WORDS  = 8;
    // bit_num gives the minimum number of bits needed to address 'NUMBER_OF_INPUT_WORDS' size of FIFO.
    localparam bit_num  = clogb2(NUMBER_OF_INPUT_WORDS-1);
    // Define the states of state machine
    // The control state machine oversees the writing of input streaming data to the FIFO,
    // and outputs the streaming data from the FIFO
    parameter [1:0] IDLE = 1'b0,        // This is the initial/idle state 

                    WRITE_FIFO  = 1'b1; // In this state FIFO is written with the
                                        // input stream data S_AXIS_TDATA 
    wire    axis_tready;
    // State variable
    reg mst_exec_state;  
    // FIFO implementation signals
    genvar byte_index;     
    // FIFO write enable
    wire fifo_wren;
    // FIFO full flag
    reg fifo_full_flag;
    // FIFO write pointer
    reg [bit_num-1:0] write_pointer;
    // sink has accepted all the streaming data and stored in FIFO
      reg writes_done;
    // I/O Connections assignments

    assign S_AXIS_TREADY    = axis_tready;
    // Control state machine implementation
    always @(posedge S_AXIS_ACLK) 
    begin  
      if (!S_AXIS_ARESETN) 
      // Synchronous reset (active low)
        begin
          mst_exec_state <= IDLE;
        end  
      else
        case (mst_exec_state)
          IDLE: 
            // The sink starts accepting tdata when 
            // there tvalid is asserted to mark the
            // presence of valid streaming data 
              if (S_AXIS_TVALID)
                begin
                  mst_exec_state <= WRITE_FIFO;
                end
              else
                begin
                  mst_exec_state <= IDLE;
                end
          WRITE_FIFO: 
            // When the sink has accepted all the streaming input data,
            // the interface swiches functionality to a streaming master
            if (writes_done)
              begin
                mst_exec_state <= IDLE;
              end
            else
              begin
                // The sink accepts and stores tdata 
                // into FIFO
                mst_exec_state <= WRITE_FIFO;
              end

        endcase
    end
    // AXI Streaming Sink 
    // 
    // The example design sink is always ready to accept the S_AXIS_TDATA  until
    // the FIFO is not filled with NUMBER_OF_INPUT_WORDS number of input words.
    //assign axis_tready = ((mst_exec_state == WRITE_FIFO) && (write_pointer <= NUMBER_OF_INPUT_WORDS-1)

    assign axis_tready =( (pixel_x>=0 && pixel_x<= 639 && pixel_y>=0 && pixel_y<=479) );

    always@(posedge S_AXIS_ACLK)
    begin
      if(!S_AXIS_ARESETN)
        begin
          write_pointer <= 0;
          writes_done <= 1'b0;
        end  
      else
        if (write_pointer <= NUMBER_OF_INPUT_WORDS-1)
          begin
            if (fifo_wren)
              begin
                // write pointer is incremented after every write to the FIFO
                // when FIFO write signal is enabled.
                write_pointer <= write_pointer + 1;
                writes_done <= 1'b0;
              end
              if ((write_pointer == NUMBER_OF_INPUT_WORDS-1)|| S_AXIS_TLAST)
                begin
                  // reads_done is asserted when NUMBER_OF_INPUT_WORDS numbers of streaming data 
                  // has been written to the FIFO which is also marked by S_AXIS_TLAST(kept for optional usage).
                  writes_done <= 1'b1;
                end
          end  
    end

    // FIFO write enable generation
    assign fifo_wren = S_AXIS_TVALID && axis_tready;

    // FIFO Implementation
    generate 
      for(byte_index=0; byte_index<= (C_S_AXIS_TDATA_WIDTH/8-1); byte_index=byte_index+1)
      begin:FIFO_GEN

        reg  [(C_S_AXIS_TDATA_WIDTH/4)-1:0] stream_data_fifo [0 : NUMBER_OF_INPUT_WORDS-1];

        // Streaming input data is stored in FIFO

        always @( posedge S_AXIS_ACLK )
        begin
          if (fifo_wren)// && S_AXIS_TSTRB[byte_index])
            begin
              stream_data_fifo[write_pointer] <= S_AXIS_TDATA[(byte_index*8+7) -: 8];
            end  
        end  
      end       
    endgenerate

    // Add user logic here

   reg     [9:0] pixel_cnt;
   reg     [9:0] line_cnt;
   reg             v_video_en;
   reg             h_video_en;

   always @(posedge clk or negedge rst_n)
       if(!rst_n)
           begin
               pixel_cnt <= 10'b0;
           end
       else
           begin
               pixel_cnt <= pixel_cnt + 1'b1;
                     if(pixel_cnt == 10'd799 || S_AXIS_TUSER == 1'b1)
                     begin
                            pixel_cnt <= 10'b0;
                     end
           end


    always @(posedge clk or negedge rst_n)
       if(!rst_n)
           begin
                h_video_en <= 1'b1;
                       hsync <= 1'b1;
           end
       else
           begin
               case (pixel_cnt) 
                   10'd0:
                       begin
                           h_video_en <= 1'b1;
                       end
                   10'd639:
                       begin
                           h_video_en <= 1'b0;
                       end 
                   10'd655:
                       begin
                           hsync <= 1'b0;
                       end 
                   10'd751:
                       begin
                           hsync <= 1'b1;
                       end             
               endcase
           end


    always @(posedge clk or negedge rst_n)
       if(!rst_n)
           begin
               line_cnt <= 10'b0;
           end
       else  
           begin
               if(pixel_cnt <= S_AXIS_TLAST)    //pixel_cnt == 10'd799
                   begin
                       line_cnt <= line_cnt + 1'b1;
                   end 

                 if(line_cnt == 10'd524)
                 begin
                       line_cnt <= 10'b0;
                 end 
                   if(S_AXIS_TUSER == 1'b1)
                 begin
                     line_cnt <= 10'b0;                            
                 end
           end

   always @(posedge clk or negedge rst_n)
       if(!rst_n)
           begin
               v_video_en <= 1'b1;
               vsync <= 1'b1;
           end
       else
           begin
               case(line_cnt)
                   10'd0:
                       begin
                           v_video_en <= 1'b1;
                       end 
                   10'd479:
                       begin
                           v_video_en <= 1'b0;
                       end 
                   10'd489:
                       begin
                           vsync <= 1'b0;
                       end 
                   10'd491:
                       begin
                           vsync <= 1'b1;
                       end 
               endcase
           end               

   assign pixel_x = pixel_cnt;
   assign pixel_y = line_cnt;

   assign video_en = ((h_video_en == 1'b1) &&  (v_video_en == 1'b1)); 
    // User logic ends

    endmodule

保存后,按照如图所示操作

这里写图片描述
这里写图片描述
其它的类似,最后在Review and Package,里选择repackage

建立硬件工程

首先要把IP的路径添加进来
在vivado里新建一个Block Design,按照如图所示建立硬件工程,FCLK_CLK0设置成25MHz

这里写图片描述

TPG这样配置

这里写图片描述

约束文件如下
set_property PACKAGE_PIN T22 [get_ports led]
set_property IOSTANDARD LVCMOS33 [get_ports led]

set_property PACKAGE_PIN AA19 [get_ports hsync]
set_property IOSTANDARD LVCMOS33 [get_ports hsync]
set_property PACKAGE_PIN Y19 [get_ports vsync]
set_property IOSTANDARD LVCMOS33 [get_ports vsync]

set_property PACKAGE_PIN Y21 [get_ports {rgb[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {rgb[0]}]
set_property PACKAGE_PIN Y20 [get_ports {rgb[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {rgb[1]}]
set_property PACKAGE_PIN AB20 [get_ports {rgb[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {rgb[2]}]
set_property PACKAGE_PIN AB19 [get_ports {rgb[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {rgb[3]}]

set_property PACKAGE_PIN AB22 [get_ports {rgb[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {rgb[4]}]
set_property PACKAGE_PIN AA22 [get_ports {rgb[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {rgb[5]}]
set_property PACKAGE_PIN AB21 [get_ports {rgb[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {rgb[6]}]
set_property PACKAGE_PIN AA21 [get_ports {rgb[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {rgb[7]}]

set_property PACKAGE_PIN V20 [get_ports {rgb[8]}]
set_property IOSTANDARD LVCMOS33 [get_ports {rgb[8]}]
set_property PACKAGE_PIN U20 [get_ports {rgb[9]}]
set_property IOSTANDARD LVCMOS33 [get_ports {rgb[9]}]
set_property PACKAGE_PIN V19 [get_ports {rgb[10]}]
set_property IOSTANDARD LVCMOS33 [get_ports {rgb[10]}]
set_property PACKAGE_PIN V18 [get_ports {rgb[11]}]
set_property IOSTANDARD LVCMOS33 [get_ports {rgb[11]}]

编译后,导出硬件,新建一个Hello工程(主要是为PL提供25M时钟)

开发板上电测试,效果如下(color bar效果)

这里写图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值