[X]关闭
0

S02-CH16 自定义IP User_GPIO实验

摘要: 软件版本:VIVADO2017.4操作系统:WIN10 64bit硬件平台:适用米联客 ZYNQ系列开发板米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!!16.1 概述 ZYNQ开发过程中,有时会需要与ARM硬核进行通信 ...

软件版本:VIVADO2017.4

操作系统:WIN10 64bit

硬件平台:适用米联客 ZYNQ系列开发板

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

16.1 概述

      ZYNQ开发过程中,有时会需要与ARM硬核进行通信。这种情况下,需要用到高速接口与ARM通信。本课讲解如何创建一个基于高速AXI总线接口的自定义IP,并使用这个IP实现流水灯功能。通过这种方法,我们可以在GPIO资源缺乏的情况下,利用PL的资源来扩充GPIO资源。在实际开发中,有非常重要的意义,大家可以根据这种方法,自行设计其他带AXI总线接口的自定义IP。

16.2 创建IP

Step4:输入要创建的IP名字,此处命名为GPIO_LITE_ML,选择保存路径,单击Next。

Step6:选择Edit IP,点击Finish按钮。软件自动打开一个编辑IP的工程,即edit_GPIO_LITE_ML_V1_0.xpr工程。

Step7:打开的edit_GPIO_LITE_ML_V1_0.xpr工程界面如下。

查看生成IP的文件夹

Step8:现在生成的IP需要进行修改才能满足我们使用需求。选中Project Manager,双击GPIO_LITE_ML_v1_0_S00_AXI_inst,做如下更改。

修改1:

修改2:

将slv_reg0的值赋值给了用户输出逻辑,当我们向slv_reg0写入数据的时候,也就相当于向GPIO_LED赋值。

更改后的文件如下所示。

