FPGA - 基于自定义AXI FULL总线的PS和PL交互

前言

FPGA - ZYNQ 基于Axi_Lite的PS和PL交互中,介绍了基于基于AXi_Lite的PL和PS交互,接下来构建基于基于Axi_Lite的PS和PL交互。


AXI_GP、AXI_HP和AXI_ACP接口

首先看一下ZYNQ SoC的系统框图,如下图所示。在图中,箭头方向代表主机到从机的方向。

在上图中红色框线中,就是PS和PL之间的交互,将上图简化如下:

可以看到主要有3中接口:AXI_GPAXI_HPAXI_ACP接口

GP:General Purpose Port(通用端口),位宽为32 位,适合PS和PL之间中 低速通信,有四个接口(两个从端口,两个主端口);

HP:High Performace Port(高性能端口),位宽为 32 位或者 64 位。适合 PS 和PL之间高速通信,有四个接口(四个都是从端口);

ACP:Accelerator Coherency Port(加速器一致),位宽为 64 位。适合 PS和PL 之间高速通信。

GP接口直接连接到的是中央互联区(central interconnect),然后由中央互联区再连接到OCM interconnect和存储器接口上;而HP接口直接连接到的是OCM interconnect和存储器接口。所以对于GP接口,通常使用他进行控制配置;而对于HP接口,通常使用它进行数据传输交互。

AXI_HP接口

4个AXI HP接口为PL的主机提供了DDR和OCM存储器的高带宽的数据路径。 每个HP接口包括两个的FIFO缓存,用于读写传输。PL到内存互连高速AXI HP端口路由连接到两个DDR内存端口和一个OCM存储器端口。AXI HP接口也被称为AFI (AXI FIFO接口),以强调它们的缓冲功能。 PL电平移位器必须通过LVL SHFTR EN启用后,才能进行PL逻辑通信。

特点

这些接口被设计为在PL主存储器和PS存储器(包括DDR和片上RAM)之间提供一个高吞吐量的数据路径。主要功能包括:

  • 可以实现32或64位数据位宽的主接口(每个端口独立编程)。
  • 在32位接口模式下,可以进行动态配置位为64位,以实现对齐传输,通过AxCACHE [1]可以进行控制。
  • 在32位接口模式下,为未对齐的32位传输自动扩展到64位。
  • 可编程的写命令释放阈值。
  • PL和PS之间的所有AXI接口的异步时钟域交叉。
  • 使用1kb (128 × 64位)数据缓存FIFO来平滑"长延迟"传输,用于读写。
  • 从PL端口提供QoS信令。
  • 命令和数据FIFO填充级计数可用于PL端。
  • 支持标准AXI 3.0接口。
  • 可编程命令下发到互连,分别用于读和写命令。
  • 14到70个指令范围的高性能从接口读接受能力。(取决于突发长度)
  • 8到32个指令范围的高性能从接口写接受能力。(取决于突发长度)

AXI_GP接口

AXI_GP接口直接连接到主互连和从互连的端口,没有任何额外的FIFO缓冲,不像AXI_HP接口使用FIFO缓冲以提高性能和吞吐量。因此,性能受到主互连端口和从互连端口的限制。这些接口仅用于通用用途,并不是为了实现高性能。

特点

AXI GP的特性包括:

  • 支持标准AXI协议
  • 数据总线宽度只有32位
  • 主端口ID位宽为12位
  • 主端口发送能力:8位读,8位写
  • 从端口ID位宽为6位
  • 从端口接受能力:8位读,8位写

AXI_GP、AXI_HP和AXI_ACP接口的主与从

注意:AXI_ACP和AXI_HP接口,PL只能是主机,PS只能是从机!!


接口介绍

AXI_HP

采用AXI_HP接口,PL为主机,PS为从机

PL 发送给PS的数据,通过AXI_HP接口后,进入DDR3控制器,然后写入到DDR3里面。

反过来,PL也可以通过AXI_HP接口读取DDR3里面的数据。

将上图简化:

