请选择 进入手机版 | 继续访问电脑版
[X]关闭
1

11AXI-Lite自定义AXI_GPIO(AXI4总线实战)

摘要: 在前文中我们学习了AXI总线协议,而且通过VIVADO自定义了AXI-LITE总线协议的IP CORE,并且实现了寄存器的读写。 那么在实际的应用中,如果我们ARM的IO不够用了,除了在前文中使用官方自带的AXI-GPIO,我们自己也可 ...

软件版本:vitis2020.2(vivado2020.2)

操作系统:WIN10 64bit

硬件平台:适用XILINX A7/K7/Z7/ZU/KU系列FPGA(米联客(milianke)MZU07A-EG硬件开发平台)

登录"米联客"FPGA社区-www.uisrc.com视频课程、答疑解惑!

11.1概述

在前文中我们学习了AXI总线协议,而且通过VIVADO自定义了AXI-LITE总线协议的IP CORE,并且实现了寄存器的读写。

那么在实际的应用中,如果我们ARM的IO不够用了,除了在前文中使用官方自带的AXI-GPIO,我们自己也可以定义AXI-GPIO IP CORE。

本文实验目的:

1:通过前文的学习,把掌握的自定义AXI-LITE-SLAVE寄存器读写方法,用于引出扩展PL的IO

2:通过VITIS-SDK实现对自定义IP中寄存器的读写访问,以此实现PL IO的控制。

11.2创建IP

11.2.1利用模板创建AXI-Lite IP

1:打开VIVADO软件,新建一个工程。

2:单击ToolsàCreate and Package NEW IP。

3:单击Next,选择Create a new AXI4 peripheral,单击Next。

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

5:NameàS00_AXI;

Interface Type(接口类型)àLite;

Data Width(Bits)(数据位宽)à32位;

Number of Registers(寄存器数量)à4 ;单击next。

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

11.2.2修改IP源码

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

查看生成IP的文件夹

2:现在生成的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


路过

雷人

握手

鲜花

鸡蛋
发表评论

最新评论

引用 uisrc 2021-8-18 20:44
配套源码下载链接:https://pan.baidu.com/s/1TvjOdZvCyDQpS4a7jYivRQ 提取码:1111

查看全部评论(1)

本文作者
2021-8-15 23:41
  • 7
    粉丝
  • 4223
    阅读
  • 1
    回复
  • 1
  • 2
  • 3
热门评论
排行榜