`timescale 1 ns / 1 ps


module GPIO_LITE_ML_v1_0_S00_AXI #

(

// Users to add parameters here


// User parameters ends

// Do not modify the parameters beyond this line


// Width of S_AXI data bus

parameter integer C_S_AXI_DATA_WIDTH = 32,

// Width of S_AXI address bus

parameter integer C_S_AXI_ADDR_WIDTH = 4

)

(

// Users to add ports here

        output wire [3:0]GPIO_LED,

// User ports ends

// Do not modify the ports beyond this line


// Global Clock Signal

input wire  S_AXI_ACLK,

// Global Reset Signal. This Signal is Active LOW

input wire  S_AXI_ARESETN,

// Write address (issued by master, acceped by Slave)

input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR,

// Write channel Protection type. This signal indicates the

     // privilege and security level of the transaction, and whether

     // the transaction is a data access or an instruction access.

input wire [2 : 0] S_AXI_AWPROT,

// Write address valid. This signal indicates that the master signaling

     // valid write address and control information.

input wire  S_AXI_AWVALID,

// Write address ready. This signal indicates that the slave is ready

     // to accept an address and associated control signals.

output wire  S_AXI_AWREADY,

// Write data (issued by master, acceped by Slave)

input wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA,

// Write strobes. This signal indicates which byte lanes hold

     // valid data. There is one write strobe bit for each eight

     // bits of the write data bus.    

input wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] S_AXI_WSTRB,

// Write valid. This signal indicates that valid write

     // data and strobes are available.

input wire  S_AXI_WVALID,

// Write ready. This signal indicates that the slave

     // can accept the write data.

output wire  S_AXI_WREADY,

// Write response. This signal indicates the status

     // of the write transaction.

output wire [1 : 0] S_AXI_BRESP,

// Write response valid. This signal indicates that the channel

     // is signaling a valid write response.

output wire  S_AXI_BVALID,

// Response ready. This signal indicates that the master

     // can accept a write response.

input wire  S_AXI_BREADY,

// Read address (issued by master, acceped by Slave)

input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR,

// Protection type. This signal indicates the privilege

     // and security level of the transaction, and whether the

     // transaction is a data access or an instruction access.

input wire [2 : 0] S_AXI_ARPROT,

// Read address valid. This signal indicates that the channel

     // is signaling valid read address and control information.

input wire  S_AXI_ARVALID,

// Read address ready. This signal indicates that the slave is

     // ready to accept an address and associated control signals.

output wire  S_AXI_ARREADY,

// Read data (issued by slave)

output wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA,

// Read response. This signal indicates the status of the

     // read transfer.

output wire [1 : 0] S_AXI_RRESP,

// Read valid. This signal indicates that the channel is

     // signaling the required read data.

output wire  S_AXI_RVALID,

// Read ready. This signal indicates that the master can

     // accept the read data and response information.

input wire  S_AXI_RREADY

);


// AXI4LITE signals

reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_awaddr;

reg   axi_awready;

reg   axi_wready;

reg [1 : 0] axi_bresp;

reg   axi_bvalid;

reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_araddr;

reg   axi_arready;

reg [C_S_AXI_DATA_WIDTH-1 : 0] axi_rdata;

reg [1 : 0] axi_rresp;

reg   axi_rvalid;


// Example-specific design signals

// local parameter for addressing 32 bit / 64 bit C_S_AXI_DATA_WIDTH

// ADDR_LSB is used for addressing 32/64 bit registers/memories

// ADDR_LSB = 2 for 32 bits (n downto 2)

// ADDR_LSB = 3 for 64 bits (n downto 3)

localparam integer ADDR_LSB = (C_S_AXI_DATA_WIDTH/32) + 1;

localparam integer OPT_MEM_ADDR_BITS = 1;

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

//-- Signals for user logic register space example

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

//-- Number of Slave Registers 4

reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg0;

reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg1;

reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg2;

reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg3;

wire  slv_reg_rden;

wire  slv_reg_wren;

reg [C_S_AXI_DATA_WIDTH-1:0]  reg_data_out;

integer  byte_index;

reg  aw_en;


// I/O Connections assignments


assign S_AXI_AWREADY = axi_awready;

assign S_AXI_WREADY = axi_wready;

assign S_AXI_BRESP = axi_bresp;

assign S_AXI_BVALID = axi_bvalid;

assign S_AXI_ARREADY = axi_arready;

assign S_AXI_RDATA = axi_rdata;

assign S_AXI_RRESP = axi_rresp;

assign S_AXI_RVALID = axi_rvalid;

// Implement axi_awready generation

// axi_awready is asserted for one S_AXI_ACLK clock cycle when both

// S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_awready is

// de-asserted when reset is low.


always @( posedge S_AXI_ACLK )

begin

  if ( S_AXI_ARESETN == 1'b0 )

    begin

      axi_awready <= 1'b0;

      aw_en <= 1'b1;

    end

  else

    begin    

      if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID && aw_en)

        begin

          // slave is ready to accept write address when

          // there is a valid write address and write data

          // on the write address and data bus. This design

          // expects no outstanding transactions.

          axi_awready <= 1'b1;

          aw_en <= 1'b0;

        end

        else if (S_AXI_BREADY && axi_bvalid)

            begin

              aw_en <= 1'b1;

              axi_awready <= 1'b0;

            end

      else           

        begin

          axi_awready <= 1'b0;

        end

    end

end       


// Implement axi_awaddr latching

// This process is used to latch the address when both

// S_AXI_AWVALID and S_AXI_WVALID are valid.


always @( posedge S_AXI_ACLK )

begin

  if ( S_AXI_ARESETN == 1'b0 )

    begin

      axi_awaddr <= 0;

    end

  else

    begin    

      if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID && aw_en)

        begin

          // Write Address latching

          axi_awaddr <= S_AXI_AWADDR;

        end

    end

end       


// Implement axi_wready generation

// axi_wready is asserted for one S_AXI_ACLK clock cycle when both

// S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_wready is

// de-asserted when reset is low.


always @( posedge S_AXI_ACLK )

begin

  if ( S_AXI_ARESETN == 1'b0 )

    begin

      axi_wready <= 1'b0;

    end

  else

    begin    

      if (~axi_wready && S_AXI_WVALID && S_AXI_AWVALID && aw_en )

        begin

          // slave is ready to accept write data when

          // there is a valid write address and write data

          // on the write address and data bus. This design

          // expects no outstanding transactions.

          axi_wready <= 1'b1;

        end

      else

        begin

          axi_wready <= 1'b0;

        end

    end

end       


// Implement memory mapped register select and write logic generation

// The write data is accepted and written to memory mapped registers when

// axi_awready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted. Write strobes are used to

// select byte enables of slave registers while writing.

// These registers are cleared when reset (active low) is applied.

// Slave register write enable is asserted when valid address and data are available

// and the slave is ready to accept the write address and write data.

assign slv_reg_wren = axi_wready && S_AXI_WVALID && axi_awready && S_AXI_AWVALID;


always @( posedge S_AXI_ACLK )

begin

  if ( S_AXI_ARESETN == 1'b0 )

    begin

      slv_reg0 <= 0;

      slv_reg1 <= 0;

      slv_reg2 <= 0;

      slv_reg3 <= 0;

    end

  else begin

    if (slv_reg_wren)

      begin

        case ( axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )

          2'h0:

            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

              if ( S_AXI_WSTRB[byte_index] == 1 ) begin

                // Respective byte enables are asserted as per write strobes

                // Slave register 0

                slv_reg0[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];

              end  

          2'h1:

            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

              if ( S_AXI_WSTRB[byte_index] == 1 ) begin

                // Respective byte enables are asserted as per write strobes

                // Slave register 1

                slv_reg1[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];

              end  

          2'h2:

            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

              if ( S_AXI_WSTRB[byte_index] == 1 ) begin

                // Respective byte enables are asserted as per write strobes

                // Slave register 2

                slv_reg2[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];

              end  

          2'h3:

            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

              if ( S_AXI_WSTRB[byte_index] == 1 ) begin

                // Respective byte enables are asserted as per write strobes

                // Slave register 3

                slv_reg3[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];

              end  

          default : begin

                      slv_reg0 <= slv_reg0;

                      slv_reg1 <= slv_reg1;

                      slv_reg2 <= slv_reg2;

                      slv_reg3 <= slv_reg3;

                    end

        endcase

      end

  end

end    


// Implement write response logic generation

// The write response and response valid signals are asserted by the slave

// when axi_wready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted.  

// This marks the acceptance of address and indicates the status of

// write transaction.


always @( posedge S_AXI_ACLK )

begin

  if ( S_AXI_ARESETN == 1'b0 )

    begin

      axi_bvalid  <= 0;

      axi_bresp   <= 2'b0;

    end

  else

    begin    

      if (axi_awready && S_AXI_AWVALID && ~axi_bvalid && axi_wready && S_AXI_WVALID)

        begin

          // indicates a valid write response is available

          axi_bvalid <= 1'b1;

          axi_bresp  <= 2'b0; // 'OKAY' response

        end                   // work error responses in future

      else

        begin

          if (S_AXI_BREADY && axi_bvalid)

            //check if bready is asserted while bvalid is high)

            //(there is a possibility that bready is always asserted high)   

            begin

              axi_bvalid <= 1'b0;

            end  

        end

    end

end   


// Implement axi_arready generation

// axi_arready is asserted for one S_AXI_ACLK clock cycle when

// S_AXI_ARVALID is asserted. axi_awready is

// de-asserted when reset (active low) is asserted.

// The read address is also latched when S_AXI_ARVALID is

// asserted. axi_araddr is reset to zero on reset assertion.


always @( posedge S_AXI_ACLK )

begin

  if ( S_AXI_ARESETN == 1'b0 )

    begin

      axi_arready <= 1'b0;

      axi_araddr  <= 32'b0;

    end

  else

    begin    

      if (~axi_arready && S_AXI_ARVALID)

        begin

          // indicates that the slave has acceped the valid read address

          axi_arready <= 1'b1;

          // Read address latching

          axi_araddr  <= S_AXI_ARADDR;

        end

      else

        begin

          axi_arready <= 1'b0;

        end

    end

end       


// Implement axi_arvalid generation

// axi_rvalid is asserted for one S_AXI_ACLK clock cycle when both

// S_AXI_ARVALID and axi_arready are asserted. The slave registers

// data are available on the axi_rdata bus at this instance. The

// assertion of axi_rvalid marks the validity of read data on the

// bus and axi_rresp indicates the status of read transaction.axi_rvalid

// is deasserted on reset (active low). axi_rresp and axi_rdata are

// cleared to zero on reset (active low).  

always @( posedge S_AXI_ACLK )

begin

  if ( S_AXI_ARESETN == 1'b0 )

    begin

      axi_rvalid <= 0;

      axi_rresp  <= 0;

    end

  else

    begin    

      if (axi_arready && S_AXI_ARVALID && ~axi_rvalid)

        begin

          // Valid read data is available at the read data bus

          axi_rvalid <= 1'b1;

          axi_rresp  <= 2'b0; // 'OKAY' response

        end   

      else if (axi_rvalid && S_AXI_RREADY)

        begin

          // Read data is accepted by the master

          axi_rvalid <= 1'b0;

        end                

    end

end    


// Implement memory mapped register select and read logic generation

// Slave register read enable is asserted when valid address is available

// and the slave is ready to accept the read address.

assign slv_reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid;

always @(*)

begin

      // Address decoding for reading registers

      case ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )

        2'h0   : reg_data_out <= slv_reg0;

        2'h1   : reg_data_out <= slv_reg1;

        2'h2   : reg_data_out <= slv_reg2;

        2'h3   : reg_data_out <= slv_reg3;

        default : reg_data_out <= 0;

      endcase

end


// Output register or memory read data

always @( posedge S_AXI_ACLK )

begin

  if ( S_AXI_ARESETN == 1'b0 )

    begin

      axi_rdata  <= 0;

    end

  else

    begin    

      // When there is a valid read address (S_AXI_ARVALID) with

      // acceptance of read address by the slave (axi_arready),

      // output the read dada

      if (slv_reg_rden)

        begin

          axi_rdata <= reg_data_out;     // register read data

        end   

    end

end    


// Add user logic here

    assign GPIO_LED[3:0] = slv_reg0[3:0];

// User logic ends


endmodule


Step9 双击GPIO_LITE_ML_v1_0文件,做如下修改。

修改1:

修改2:

修改后的文件如下。

`timescale 1 ns / 1 ps