PS 也可以向DDR3 写入或者读取数据,DDR3 相对于PS 而言就是一个外设。

PS 首先将数据写入到CacheCache 里面的数据再写入到DDR3 contorller , 最后到DDR3 。反过来,PS 也可以从DDR3里面读取数据。

PL 将数据通过AXI_HP 接口写入到DDR3PS 再将数据从DDR3 里面读出 来,这样就实现了PL与PS的数据交互


AXI_GP

采用AXI_GP接口,PL为从机,PS为主机

如果PS端采用AXI_GP接口,且PS端为主机,PL为从机,那么PL的接 口模块相对于PS来说,就是一个外设。(下面的图片加强理解)

既然是外设,那么就会有对应的地址和寄存器。

其中0x4300_0000 为起始地址 ,又称之为基地址 ;0x4300_FFFF为结束地址

其中,基地址结束地址 的值,是由PL端 分配的,也就是在PL端 可以使用VIVADO软件更改。

第二个地址为0x4300_0004,相比于0x4300_0000 偏移量为4。所以4就是偏移地址

可以通过**"基地址 + 偏移地址"**表示任意的地址。比如基地址为 0x4300_0000,偏移地址为8,表示的地址为0x4300_0008。

  • PS 如何通过AXI_GP接口写入数据到PL ?
  • PS 先将数据写入到寄存器里面,然后写入到PL。
  • PS 如何通过AXI_GP接口从PL端读取数据 ?
  • PL 端的数据先通过AXI_GP接口发送PS的寄存器里面,PS从寄存器里面 读取数据。

如下图:


AXI_HP、AXI_GP、AXI_ACP理论带宽

下表介绍了 PS- PL和PS内存接口的理论带宽

注意:Gb/s和GB/s是不一样的,B代表字节,b代表比特。

  • Gb/s:每秒传输多少个比特
  • GB/s:每秒传输多少个字节
  • GB/s = 8 * Gb/s

开发流程

在ZYNQ开发中,FPGA - ZYNQ 基于EMIO的PS和PL交互https://blog.csdn.net/weixin_46897065/article/details/137865852?spm=1001.2014.3001.5501

FPGA - ZYNQ 基于Axi_Lite的PS和PL交互https://blog.csdn.net/weixin_46897065/article/details/137937509?spm=1001.2014.3001.5501

中详细介绍了开发流程。

Creat Block Design 中:搜索ZYNQ以及axi_interconnect 并进行配置

然后进行自动连线,连线完成后如下图:

这里AXI_HP的从机搭建完成。、


然后建立top文件,设计AXI4_FULL主机模块。

代码如下:

