以下内容仅记录本人工作中发现的问题以及解决方法,仅供参考。

        文章记录了作者在基于zynq平台PL与PS的数据交互开发过程中,总结的AXI4_LITE通信协议开发经验,并在文章中详细介绍了VIVADO软件中AXI4_LITE IP核的生成、测试版本及正式版本工程BD(BLOCK DESIGN)的搭建、从机PL端AXI4_LITE IP核的协议层代码开发、主机PS端应用层的代码开发、仿真测试工程以及上板工程的完整代码及测试结果。

         本文着重介绍PL与PS的AXI4-Lite协议交互,AXI4-Lite协议的PL端应用开发详见另一篇笔记:vivado PL端串口通信协议及AXI_Uartlite (2.0)IP驱动开发​​​​https://blog.csdn.net/weixin_46168087/article/details/155612353?spm=1001.2014.3001.5502

目录

一、AXI4_LITE协议概述

1.AXI4-LITE协议接口

2.AXI4-Lite 写数据工作流程  

3.AXI4-Lite 读数据 工作流程

二、AXI4_LITE IP核

1.AXI4-Lite IP核的生成  

2.AXI4-Lite IP核的应用

三、仿真测试工程

四、在线测试工程

一、AXI4_LITE协议概述

        AXI协议官方下载链接:https://developer.arm.com/documentation/ihi0022/latest

        AXI4-Lite 是 AXI4 协议的轻量级子集,专为低速、低带宽的控制类交互设计(如寄存器读写、外设配置),是 Zynq-7000中 PS与 PL通信的核心总线之一,也是嵌入式硬件开发中最常用的 AXI 子协议。

协议 适用场景 核心差异
AXI4-Lite 低速控制(寄存器读写) 无突发、固定 32/64 位、轻量
AXI4 高速数据传输(如 DDR) 支持突发(最大 256 拍)、缓存
AXI-Stream 流式数据(如视频 / 音频) 无地址、连续数据流、低延迟

1.AXI4-LITE协议接口

         AXI4-Lite 包括全局时钟复位和 5 个独立通道(写地址/写数据/写响应/读地址/读数据通道),主设备(如 Zynq PS)发起请求,从设备(如 PL 自定义 IP)响应,AXI4-Lite协议接口如下:

序号 类型 命名 位宽(bit) 输入/输出 定义
1 全局信号 ACLK 1 input 时钟
2 ARESET 1 input 复位:低有效
3 写地址通道 AWVALID 1 input 写地址有效位:高有效
4 AWREADY 1 output 从机写地址通道准备就绪信号:高有效
5 AWDATA 4 input 写地址
7 写数据通道 WVALID 1 input 写数据有效位:高有效
8 WREADY 1 output 从机写数据通道准备就绪信号:高有效
9 WDATA 32 input 写数据
10 WSTRB 4 input

写数据选择:bit[0]=1=data[7:0]

bit[1]=1=data[15:8]以此类推,默认全高

11 写响应通道 BVALID 1 output 写入响应有效位:高有效
12 BREADY 1 input 主机接收响应通道准备就绪信号:高有效
13 BRESP 2 output 写响应状态(一般不用)
14 读地址通道 ARVALID 1 input 读地址有效位:高有效
15 ARREADY 1 output 从机读地址通道准备就绪信号:高有效
16 ARDATA 4 input 读地址
18 读数据通道 RVALID 1 output 读数据有效位:高有效
19 RREADY 1 input 主机读数据通道准备就绪信号:高有效
20 RDATA 32 output 读数据
21 RRESP 2 output 读响应状态(00 = 成功,一般不用)

2.AXI4-Lite 写数据工作流程  

        写入、读取之间存在通道依赖关系。读写流程示意图中的单向箭头表示可在箭头起点信号前或后触发的信号。双向箭头表示必须在箭头起点信号触发后才能触发的信号。

        根据写数据流程图可知,写数据只与三个通道有关,写地址通道/写数据通道/写响应通道,简单概括一下写数据的流程为:

        step1:写入数据(WDATA)、写入地址(AWDATA)、写数据有效位拉高(WVALID)、写地址有效位拉高(AWVALID)

        step2:等待从机写数据通道准备就绪(WREADY)、等待从机写地址通道准备就绪(AWREADY)

        step3:等待写入响应有效(BVALID)、主机接收响应通道准备就绪信号拉高(BREADY)、返回step1循环