module GPIO_LITE_ML_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_AXI

parameter integer C_S00_AXI_DATA_WIDTH = 32,

parameter integer C_S00_AXI_ADDR_WIDTH = 4

)

(

// Users to add ports here

        output wire [3:0]GPIO_LED,

// User ports ends

// Do not modify the ports beyond this line



// Ports of Axi Slave Bus Interface S00_AXI

input wire  s00_axi_aclk,

input wire  s00_axi_aresetn,

input wire [C_S00_AXI_ADDR_WIDTH-1 : 0] s00_axi_awaddr,

input wire [2 : 0] s00_axi_awprot,

input wire  s00_axi_awvalid,

output wire  s00_axi_awready,

input wire [C_S00_AXI_DATA_WIDTH-1 : 0] s00_axi_wdata,

input wire [(C_S00_AXI_DATA_WIDTH/8)-1 : 0] s00_axi_wstrb,

input wire  s00_axi_wvalid,

output wire  s00_axi_wready,

output wire [1 : 0] s00_axi_bresp,

output wire  s00_axi_bvalid,

input wire  s00_axi_bready,

input wire [C_S00_AXI_ADDR_WIDTH-1 : 0] s00_axi_araddr,

input wire [2 : 0] s00_axi_arprot,

input wire  s00_axi_arvalid,

output wire  s00_axi_arready,

output wire [C_S00_AXI_DATA_WIDTH-1 : 0] s00_axi_rdata,

output wire [1 : 0] s00_axi_rresp,

output wire  s00_axi_rvalid,

input wire  s00_axi_rready

);

// Instantiation of Axi Bus Interface S00_AXI

GPIO_LITE_ML_v1_0_S00_AXI # (

.C_S_AXI_DATA_WIDTH(C_S00_AXI_DATA_WIDTH),

.C_S_AXI_ADDR_WIDTH(C_S00_AXI_ADDR_WIDTH)

) GPIO_LITE_ML_v1_0_S00_AXI_inst (

.S_AXI_ACLK(s00_axi_aclk),

.S_AXI_ARESETN(s00_axi_aresetn),

.S_AXI_AWADDR(s00_axi_awaddr),

.S_AXI_AWPROT(s00_axi_awprot),

.S_AXI_AWVALID(s00_axi_awvalid),

.S_AXI_AWREADY(s00_axi_awready),

.S_AXI_WDATA(s00_axi_wdata),

.S_AXI_WSTRB(s00_axi_wstrb),

.S_AXI_WVALID(s00_axi_wvalid),

.S_AXI_WREADY(s00_axi_wready),

.S_AXI_BRESP(s00_axi_bresp),

.S_AXI_BVALID(s00_axi_bvalid),

.S_AXI_BREADY(s00_axi_bready),

.S_AXI_ARADDR(s00_axi_araddr),

.S_AXI_ARPROT(s00_axi_arprot),

.S_AXI_ARVALID(s00_axi_arvalid),

.S_AXI_ARREADY(s00_axi_arready),

.S_AXI_RDATA(s00_axi_rdata),

.S_AXI_RRESP(s00_axi_rresp),

.S_AXI_RVALID(s00_axi_rvalid),

.S_AXI_RREADY(s00_axi_rready),

.GPIO_LED(GPIO_LED)

);