`timescale 1ns / 1ps
module top(
	inout     	[14:0]		DDR_addr			,
	inout     	[2:0]		DDR_ba				,
	inout     				DDR_cas_n			,
	inout     				DDR_ck_n			,
	inout     				DDR_ck_p			,
	inout     				DDR_cke				,
	inout     				DDR_cs_n 			,
	inout     	[3:0]		DDR_dm 				,
	inout     	[31:0]		DDR_dq 				,
	inout     	[3:0]		DDR_dqs_n 			,
	inout     	[3:0]		DDR_dqs_p 			,
	inout     				DDR_odt 			,
	inout     				DDR_ras_n 			,
	inout     				DDR_reset_n 		,
	inout     				DDR_we_n  			,
	inout     				FIXED_IO_ddr_vrn 	,
	inout     				FIXED_IO_ddr_vrp	,
	inout     	[53:0]		FIXED_IO_mio 		,
	inout     				FIXED_IO_ps_clk		,
	inout     				FIXED_IO_ps_porb 	,
	inout     				FIXED_IO_ps_srstb  	
    );
	parameter     AXI_DATA_WIDTH = 64;
	parameter     AXI_ADDR_WIDTH = 32;
	parameter USER_WR_DATA_WIDTH = 16;
	parameter USER_RD_DATA_WIDTH = 16;

	wire PstoPl_clk150m;
	wire PstoPl_resetn;

	wire                         user_rd_clk;
	wire                         user_wr_clk;
	wire                         axi_clk;
	wire                         reset;
	wire                         ddr_init_done;
	wire                         user_wr_en;
	wire[USER_WR_DATA_WIDTH-1:0] user_wr_data;
	wire    [AXI_ADDR_WIDTH-1:0] user_wr_base_addr;
	wire    [AXI_ADDR_WIDTH-1:0] user_wr_end_addr;
	wire                         user_rd_req;
	wire    [AXI_ADDR_WIDTH-1:0] user_rd_base_addr;
	wire    [AXI_ADDR_WIDTH-1:0] user_rd_end_addr;
	wire                         user_rd_req_busy;
	wire                         user_rd_valid;
	wire                         user_rd_last;
	wire[USER_RD_DATA_WIDTH-1:0] user_rd_data;
	wire                         m_axi_awvalid;
	wire                         m_axi_awready;
	wire    [AXI_ADDR_WIDTH-1:0] m_axi_awaddr;
	wire                   [3:0] m_axi_awid;
	wire                   [7:0] m_axi_awlen;
	wire                   [1:0] m_axi_awburst;
	wire                   [2:0] m_axi_awsize;
	wire                   [2:0] m_axi_awport;
	wire                   [3:0] m_axi_awqos;
	wire                         m_axi_awlock;
	wire                   [3:0] m_axi_awcache;
	wire   [AXI_DATA_WIDTH-1 :0] m_axi_wdata;
	wire  [AXI_DATA_WIDTH/8-1:0] m_axi_wstrb;
	wire                         m_axi_wvalid;
	wire                         m_axi_wlast;
	wire                         m_axi_wready;
	wire                  [ 3:0] m_axi_bid;
	wire                  [ 1:0] m_axi_bresp;
	wire                         m_axi_bvalid;
	wire                         m_axi_bready;
	wire                         m_axi_arvalid;
	wire                         m_axi_arready;
	wire    [AXI_ADDR_WIDTH-1:0] m_axi_araddr;
	wire                   [3:0] m_axi_arid;
	wire                   [7:0] m_axi_arlen;
	wire                   [1:0] m_axi_arburst;
	wire                   [2:0] m_axi_arsize;
	wire                   [2:0] m_axi_arport;
	wire                   [3:0] m_axi_arqos;
	wire                         m_axi_arlock;
	wire                   [3:0] m_axi_arcache;
	wire                   [3:0] m_axi_rid;
	wire                         m_axi_rvalid;
	wire                         m_axi_rready;
	wire    [AXI_DATA_WIDTH-1:0] m_axi_rdata;
	wire                   [1:0] m_axi_rresp;
	wire                         m_axi_rlast;


	user_req_generate #(
			.USER_WR_DATA_WIDTH(USER_WR_DATA_WIDTH)
		) user_req_generate (
			.wr_clk       (PstoPl_clk150m),
			.rd_clk       (PstoPl_clk150m),
			.reset        (~PstoPl_resetn),
			.user_wr_en   (user_wr_en),
			.user_wr_data (user_wr_data),
			.user_rd_req  (user_rd_req)
		);


	axi4_adma_v1 #(
			.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
			.AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
			.USER_RD_DATA_WIDTH(USER_RD_DATA_WIDTH),
			.USER_WR_DATA_WIDTH(USER_WR_DATA_WIDTH)
		) axi_adma_v1 (
			.user_wr_clk       (PstoPl_clk150m),
			.user_rd_clk       (PstoPl_clk150m),
			.axi_clk           (PstoPl_clk150m),
			.reset             (~PstoPl_resetn),

			.ddr_init_done     (1'b1),

			.user_wr_en        (user_wr_en),
			.user_wr_data      (user_wr_data),
			.user_wr_base_addr (32'h0020_0000), //猫碌路氓搂鈥姑ヅ撀懊ヂ濃偓盲赂聧猫茠陆盲禄?0氓录?氓搂?
			.user_wr_end_addr  (32'h1000_0000),
			.user_rd_req       (user_rd_req),
			.user_rd_base_addr (32'h0020_0000),
			.user_rd_end_addr  (32'h1000_0000),
			.user_rd_req_busy  (user_rd_req_busy),
			.user_rd_valid     (user_rd_valid),
			.user_rd_last      (user_rd_last),
			.user_rd_data      (user_rd_data),
			.m_axi_awvalid     (m_axi_awvalid),
			.m_axi_awready     (m_axi_awready),
			.m_axi_awaddr      (m_axi_awaddr),
			.m_axi_awid        (m_axi_awid),
			.m_axi_awlen       (m_axi_awlen),
			.m_axi_awburst     (m_axi_awburst),
			.m_axi_awsize      (m_axi_awsize),
			.m_axi_awport      (m_axi_awport),
			.m_axi_awqos       (m_axi_awqos),
			.m_axi_awlock      (m_axi_awlock),
			.m_axi_awcache     (m_axi_awcache),
			.m_axi_wvalid      (m_axi_wvalid),
			.m_axi_wready      (m_axi_wready),
			.m_axi_wdata       (m_axi_wdata),
			.m_axi_wstrb       (m_axi_wstrb),
			.m_axi_wlast       (m_axi_wlast),
			.m_axi_bid         (m_axi_bid),
			.m_axi_bresp       (m_axi_bresp),
			.m_axi_bvalid      (m_axi_bvalid),
			.m_axi_bready      (m_axi_bready),
			.m_axi_arvalid     (m_axi_arvalid),
			.m_axi_arready     (m_axi_arready),
			.m_axi_araddr      (m_axi_araddr),
			.m_axi_arid        (m_axi_arid),
			.m_axi_arlen       (m_axi_arlen),
			.m_axi_arburst     (m_axi_arburst),
			.m_axi_arsize      (m_axi_arsize),
			.m_axi_arport      (m_axi_arport),
			.m_axi_arqos       (m_axi_arqos),
			.m_axi_arlock      (m_axi_arlock),
			.m_axi_arcache     (m_axi_arcache),
			.m_axi_rid         (m_axi_rid),
			.m_axi_rvalid      (m_axi_rvalid),
			.m_axi_rready      (m_axi_rready),
			.m_axi_rdata       (m_axi_rdata),
			.m_axi_rlast       (m_axi_rlast),
			.m_axi_rresp       (m_axi_rresp)
		);


	mcu_design_wrapper mcu_design_wrapper
		(
			.DDR_addr          (DDR_addr),
			.DDR_ba            (DDR_ba),
			.DDR_cas_n         (DDR_cas_n),
			.DDR_ck_n          (DDR_ck_n),
			.DDR_ck_p          (DDR_ck_p),
			.DDR_cke           (DDR_cke),
			.DDR_cs_n          (DDR_cs_n),
			.DDR_dm            (DDR_dm),
			.DDR_dq            (DDR_dq),
			.DDR_dqs_n         (DDR_dqs_n),
			.DDR_dqs_p         (DDR_dqs_p),
			.DDR_odt           (DDR_odt),
			.DDR_ras_n         (DDR_ras_n),
			.DDR_reset_n       (DDR_reset_n),
			.DDR_we_n          (DDR_we_n),

			.FIXED_IO_ddr_vrn  (FIXED_IO_ddr_vrn),
			.FIXED_IO_ddr_vrp  (FIXED_IO_ddr_vrp),
			.FIXED_IO_mio      (FIXED_IO_mio),
			.FIXED_IO_ps_clk   (FIXED_IO_ps_clk),
			.FIXED_IO_ps_porb  (FIXED_IO_ps_porb),
			.FIXED_IO_ps_srstb (FIXED_IO_ps_srstb),

			.PStoPL_resetn     (PstoPl_resetn),
			.PStoPL_clk150m    (PstoPl_clk150m),

			.S00_AXI_0_araddr  (m_axi_araddr),
			.S00_AXI_0_arburst (m_axi_arburst),
			.S00_AXI_0_arcache (m_axi_arcache),
			.S00_AXI_0_arid    (0),
			.S00_AXI_0_arlen   (m_axi_arlen),
			.S00_AXI_0_arlock  (0),
			.S00_AXI_0_arprot  (m_axi_arport),
			.S00_AXI_0_arqos   (m_axi_arqos),
			.S00_AXI_0_arready (m_axi_arready),
			.S00_AXI_0_arsize  (m_axi_arsize),
			.S00_AXI_0_arvalid (m_axi_arvalid),
			.S00_AXI_0_awaddr  (m_axi_awaddr),
			.S00_AXI_0_awburst (m_axi_awburst),
			.S00_AXI_0_awcache (m_axi_awcache),
			.S00_AXI_0_awid    (0),
			.S00_AXI_0_awlen   (m_axi_awlen),
			.S00_AXI_0_awlock  (0),
			.S00_AXI_0_awprot  (m_axi_awport),
			.S00_AXI_0_awqos   (m_axi_awqos),
			.S00_AXI_0_awready (m_axi_awready),
			.S00_AXI_0_awsize  (m_axi_awsize),
			.S00_AXI_0_awvalid (m_axi_awvalid),
			.S00_AXI_0_bid     (),
			.S00_AXI_0_bready  (m_axi_bready),
			.S00_AXI_0_bresp   (m_axi_bresp),
			.S00_AXI_0_bvalid  (m_axi_bvalid),
			.S00_AXI_0_rdata   (m_axi_rdata),
			.S00_AXI_0_rid     (),
			.S00_AXI_0_rlast   (m_axi_rlast),
			.S00_AXI_0_rready  (m_axi_rready),
			.S00_AXI_0_rresp   (m_axi_rresp),
			.S00_AXI_0_rvalid  (m_axi_rvalid),
			.S00_AXI_0_wdata   (m_axi_wdata),
			.S00_AXI_0_wid     (0),
			.S00_AXI_0_wlast   (m_axi_wlast),
			.S00_AXI_0_wready  (m_axi_wready),
			.S00_AXI_0_wstrb   (m_axi_wstrb),
			.S00_AXI_0_wvalid  (m_axi_wvalid)
		);

endmodule

然后生成bitstream导出硬件启动SDK


建立新工程

点击空工程 点击finish


接下来返回main.c,向其中添加以下代码:

一直处于接收发送状态。

#include <stdio.h>
#include "xil_printf.h"


int main()
{
	while(1)
	{

	};
    return 0;
}

最后,下载验证。


总结

在这里,实现了基于Axi_full的PS和PL交互,详细介绍了AXI_GP、AXI_HP和AXI_ACP接口。

相关推荐
DS小龙哥1 小时前
基于Zynq FPGA的雷龙SD NAND存储芯片性能测试
fpga开发·sd nand·雷龙·spi nand·spi nand flash·工业级tf卡·嵌入式tf卡
上理考研周导师10 小时前
第二章 虚拟仪器及其构成原理
fpga开发
FPGA技术实战12 小时前
《探索Zynq MPSoC》学习笔记(二)
fpga开发·mpsoc
bigbig猩猩1 天前
FPGA(现场可编程门阵列)的时序分析
fpga开发
Terasic友晶科技1 天前
第2篇 使用Intel FPGA Monitor Program创建基于ARM处理器的汇编或C语言工程<二>
fpga开发·汇编语言和c语言
码农阿豪1 天前
基于Zynq FPGA对雷龙SD NAND的测试
fpga开发·sd nand·spi nand·spi nand flash·工业级tf卡·嵌入式tf卡
江山如画,佳人北望1 天前
EDA技术简介
fpga开发
淘晶驰AK1 天前
电子设计竞赛准备经历分享
嵌入式硬件·fpga开发
最好有梦想~1 天前
FPGA时序分析和约束学习笔记(4、IO传输模型)
笔记·学习·fpga开发