3.AXI4-Lite 读数据 工作流程

       根据读数据流程图可知,读数据只与两个通道有关,读地址通道/读数据通道,简单概括一下读数据的流程为::

        step1:写入读地址(ARDATA)、读地址有效位拉高(WVALID)

        step2:等待从机读地址通道准备就绪(ARREADY)

        step3:主机读数据通道准备就绪信号拉高(RREADY)

        step4:等待从机读数据有效位拉高(RVALID)、提取数据(RDATA)、返回step1循环

二、AXI4_LITE IP核

1.AXI4-Lite IP核的生成  

        打开vivado软件,点击Tools下拉选项,点击Create and Package New IP。

        点击next。

        这里选择IP存放的路径,以及更改自定义IP的命名为axi4_lite_slave。

        接口模式选择从机模式,寄存器数量先随便写4,后面再改。

        选择编辑IP,进行下一步根据实际应用来更改IP。

2.AXI4-Lite IP核的应用

        在上一章节点击完成后可以看到IP编辑界面已经打开,IP已经生成,观察代码可以发现读数据状态机的内容,即为重复4个寄存器的读写,若前面设置寄存器数量为128个,则状态机会重复128次。

        简化状态机,以及根据自己的需求定义读写数据寄存器的个数,定义AXI4_lite协议的基地址,将需要读出的值提出来,需要写入的值发出去,就是本节IP核的应用中改造这段代码的目的。

        本实验自定义PL端从地址0x43c00000中读取来自PS端的6个32位的数data_out0~data_out5,PL端向PS端给地址0x43c00000写入4个32位的数data_in0~data_in3。

        更改后的axi4_lite_slave_v1_0_S00_AXI.v文件:

module axi4_lite_slave_v1_0_S00_AXI  #(
    parameter integer C_S_AXI_DATA_WIDTH	= 32,
    parameter integer C_S_AXI_ADDR_WIDTH	= 32,
    parameter integer S_AXI_RD_DATA_DEPTH   = 6,
    parameter integer S_AXI_WR_DATA_DEPTH   = 4,
    parameter integer S_AXI_RDADDR_BASE     = 32'h43c00000	 
)(
    input  wire                                 S_AXI_ACLK     ,
    input  wire                                 S_AXI_ARESETN  ,
    input  wire [C_S_AXI_ADDR_WIDTH-1 : 0]      S_AXI_AWADDR   ,
    input  wire [2 : 0]                         S_AXI_AWPROT   ,
    input  wire                                 S_AXI_AWVALID  ,
    output wire                                 S_AXI_AWREADY  ,
    input  wire [C_S_AXI_DATA_WIDTH-1 : 0]      S_AXI_WDATA    ,
    input  wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0]  S_AXI_WSTRB    ,
    input  wire                                 S_AXI_WVALID   ,
    output wire                                 S_AXI_WREADY   ,
    output wire [1 : 0]                         S_AXI_BRESP    ,
    output wire                                 S_AXI_BVALID   ,
    input  wire                                 S_AXI_BREADY   ,
    input  wire [C_S_AXI_ADDR_WIDTH-1 : 0]      S_AXI_ARADDR   ,
    input  wire [2 : 0]                         S_AXI_ARPROT   ,
    input  wire                                 S_AXI_ARVALID  ,
    output wire                                 S_AXI_ARREADY  ,
    output wire [C_S_AXI_DATA_WIDTH-1 : 0]      S_AXI_RDATA    ,
    output wire [1 : 0]                         S_AXI_RRESP    ,
    output wire                                 S_AXI_RVALID   ,
    input  wire                                 S_AXI_RREADY   ,
    input  wire [31:0]                          data_in0       ,          
    input  wire [31:0]                          data_in1       ,
    input  wire [31:0]                          data_in2       ,
    input  wire [31:0]                          data_in3       ,
    output wire [31:0]                          data_out0      ,
    output wire [31:0]                          data_out1      ,
    output wire [31:0]                          data_out2      ,
    output wire [31:0]                          data_out3      ,
    output wire [31:0]                          data_out4      ,
    output wire [31:0]                          data_out5       

);

function integer clogb2 (input integer bit_depth);              
    begin                                                           
        for(clogb2=0; bit_depth>0; clogb2=clogb2+1)                   
            bit_depth = bit_depth >> 1;                                 
    end                                                           
endfunction    
                                                 
localparam integer ADDR_LSB = (C_S_AXI_DATA_WIDTH/32) + 1;
localparam integer ADDR_HSB = clogb2(S_AXI_RD_DATA_DEPTH-1)+ADDR_LSB;	 

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;
reg [C_S_AXI_DATA_WIDTH-1:0]	 slv_reg [0:S_AXI_RD_DATA_DEPTH-1];
wire	                         slv_reg_rden;
wire	                         slv_reg_wren;
integer	                         byte_index;
reg	                             aw_en;
wire  [7:0]                      write_index;
wire  [7:0]                      read_index ;
assign write_index               = axi_awaddr[ADDR_HSB:ADDR_LSB];
assign read_index                = axi_araddr[ADDR_HSB:ADDR_LSB];
assign slv_reg_wren              = axi_wready && S_AXI_WVALID && axi_awready && S_AXI_AWVALID;
assign slv_reg_rden              = axi_arready & S_AXI_ARVALID & ~axi_rvalid;
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;

assign data_out0                 = slv_reg[0];
assign data_out1                 = slv_reg[1];
assign data_out2                 = slv_reg[2];
assign data_out3                 = slv_reg[3];
assign data_out4                 = slv_reg[4];
assign data_out5                 = slv_reg[5];

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
            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       

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
            axi_awaddr <= S_AXI_AWADDR;
        end
    end 
end       

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
            axi_wready <= 1'b1;
        end
        else begin
            axi_wready <= 1'b0;
        end
    end 
end       


	
reg  [7:0] slv_reg_cnt;
always @( posedge S_AXI_ACLK )begin
    if ( S_AXI_ARESETN == 1'b0 )begin
        for(slv_reg_cnt=0;slv_reg_cnt<S_AXI_RD_DATA_DEPTH;slv_reg_cnt = slv_reg_cnt+1)
            slv_reg[slv_reg_cnt] <= 0;
        end 
        else begin
        if (slv_reg_wren)begin
            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
                slv_reg[write_index][(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
            end 
        end
    end
end    


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
            axi_bvalid <= 1'b1;
            axi_bresp  <= 2'b0; 
        end                 
        else begin
            if (S_AXI_BREADY && axi_bvalid) begin
                axi_bvalid <= 1'b0; 
            end  
        end
    end
end   

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
            axi_arready <= 1'b1;
            axi_araddr  <= S_AXI_ARADDR;
        end
        else begin
            axi_arready <= 1'b0;
        end
    end 
end       

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
            axi_rvalid <= 1'b1;
            axi_rresp  <= 2'b0;
        end   
        else if (axi_rvalid && S_AXI_RREADY)begin
            axi_rvalid <= 1'b0;
        end                
    end
end    
  
always@(posedge S_AXI_ACLK or negedge S_AXI_ARESETN)begin                                                                             
    if (!S_AXI_ARESETN)begin                                                                                                               
        axi_rdata      <= 'd0;
    end                                                                           
    else begin      
        if (slv_reg_rden)begin
            case(axi_araddr)
                32'h43c00000 :begin axi_rdata <= data_in0     ;end
                32'h43c00004 :begin axi_rdata <= data_in1     ;end
                32'h43c00008 :begin axi_rdata <= data_in2     ;end
                32'h43c0000C :begin axi_rdata <= data_in3     ;end
                default      :begin axi_rdata <= axi_rdata;    end     
            endcase
        end  
    end
end
           
endmodule

        更改后的axi4_lite_slave_v1_0.v文件:


`timescale 1 ns / 1 ps

	module axi4_lite_slave_v1_0 #
	(
    parameter integer C_S_AXI_DATA_WIDTH	= 32,
    parameter integer C_S_AXI_ADDR_WIDTH	= 32,
    parameter integer S_AXI_RD_DATA_DEPTH   = 6,
    parameter integer S_AXI_WR_DATA_DEPTH   = 4,
    parameter integer S_AXI_RDADDR_BASE     = 32'h43c00000	 
	)
	(

		input wire  s00_axi_aclk,
		input wire  s00_axi_aresetn,
		input wire [C_S_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_S_AXI_DATA_WIDTH-1 : 0] s00_axi_wdata,
		input wire [(C_S_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_S_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_S_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,
        input  wire [31:0]                          data_in0       ,          
        input  wire [31:0]                          data_in1       ,
        input  wire [31:0]                          data_in2       ,
        input  wire [31:0]                          data_in3       ,
        output wire [31:0]                          data_out0      ,
        output wire [31:0]                          data_out1      ,
        output wire [31:0]                          data_out2      ,
        output wire [31:0]                          data_out3      ,
        output wire [31:0]                          data_out4      ,
        output wire [31:0]                          data_out5       
	);
// Instantiation of Axi Bus Interface S00_AXI
	axi4_lite_slave_v1_0_S00_AXI # ( 
         .C_S_AXI_DATA_WIDTH	(C_S_AXI_DATA_WIDTH	),
         .C_S_AXI_ADDR_WIDTH	(C_S_AXI_ADDR_WIDTH	),
         .S_AXI_RD_DATA_DEPTH   (S_AXI_RD_DATA_DEPTH),
         .S_AXI_WR_DATA_DEPTH   (S_AXI_WR_DATA_DEPTH),
         .S_AXI_RDADDR_BASE     (S_AXI_RDADDR_BASE  )
	) axi4_lite_slave_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),
		.data_in0   (data_in0   ),
		.data_in1   (data_in1   ),
		.data_in2   (data_in2   ),
		.data_in3   (data_in3   ),
		.data_out0  (data_out0  ),
		.data_out1  (data_out1  ),
		.data_out2  (data_out2  ),
		.data_out3  (data_out3  ),
		.data_out4  (data_out4  ),
		.data_out5  (data_out5  )
		
	);


	endmodule

        改完代码后,回到IP封装界面如图:

        将自定义的参数(读写数据位宽、寄存器深度、读写基地址)拖到可视窗口界面,在BD中即可实时更改IP参数。

        点击重新生成IP,退出IP编辑界面。按照下图所示,可以看到IP路径已经自动添加进工程,更新一下IP。

        回到BD,点击加号,输入IP命名,在BD中添加上一步生成的IP。

        双击IP ,可以看到刚刚添加到可视窗口的参数编辑界面。

三、仿真测试工程

        在没有硬件的情况下,PL端单独进行仿真验证刚刚改过的从机IP,需要生成一个主机IP,与从机互联,在PL端进行仿真测试。还是一样的生成流程,选择主机模式。主机IP直接创建用于测试,不需要编辑。

        主机测试IP创建完成后添加进BD。双击主机IP,设置测试的起始值为0xabcd0001,设置基地址与从机一致,均为0x43C00000,由于从机设置测试读6个写4个,但主机逻辑为读写数据量一致,故这里读写寄存器的值设为大值6。

        按照图示连接,导出design_1_wrapper.v文件。

        sim_tb.v如下:

module sim_tb(

    );
reg   clk    ;
reg   rst    ;
reg   test_en;
design_1_wrapper design_1_wrapper(
    .data_in0_0             (32'haa550001),
    .data_in1_0             (32'haa550002),
    .data_in2_0             (32'haa550003),
    .data_in3_0             (32'haa550004),
    .data_out0_0            (            ),
    .data_out1_0            (            ),
    .data_out2_0            (            ),
    .data_out3_0            (            ),
    .data_out4_0            (            ),
    .data_out5_0            (            ),
    .m00_axi_aclk_0         (clk         ),
    .m00_axi_aresetn_0      (rst         ),
    .m00_axi_error_0        (            ),
    .m00_axi_init_axi_txn_0 (test_en     ),
    .m00_axi_txn_done_0     (            )
);
initial begin
    clk     = 0;
    rst     = 0;
    test_en = 0;
    #1000
    rst     = 1;
    #100
    test_en = 1;
    #10
    test_en = 0;

end 
always #5 clk =~clk;
endmodule

        下图所示为从机仿真时序,为方便测试,主机IP生成后未修改,未修改的主机逻辑为读写数据量一致,因此可以看到读数据后两个值不变,这里仅供理解AXI4_lite协议的读写时序,若要主从读写数据量完全一致,可以按照前面的方法根据个人需求再次编辑主从IP。

四、在线测试工程

        在线测试即为上板工程,删除仿真测试的主机IP,在BD中创建ZYNQ最小系统,定义地址为0x43C0_0000,按照图示连接,导出design_1_wrapper.v文件。

        新建一个工程顶层top.v,编译生成bit文件,导出xsa文件,新建一个vitis的helloword空工程。

module top(
  inout wire [14:0]DDR_0_addr,
  inout wire [2:0]DDR_0_ba,
  inout wire DDR_0_cas_n,
  inout wire DDR_0_ck_n,
  inout wire DDR_0_ck_p,
  inout wire DDR_0_cke,
  inout wire DDR_0_cs_n,
  inout wire [3:0]DDR_0_dm,
  inout wire [31:0]DDR_0_dq,
  inout wire [3:0]DDR_0_dqs_n,
  inout wire [3:0]DDR_0_dqs_p,
  inout wire DDR_0_odt,
  inout wire DDR_0_ras_n,
  inout wire DDR_0_reset_n,
  inout wire DDR_0_we_n,
  inout wire FIXED_IO_0_ddr_vrn,
  inout wire FIXED_IO_0_ddr_vrp,
  inout wire [53:0]FIXED_IO_0_mio,
  inout wire FIXED_IO_0_ps_clk,
  inout wire FIXED_IO_0_ps_porb,
  inout wire FIXED_IO_0_ps_srstb
    );
wire  [31:0] data_out0_0 ;
wire  [31:0] data_out1_0 ;
wire  [31:0] data_out2_0 ;
wire  [31:0] data_out3_0 ;
wire  [31:0] data_out4_0 ;
wire  [31:0] data_out5_0 ;
wire         ps_aclk     ;
ila_0 ila_0 (
	.clk   (ps_aclk     ), // input wire clk
	.probe0(data_out0_0 ), // input wire [31:0]  probe0  
	.probe1(data_out1_0 ), // input wire [31:0]  probe1 
	.probe2(data_out2_0 ), // input wire [31:0]  probe2 
	.probe3(data_out3_0 ), // input wire [31:0]  probe3 
	.probe4(data_out4_0 ), // input wire [31:0]  probe4 
	.probe5(data_out5_0 ) // input wire [31:0]  probe5
);
design_1_wrapper design_1_wrapper(
    .DDR_0_addr          (DDR_0_addr         ),
    .DDR_0_ba            (DDR_0_ba           ),
    .DDR_0_cas_n         (DDR_0_cas_n        ),
    .DDR_0_ck_n          (DDR_0_ck_n         ),
    .DDR_0_ck_p          (DDR_0_ck_p         ),
    .DDR_0_cke           (DDR_0_cke          ),
    .DDR_0_cs_n          (DDR_0_cs_n         ),
    .DDR_0_dm            (DDR_0_dm           ),
    .DDR_0_dq            (DDR_0_dq           ),
    .DDR_0_dqs_n         (DDR_0_dqs_n        ),
    .DDR_0_dqs_p         (DDR_0_dqs_p        ),
    .DDR_0_odt           (DDR_0_odt          ),
    .DDR_0_ras_n         (DDR_0_ras_n        ),
    .DDR_0_reset_n       (DDR_0_reset_n      ),
    .DDR_0_we_n          (DDR_0_we_n         ),
    .FIXED_IO_0_ddr_vrn  (FIXED_IO_0_ddr_vrn ),
    .FIXED_IO_0_ddr_vrp  (FIXED_IO_0_ddr_vrp ),
    .FIXED_IO_0_mio      (FIXED_IO_0_mio     ),
    .FIXED_IO_0_ps_clk   (FIXED_IO_0_ps_clk  ),
    .FIXED_IO_0_ps_porb  (FIXED_IO_0_ps_porb ),
    .FIXED_IO_0_ps_srstb (FIXED_IO_0_ps_srstb),
    .data_in0_0          (32'haa550001       ),
    .data_in1_0          (32'haa550002       ),
    .data_in2_0          (32'haa550003       ),
    .data_in3_0          (32'haa550004       ),
    .data_out0_0         (data_out0_0        ),
    .data_out1_0         (data_out1_0        ),
    .data_out2_0         (data_out2_0        ),
    .data_out3_0         (data_out3_0        ),
    .data_out4_0         (data_out4_0        ),
    .data_out5_0         (data_out5_0        ),
    .ps_aclk             (ps_aclk            ),
    .ps_aresetn          (                   )
);
endmodule

        vitis中helloword.c如下:

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xil_io.h"
#define  AXI_LITE_BASEADDR XPAR_AXI4_LITE_SLAVE_0_S00_AXI_BASEADDR

int main()
{
    init_platform();

	u32   test_in0 ;
	u32   test_in1 ;
	u32   test_in2 ;
	u32   test_in3 ;
	test_in0 = Xil_In32(AXI_LITE_BASEADDR);
	test_in1 = Xil_In32(AXI_LITE_BASEADDR + 0x04);
	test_in2 = Xil_In32(AXI_LITE_BASEADDR + 0x08);
	test_in3 = Xil_In32(AXI_LITE_BASEADDR + 0x0c);
    Xil_Out32(AXI_LITE_BASEADDR,     0xabcd0001 );
    Xil_Out32(AXI_LITE_BASEADDR+4 ,  0xabcd0002 );
    Xil_Out32(AXI_LITE_BASEADDR+8 ,  0xabcd0003 );
    Xil_Out32(AXI_LITE_BASEADDR+12,  0xabcd0004 );
    Xil_Out32(AXI_LITE_BASEADDR+16,  0xabcd0005  );
    Xil_Out32(AXI_LITE_BASEADDR+20,  0xabcd0006 );
    print("Hello World\n\r");
    print("Successfully ran Hello World application");
    cleanup_platform();
    return 0;
}

        板卡上电,运行程序,vitis中可以看到PL写给PS的四组数据与代码中设置的测试值一致。

        vivado中可以看到PS写给PL的六组数据与代码中设置的测试值一致。

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