// Add user logic here


// User logic ends


endmodule

Step10:进一步修改。去掉“_v1_0”。

  1. GPIO_LITE_ML_v1_0_S00_AXI.v中:

更新后界面

路径选择原来IP所在的位置,覆盖原来的文件。

Step14:选择Overwrite。

自定义IP生成完毕。

16.3 搭建FPGA BD工程

Step1:新建一个VIVADO工程,根据自己的开发板正确配置芯片型号。

Step2:将封装好的自定义IP路径添加到工程。

Step3:新建一个BD文件。

Step4:向BD文件中添加一个ZYNQ Processing system IP,根据自身硬件完成IP的配置。

Step5:添加自定义IP的模块名到BD文件中。

 Step6:直接点击Run connection automation。点击OK。

Step7:选中GPIO_LED端口,按Ctrl+T引出端口,整体硬件电路如下。

16.4 加载到SDK

Step1:创建一个新的空工程。

Step2:将提供例程中SDK工程的main.c源文件复制,并粘贴到新建SDK工程。

Step3:右击工程,选择Debug as ->Debug configurations。

Step4:选中system Debugger,双击创建一个系统调试,点击Apply,点击Debug。

Step5:点击运行按钮,可以看到LED流水灯工作

16.5 程序分析

      XGpio_axi_WriteReg()函数实现的是向AXI的寄存器中写入数据,它的三个参数分别为基地址,偏移量和数据。需要注意的是此处的偏移量,AXI的相邻寄存器偏移量相差4个字节,默认slv_reg0的偏移量是0,因此,可以推导出slv_reg1,slv_reg2的偏移量分别为4和8,本课中,我们只用到了slv_reg0,所以偏移量为0。


路过

雷人

握手

鲜花

鸡蛋

最新评论

本文作者
2019-9-6 19:26
  • 7
    粉丝
  • 2024
    阅读
  • 0
    回复

关注米联客

扫描关注,了解最新资讯

联系人:汤经理
电话:0519-80699907
EMAIL:270682667@qq.com
地址:常州溧阳市天目云谷3号楼北楼201B
热门评论
排行榜