參考文獻
[1]、長弓的堅持
[2]、V3學院
項目簡述
這篇文章我們主要講解AXI_Lite協議,主要內容包括AXI_Lite協議在FPGA中主要起到的作用,遵循的時序要求是什麼,在FPGA中咋麼編寫Verilog代碼。
本次實驗將主要講解AXI_Lite從機的協議,PS端通過AXI_Lite協議寫寄存器控制PL端的LED、通過讀寄存器讀取PL端KEY的按鍵值。 這裏爲什麼講解AXI_Lite從機協議,因爲PS端我們一般作爲主機,那麼需要我們實現的PL端的Verilog代碼自然是從機
本次實驗所用到的軟硬件環境如下:
1、米聯客MZ7015FA開發板
2、VIVADO 2019.1
AXI協議簡述
相信同學們都聽說過AXI協議,現在Xilinx中提出了Block Design的設計思想,而這個設計思想的基礎就是AXI協議。AXI協議起源於AMBA協議協議,2010發佈的AMBA4.0包含了AXI的第二個版本AXI4。現在常見的AXI協議是AXI4版本的協議。AXI4總線協議規定的數據傳輸方式是猝發式的。它的地址/控制和數據相位是分離的,支持不對齊的數據傳輸。在突發傳輸中,使用首字節選通方式,只需要首地址,在獨立的讀寫數據通道,採用獨立的地址、控制和數據週期進行數據傳輸,支持非對齊方式的數據傳輸,能夠發出多個未解析的地址,從而完成無序的數據傳輸交易,並更加容易並行時序收斂。
常用的AXI總線有:AXI4、 AXI_Lite、AXI_Stream。
AXI4:主要面向高性能地址映射通信的需求,允許最大256輪的數據突發傳輸;
AXI4-Lite:是一個輕量級的地址映射單次傳輸接口,佔用很少的邏輯單元;
AXI4-Stream:面向高速流數據傳輸,去掉了地址項,允許無限制的數據突發傳輸規模。
AXI4總線分爲主、從兩端,兩者間可以連續的進行通信。
AXI協議接口簡述
AXI4和AXI4-Lite包含5個不同的通道:
1、 讀地址通道
2、 寫地址通道
3、 讀數據通道
4、 寫數據通道
5、 讀響應通道
數據可以在主從設備間同步的雙向傳輸,並且數據傳輸大小可以改變。AXI4將數據傳輸的突發長度限制爲最大256,AXI4-Lite每次傳輸僅運輸傳輸一個數據。
AXI4-Lite接口和AXI4接口類似,但是不支持AXI4的突發傳輸模式。AXI4-Stream接口僅使用數據通道傳輸數據流,數據突發長度無限。我們先對AXI4與AXI4_Lite的接口信號進行簡要描述,因爲他們的接口信號是一樣的。
1)全局信號
2)寫地址通道信號
3)寫數據通道信號
4)寫響應通道
5)讀地址通道
6)讀數據通道
對於AXI4_Stream協議,該協議只是數據操作,不涉及地址操作,所以信號比較簡單:
上面簡要介紹了AXI4_Lite、AXI4、AXI4_Stream三種協議的信號,其中前兩種協議接口信號一模一樣,只是突發類型不一樣。這也就導致了AXI4_Lite用於配置外部寄存器、配置IP的作用;AXI4用於數據傳輸、DDR的存取;AXI4_Stream用於不同模塊的接口信號。
AXI4協議時序
我們講完了AXI4的接口信號,那麼我們將講解AXI4遵循的時序要求,這裏直接給出AXI4讀寫的時序要求。
AXI4寫時序要求:
AXI4讀時序要求:
知道了接口類型與時序要求,那麼我們便可以根據上面的知識編寫AXI4的協議,下面便以一個例子爲例進行講解。
VIVADO中AXI_Lite的搭建與使用
因爲AXI4協議主要是爲了Block Design的搭建而使用的協議,所以我們也以Block design的搭建爲一個例子。而Block Design的操作是以IP爲基本單元,所以我們得求助於VIVADO的IP封裝工具。當我們打開IP封裝工具的時候,我們會發現裏面給出了AXI4協議的模板,所以我們也就使用上面的模板進行操作。
1、創建IP
2、點擊Next
3、點擊創建一個AXI4封裝的IP
4、填寫IP的名字、版本、描述、目錄等信息
5、進行IP的配置
1、生成IP的名字
2、選擇生成AXI4協議的類型
3、選擇是主機還是從機
4、數據的位寬,對於AXI_Lite協議數據位寬恆定是32個,對於AXI4協議可以是64
5、存儲器的數目,對於AXI_Full協議的從機需要設置
6、寄存器的數目、對於AXI_Lite協議的從機需要設置
然後修改VIVADO給我們提供的AXI4協議歷程
這裏需要注意VIVADO給我們的歷程時基於AXI4_Lite循環測試的歷程,我們進行修改的話,只需要進行如下操作:
1、添加AXI4_Lite主機發送來數據的用途即可
2、修改AXI4_Lite發起讀請求時,根據自己的功能對AXI4_Lite從機的axi_rdata信號即可。
這裏爲了方便大家理解我們給出源代碼:
myip_v1_0模塊:
`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_AXI
parameter integer C_S00_AXI_DATA_WIDTH = 32,
parameter integer C_S00_AXI_ADDR_WIDTH = 4
)
(
// Users to add ports here
input [ 3:0] key ,
output wire [ 3:0] 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
myip_v1_0_S00_AXI # (
.C_S_AXI_DATA_WIDTH(C_S00_AXI_DATA_WIDTH),
.C_S_AXI_ADDR_WIDTH(C_S00_AXI_ADDR_WIDTH)
) myip_v1_0_S00_AXI_inst (
.key (key ),
.led (led ),
.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)
);
// Add user logic here
// User logic ends
endmodule
myip_v1_0_S00_AXI 模塊:
`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author : zhangningning
// Email : [email protected]
// Website : https://blog.csdn.net/zhangningning1996
// Module Name : myip_v1_0_S00_AXI.v
// Create Time : 2020-06-19 12:48:34
// Editor : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date By Version Change Description
// -----------------------------------------------------------------------
// XXXX zhangningning 1.0 Original
//
// *********************************************************************************
module myip_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
input [ 3:0] key ,
output reg [ 3:0] 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;
// 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
always @(*)
// Address decoding for reading registers
case ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )
2'h0 : reg_data_out <= key;
2'h1 : reg_data_out <= ~key;
2'h2 : reg_data_out <= 32'b0101_0101_0101_0101_0101_0101_0101_0101;
2'h3 : reg_data_out <= 32'b1111_1111_1111_1111_0000_0000_0000_0000;
default : reg_data_out <= 0;
endcase
always @( posedge S_AXI_ACLK )
if ( S_AXI_ARESETN == 1'b0 )
led <= 4'b0000;
else if(slv_reg0 != 0)
led <= 4'b1010;
else if(slv_reg1 != 0)
led <= 4'b0101;
else if(slv_reg2 != 0)
led <= 4'b1111;
else if(slv_reg3 != 0)
led <= 4'b0000;
else
led <= led;
// User logic ends
endmodule
我們進行修改的部分如下:
大家可以試着跟着我們的教程來一遍就可以掌握上面的操作,可以掌握VIVADO中利用自帶的IP封裝工具快速建立AXI4的IP。
寫完代碼之後進行IP的封裝:
封裝完IP之後就可以進行Block Design的搭建,如下圖:
然後右擊生成v文件
生成對應的BD設計的工程:
然後生成相應的bit文件進行下載。
PS端操作
上面我們已經建立了PL端的代碼操作,那麼接下來我們進行PS端的代碼編寫。首先我們從生成的硬件平臺文件裏面會發現:
然後我們將上面頭文件與源文件複製到自己建立的工程中去
進行書寫相應的測試代碼,代碼如下:
/******************************************************************************
*
* Copyright (C) 2009 - 2014 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
/*
* helloworld.c: simple test application
*
* This application configures UART 16550 to baud rate 9600.
* PS7 UART (Zynq) is not initialized by this application, since
* bootrom/bsp configures it to baud rate 115200
*
* ------------------------------------------------
* | UART TYPE BAUD RATE |
* ------------------------------------------------
* uartns550 9600
* uartlite Configurable only in HW design
* ps7_uart 115200 (configured by bootrom/bsp)
*/
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "myip.h"
#include <xil_io.h>
#define BaseAddress 0x43C00000
int main()
{
init_platform();
int data;
MYIP_mWriteReg(BaseAddress, MYIP_S00_AXI_SLV_REG0_OFFSET, 1);
MYIP_mWriteReg(BaseAddress, MYIP_S00_AXI_SLV_REG0_OFFSET, 0);
MYIP_mWriteReg(BaseAddress, MYIP_S00_AXI_SLV_REG1_OFFSET, 1);
MYIP_mWriteReg(BaseAddress, MYIP_S00_AXI_SLV_REG1_OFFSET, 0);
MYIP_mWriteReg(BaseAddress, MYIP_S00_AXI_SLV_REG2_OFFSET, 1);
MYIP_mWriteReg(BaseAddress, MYIP_S00_AXI_SLV_REG2_OFFSET, 0);
MYIP_mWriteReg(BaseAddress, MYIP_S00_AXI_SLV_REG3_OFFSET, 1);
MYIP_mWriteReg(BaseAddress, MYIP_S00_AXI_SLV_REG3_OFFSET, 0);
data = MYIP_mReadReg(BaseAddress, MYIP_S00_AXI_SLV_REG0_OFFSET);
data = MYIP_mReadReg(BaseAddress, MYIP_S00_AXI_SLV_REG1_OFFSET);
data = MYIP_mReadReg(BaseAddress, MYIP_S00_AXI_SLV_REG2_OFFSET);
data = MYIP_mReadReg(BaseAddress, MYIP_S00_AXI_SLV_REG3_OFFSET);
print("Hello World\n\r");
cleanup_platform();
return 0;
}
測試結果
進行單步調試可以看出PS與預期的現象是相同的。
從上面的結果可以驗證我們實驗的正確性。
總結
創作不易,認爲文章有幫助的同學們可以關注、點贊、轉發支持。爲行業貢獻及其微小的一部分。或者對文章有什麼看法或者需要更近一步交流的同學,可以加入下面的羣: