11AXI-Lite自定義AXI_GPIO(AXI4總線實戰)


軟件版本: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

     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

3:雙擊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 

4:進一步修改。去掉"_v1_0"。

  1. GPIO_LITE_ML_v1_0_S00_AXI.v中:

    module GPIO_LITE_ML_v1_0_S00_AXI #修改為à module GPIO_LITE_ML_S00_AXI #

修改后

    

2、GPIO_LITE_ML_v1_0.v中:

module GPIO_LITE_ML_v1_0 # 修改為à module GPIO_LITE_ML #

修改后

GPIO_LITE_ML_v1_0_S00_AXI # 修改為à GPIO_LITE_ML_S00_AXI #

GPIO_LITE_ML_v1_0_S00_AXI_inst 修改為à GPIO_LITE_ML_S00_AXI_inst

修改后

5:修改后,保存。出現如下界面,選擇Automatically pick new top module。

更新后界面

6:重新封裝。選擇ToolsàCreat and Pakage New IP,單擊Next。

7:選擇Package your current project,單擊Next。

路徑選擇原來IP所在的位置,覆蓋原來的文件。

8:選擇Overwrite。

9:選擇Package IPàRewiew and Package àRe-Package IP

自定義IP生成完畢。

11.3硬件電路分析

在功能底板上,PL部分FPGA引腳A21和A18接到了LED上,本文實驗用到這個2個PL GPIO。

11.3.1原理圖

11.3.2fpga_pin.xdc中IO約束

最后的set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design]是為了對fpga的bit進行壓縮,減少bit大小,提高加載速度。

set_property PACKAGE_PIN A21 [get_ports {GPIO_LED[0]}]

set_property IOSTANDARD LVCMOS18 [get_ports {GPIO_LED[0]}]

set_property PACKAGE_PIN A18 [get_ports {GPIO_LED[1]}]

set_property IOSTANDARD LVCMOS18 [get_ports {GPIO_LED[1]}]

11.4搭建SOC系統工程

新建一個名為為zu_prj的工程,之后創建一個BD文件,並命名為system,添加並且配置好ZYNQ Ultrascale+ MPSOC IP。讀者需要根據自己的硬件類型配置好輸入時鍾頻率、內存型號、串口,連接時鍾等。新手不清楚這些內容個,請參考"3-2-01_ex_soc_base_07a-eg .pdf" "01 HelloWold/DDR/網口測試"這篇文章。

11.4.1PS部分設置

1:PS復位設置

2:PS LPD設置

3:PL輸出時鍾設置

11.4.2添加自定義AXI-Lite IP

1:設置IP路徑

本文中是我們第一次在BD圖形化設計中添加自定義的IP,自定義的IP需要設置IP路徑才能被識別到。默認情況下,我們自定的IP在配套工程的uisrc/ip路徑下:

2:添加IP

11.4.3PL圖像化編程

11.4.4設置地址分配

11.4.5編譯並導出平台文件

1:單擊Block文件à右鍵àGenerate the Output ProductsàGlobalàGenerate。

2:單擊Block文件à右鍵à Create a HDL wrapper(生成HDL頂層文件)àLet vivado manager wrapper and auto-update(自動更新)。

3:生成Bit文件。

4:導出到硬件: FileàExport HardwareàInclude bitstream

5:導出完成后,對應工程路徑的zu_hw路徑下有硬件平台文件:system_wrapper.xsa的文件。根據硬件平台文件system_wrapper.xsa來創建需要Platform平台。

11.5搭建Vitis-sdk工程

創建zu_base sdk platform和APP工程的過程不再重復,可以閱讀本章節01~05相關demo。以下給出創建好zu_base sdk platform的截圖和對應工程APP的截圖。

11.5.1創建SDK Platform工程

11.5.2創建axi_lite_gpio_test APP工程

11.6程序分析

XGpio_axi_WriteReg()函數實現的是向AXI的寄存器中寫入數據,它的三個參數分別為基地址,偏移量和數據。需要注意的是此處的偏移量,AXI的相鄰寄存器偏移量相差4個字節,默認slv_reg0的偏移量是0,因此,可以推導出slv_reg1,slv_reg2的偏移量分別為4和8,本課中,我們只用到了slv_reg0,所以偏移量為0。

11.7實驗結果


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM