4.1.3 vivado中AXI写DDR说明

这篇具有很好参考价值的文章主要介绍了4.1.3 vivado中AXI写DDR说明。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

link

在使用ZYNQ7021系列的FPGA,若涉及到PL部分读写DDR,可使用过AXI-Lite,AXI4-FULL,AXI-Stream这三个IP来实现,使用的是这三个IP的主机模式。

AXI 4总线协议解析

  • AXI4:主要面向高性能地址映射通信的需求;
  • AXI4-Lite:是一个简单地吞吐量地址映射性通信总线;
  • AXI4-Stream:面向高速流数据传输;
  • AXI4总线分为主、从两端,两者间可以连续的进行通信;

AXI 4总线采用READY,VALID握手通信机制,主设备收到从设备发送的READY,主设备将数据和VALID信号同时发送给从设备。
AXI 4-Lite所有的猝发长度为1,数据总线宽度为32位或64位
AXI 4-Stream数据总线宽度:8、16、32、64、128、256、512和1024位;
axi总线分为五个通道:

  • --读地址通道,包含ARVALID,ARADDR, ARREADY信号;
  • --写地址通道,包含AWVALID,AWADDR,AWREADY信号;
  • --读数据通道,包含RVALID,RDATA, RREADY, RRESP信号;
  • --写数据通道,包含WVALID, WDATA,WSTRB,WREADY信号;
  • --写应答通道,包含BVALID,BRESP, BREADY信号;
    AWLEN,猝发长度,是一个猝发中传送的数据个数,传送个数=AWLEN+1;如AWLEN=5,传送6个数据。
    AWSIZE,猝发大小,猝发中每个传送的数据的大小,字节数为=2^AWSIZE;如AWSIZE=0,每个数据是1个字节,AWSIZE=3,每个数据大小是8个字节

axis信号分为:

  • --TREADY信号:从告诉主做好传输准备;
  • --TVALID信号:主告诉从数据传输有效;
  • --TLAST信号:主告诉从该次传输为突发传输结尾
  • --TDATA信号:数据,可选宽度32,64,128,256bit
  • --TSTRB信号:为1的bit为对应tdata有效字节,宽度为tdata/8
  • --TUSER信号  :用户定义信号,宽度为128bit
  • --ACLK信号:总线时钟,上升沿有效;
  • --ARESETn信号:总线复位,低电平有效;

读操作

在读交易中,主设备先发送ARADDR和ARVALID给从设备,从设备回发ARREADY,通知主设备该地址有效,当ARVALID和ARREADY都为高电平时,主设备发出RREADY,表示主设备准备好接受读数据和相应信号了。从设备发送RVALID、RDATA以及RRESP,当RVALID和RREADY都为高电平时,数据被写入主设备。
写操作

在写操作中,主设备往从设备中写入AWADDR和AWVALID,然后主设备并没有等待从设备的AWREADY,而是继续发送WVALID和WDATA,当从设备回应AWREADY有效后,紧接着从设备发送WREADY表示从设备准备好接受数据,当WVALID和WREADY都为高电平是数据写入从设备。主设备发送的AWVALID和WVALID要有重叠区。

关于同时对DDR写操作的说明

在进行数据存储时,有时候有几类数据需要写入DDR,并且这些数据相互间没有相关性,比如将AD芯片K5394获取的数据存入地址为0x02000000,长度为0xf,将时间信息存入0x020000f0,长度为0XF0的DDR空间,这两者间数据基本无相关性,即获得了数据就将其写入DDR中,在使用这些IP来写数据时不需要考虑数据写入之间的竞争情况,因为AXI的IP模块有自己的WID,不同的WID可以乱序写入,但是同一个WID需要顺序写入,模块将会根据WID来X向DDR写数据。同时AK5394的数据得到为流水线形式,且得到两个数据之间的时间较大,因此这种的数据适合使用AXI-Lite来进行数据传输。
验证例程为pl_write_ddr_lite,其中MCU_2_FPGA的IP为修改的axi-lite的slave的IP,用于PS向PL部分发送数据。

axi_lite_wrddr模块是修改的AXI-Lite的Master的IP,用于实现想DDR的某一地址写入数据。

在使用时,由于对该IP进行了修改,若设置多次传输数据,将会对同一地址写入相同的数据,该模块主要是为了对一个地址写一个数据,不进行突发数据写入,因此需要设置写入次数为1次,如下图所示。同时写入的地址和写入的数据被引出,方便使用。

HP和GP接口

在 ZYNQ 芯片内部用硬件实现了 AXI 总线协议,包括 9 个物理接口,分别为 AXI-GP0~AXI-
GP3,AXI-HP0~AXI-HP3,AXI-ACP 接口。
AXI_ACP 接口,是 ARM 多核架构下定义的一种接口,中文翻译为加速器一致性端口,用
来管理 DMA 之类的不带缓存的 AXI 外设,PS 端是 Slave 接口。
AXI_HP 接口,是高性能/带宽的 AXI3.0 标准的接口,总共有四个,PL 模块作为主设备连
接。主要用于 PL 访问 PS 上的存储器(DDR 和 On-Chip RAM)
AXI_GP 接口,是通用的 AXI 接口,总共有四个,包括两个 32 位主设备接口和两个 32 位
从设备接口。

可以看到,只有两个 AXI-GP 是 Master Port,即主机接口,其余 7 个口都是 Slave Port(从
机接口)。主机接口具有发起读写的权限,ARM 可以利用两个 AXI-GP 主机接口主动访问 PL 逻
辑,其实就是把 PL 映射到某个地址,读写 PL 寄存器如同在读写自己的存储器。其余从机接口
就属于被动接口,接受来自 PL 的读写,逆来顺受。
另外这 9 个 AXI 接口性能也是不同的。GP 接口是 32 位的低性能接口,理论带宽
600MB/s,而 HP 和 ACP 接口为 64 位高性能接口,理论带宽 1200MB/s。有人会问,为什么高
性能接口不做成主机接口呢?这样可以由 ARM 发起高速数据传输。答案是高性能接口根本不
需要 ARM CPU 来负责数据搬移,真正的搬运工是位于 PL 中的 DMA 控制器。

几个AXI IP介绍

下面为几个常用的 AXI 接口 IP 的功能介绍:
AXI-DMA:实现从 PS 内存到 PL 高速传输高速通道 AXI-HP<---->AXI-Stream 的转换

AXI-FIFO-MM2S:实现从 PS 内存到 PL 通用传输通道 AXI-GP<----->AXI-Stream 的转换

AXI-Datamover:实现从 PS 内存到 PL 高速传输高速通道 AXI-HP<---->AXI-Stream 的转换,只
不过这次是完全由 PL 控制的,PS 是完全被动的。
AXI-VDMA:实现从 PS 内存到 PL 高速传输高速通道 AXI-HP<---->AXI-Stream 的转换,只不
过是专门针对视频、图像等二维数据的。
AXI-CDMA:这个是由 PL 完成的将数据从内存的一个位置搬移到另一个位置,无需 CPU 来
插手。
AXI 协议严格的讲是一个点对点的主从接口协议,当多个外设需要互相交互数据时,我们
需要加入一个 AXI Interconnect 模块,也就是 AXI 互联矩阵,作用是提供将一个或多个 AXI 主设
备连接到一个或多个 AXI 从设备的一种交换机制(有点类似于交换机里面的交换矩阵)。
这个 AXI Interconnect IP 核最多可以支持 16 个主设备、16 个从设备,如果需要更多的接
口,可以多加入几个 IP 核。

多个AXI模块并存时的地址分配

当使用多个AXI的IP(主机/从机),需要对地址进行映射。

需要对每一个主机会映射的从机进行地址分配,如硬核PS的AXI主机接口需要连接MCU_2_FPGA的IP,那么就对这哥IP进行地址分配。axi_lite_wrddr需要映射到PS的HP接口,则对HP进行地址分配。

但是需要注意的是,两个IP不要对重复地址段进行写数据,因为这样会造成数据混乱。

测试程序说明

main文件代码如下:

/*
 * 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 “sleep.h”
#include “xil_io.h”
#include “xparameters.h”
#include “xparameters_ps.h”

#include “mcu_2_fpga.h”

#include “stdbool.h”

void mcu2fpga_write(int id,u32 data)
{
switch(id){
case(0):MCU_2_FPGA_mWriteReg(XPAR_MCU_2_FPGA_0_S00_AXI_BASEADDR,MCU_2_FPGA_S00_AXI_SLV_REG0_OFFSET,data);break;
case(1):MCU_2_FPGA_mWriteReg(XPAR_MCU_2_FPGA_0_S00_AXI_BASEADDR,MCU_2_FPGA_S00_AXI_SLV_REG1_OFFSET,data);break;
case(2):MCU_2_FPGA_mWriteReg(XPAR_MCU_2_FPGA_0_S00_AXI_BASEADDR,MCU_2_FPGA_S00_AXI_SLV_REG2_OFFSET,data);break;
case(3):MCU_2_FPGA_mWriteReg(XPAR_MCU_2_FPGA_0_S00_AXI_BASEADDR,MCU_2_FPGA_S00_AXI_SLV_REG3_OFFSET,data);break;
default:break;
}

}

void mcu2fpga1_write(int id,u32 data)
{
switch(id){
case(0):MCU_2_FPGA_mWriteReg(XPAR_MCU_2_FPGA_1_S00_AXI_BASEADDR,MCU_2_FPGA_S00_AXI_SLV_REG0_OFFSET,data);break;
case(1):MCU_2_FPGA_mWriteReg(XPAR_MCU_2_FPGA_1_S00_AXI_BASEADDR,MCU_2_FPGA_S00_AXI_SLV_REG1_OFFSET,data);break;
case(2):MCU_2_FPGA_mWriteReg(XPAR_MCU_2_FPGA_1_S00_AXI_BASEADDR,MCU_2_FPGA_S00_AXI_SLV_REG2_OFFSET,data);break;
case(3):MCU_2_FPGA_mWriteReg(XPAR_MCU_2_FPGA_1_S00_AXI_BASEADDR,MCU_2_FPGA_S00_AXI_SLV_REG3_OFFSET,data);break;
default:break;
}

}
void mcu2fpga2_write(int id,u32 data)
{
switch(id){
case(0):MCU_2_FPGA_mWriteReg(XPAR_MCU_2_FPGA_2_S00_AXI_BASEADDR,MCU_2_FPGA_S00_AXI_SLV_REG0_OFFSET,data);break;
case(1):MCU_2_FPGA_mWriteReg(XPAR_MCU_2_FPGA_2_S00_AXI_BASEADDR,MCU_2_FPGA_S00_AXI_SLV_REG1_OFFSET,data);break;
case(2):MCU_2_FPGA_mWriteReg(XPAR_MCU_2_FPGA_2_S00_AXI_BASEADDR,MCU_2_FPGA_S00_AXI_SLV_REG2_OFFSET,data);break;
case(3):MCU_2_FPGA_mWriteReg(XPAR_MCU_2_FPGA_2_S00_AXI_BASEADDR,MCU_2_FPGA_S00_AXI_SLV_REG3_OFFSET,data);break;
default:break;
}

}
u32 mcu2fpga_read(int id)
{
switch(id){
case(0):return MCU_2_FPGA_mReadReg(XPAR_MCU_2_FPGA_0_S00_AXI_BASEADDR,MCU_2_FPGA_S00_AXI_SLV_REG0_OFFSET);break;
case(1):return MCU_2_FPGA_mReadReg(XPAR_MCU_2_FPGA_0_S00_AXI_BASEADDR,MCU_2_FPGA_S00_AXI_SLV_REG1_OFFSET);break;
case(2):return MCU_2_FPGA_mReadReg(XPAR_MCU_2_FPGA_0_S00_AXI_BASEADDR,MCU_2_FPGA_S00_AXI_SLV_REG2_OFFSET);break;
case(3):return MCU_2_FPGA_mReadReg(XPAR_MCU_2_FPGA_0_S00_AXI_BASEADDR,MCU_2_FPGA_S00_AXI_SLV_REG3_OFFSET);break;
default:break;
}
return 12;
}

//分配DDR中对应AD数据的内存地址给数组
u32 ak5394_m1[60] attribute((section(“.ak5394M1Section”)));//hpy test PS read DDR
u32 ak5394_m2[60] attribute((section(“.ak5394M2Section”)));//hpy test PS read DDR

void pl_update_ddr(u32 addr,int offset,_Bool display)//测试PL写DDR,用于发送数据到FPGA更新DDR中的数据
{
for(int j = 0;j<30;j++){

    	<span class="token function">mcu2fpga_write</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token operator">*</span>j <span class="token operator">+</span> offset<span class="token punctuation">)</span><span class="token punctuation">;</span>
    	<span class="token function">mcu2fpga_write</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token operator">*</span>j<span class="token operator">+</span><span class="token number">1</span> <span class="token operator">+</span> offset<span class="token punctuation">)</span><span class="token punctuation">;</span>
    	<span class="token function">mcu2fpga_write</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token operator">*</span>j<span class="token operator">+</span><span class="token number">2</span> <span class="token operator">+</span> offset<span class="token punctuation">)</span><span class="token punctuation">;</span>
    	<span class="token function">usleep</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    	<span class="token function">mcu2fpga_write</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span>addr <span class="token operator">+</span> j<span class="token operator">*</span><span class="token number">16</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    	<span class="token keyword">if</span><span class="token punctuation">(</span>display <span class="token operator">==</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
	    	<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"data[%d] = %d\n"</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token operator">*</span>j<span class="token punctuation">,</span><span class="token number">4</span><span class="token operator">*</span>j <span class="token operator">+</span> offset<span class="token punctuation">)</span><span class="token punctuation">;</span>
	    	<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"data[%d] = %d\n"</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token operator">*</span>j<span class="token operator">+</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token operator">*</span>j<span class="token operator">+</span><span class="token number">1</span> <span class="token operator">+</span> offset<span class="token punctuation">)</span><span class="token punctuation">;</span>
	    	<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"data[%d] = %d\n"</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token operator">*</span>j<span class="token operator">+</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token operator">*</span>j<span class="token operator">+</span><span class="token number">2</span> <span class="token operator">+</span> offset<span class="token punctuation">)</span><span class="token punctuation">;</span>
	    	<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"data[%d] = %d\n"</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token operator">*</span>j<span class="token operator">+</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token operator">*</span>j<span class="token operator">+</span><span class="token number">3</span> <span class="token operator">+</span> offset<span class="token punctuation">)</span><span class="token punctuation">;</span>
    	<span class="token punctuation">}</span>
    	<span class="token function">usleep</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

}
//利用MCU_2_FPGA向PL发送数据,然后PL将数据写入DDR
void lite_write(u32 ad,int off){
for(int i=0;i<30;i++){
mcu2fpga2_write(1,i+off);
mcu2fpga1_write(1,i+off+1);
mcu2fpga2_write(0,ad+i4);
mcu2fpga1_write(0,ad+i4 + 120);
usleep(100);
}
pl_update_ddr(0x020000F0,off,false);
}
void write_ddr_lite_test(){
int i = 0;
int mdata = 5;
u32 ad0 = 0x02000000;
u32 ad = ad0;
int cnt=0;
while(1){
lite_write(ad,cnt);
if(cnt>=100)cnt = 0;
else cnt++;
printf(“--------------------------\n”);
usleep(1000000);
Xil_DCacheInvalidateRange(ad0,sizeof(ak5394_m1));//将DDR中数据更新到cache中
Xil_DCacheInvalidateRange(0x020000F0,sizeof(ak5394_m2));//将DDR中数据更新到cache中
for(u32 j=0;j<30;j++){// PS读取DDR并显示
printf("a[%d]=%d a[%d]=%d b[%d]=%d\n ",j,ak5394_m1[j],j+30,ak5394_m1[j+30],j,ak5394_m2[j]);
}
}
}
int main()
{
init_platform();
int max = 7;
int i = 1;

u32 addr <span class="token operator">=</span> <span class="token number">0x02000000</span><span class="token punctuation">;</span>
u32 addr2 <span class="token operator">=</span><span class="token number">0x02000000</span><span class="token punctuation">;</span>
<span class="token function">write_ddr_lite_test</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">pl_update_ddr</span><span class="token punctuation">(</span>addr<span class="token punctuation">,</span><span class="token number">0</span><span class="token punctuation">,</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//测试函数</span>
    <span class="token function">cleanup_platform</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

}

link脚本文件编写

为了方便数据读出,将写入DDR的地址段分配给数组,得益于GCC的强大功能,通过__attribute__可以实现给数组分配指定地址空间。
文件编写如下

/*******************************************************************/
/*                                                                 */
/* This file is automatically generated by linker script generator.*/
/*                                                                 */
/* Version: 2018.3                                                 */
/*                                                                 */
/* Copyright (c) 2010-2016 Xilinx, Inc.  All rights reserved.      */
/*                                                                 */
/* Description : Cortex-A9 Linker Script                           */
/*                                                                 */
/*******************************************************************/

_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x2000;
_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x2000;

_ABORT_STACK_SIZE = DEFINED(_ABORT_STACK_SIZE) ? _ABORT_STACK_SIZE : 1024;
_SUPERVISOR_STACK_SIZE = DEFINED(_SUPERVISOR_STACK_SIZE) ? _SUPERVISOR_STACK_SIZE : 2048;
_IRQ_STACK_SIZE = DEFINED(_IRQ_STACK_SIZE) ? _IRQ_STACK_SIZE : 1024;
_FIQ_STACK_SIZE = DEFINED(_FIQ_STACK_SIZE) ? _FIQ_STACK_SIZE : 1024;
_UNDEF_STACK_SIZE = DEFINED(_UNDEF_STACK_SIZE) ? _UNDEF_STACK_SIZE : 1024;

/* Define Memories in the system */

MEMORY
{
ps7_ddr_0 : ORIGIN = 0x100000, LENGTH = 0x1f00000 /0x3FF00000/
ps7_ram_0 : ORIGIN = 0x0, LENGTH = 0x30000
ps7_ram_1 : ORIGIN = 0xFFFF0000, LENGTH = 0xFE00
/以下为自己定义,需要分配的地址段/
AK5394_M1 : ORIGIN = 0x02000000, LENGTH = 0x000000F0
AK5394_M2 : ORIGIN = 0x020000F0, LENGTH = 0x000000F0
}

/* Specify the default entry point to the program */

ENTRY(_vector_table)

/* Define the sections, and where they are mapped in memory */

SECTIONS
{
.ak5394M1Section :{
__ak5394Section_start = .;
*(.ak5394M1Section)
__ak5394Section_end = .;
} > AK5394_M1

.ak5394M2Section :{
__ak5394Section_start = .;
*(.ak5394M2Section)
__ak5394Section_end = .;
} > AK5394_M2

.text : {
KEEP ((.vectors))
(.boot)
(.text)
(.text.)
(.gnu.linkonce.t.)
(.plt)
(.gnu_warning)
(.gcc_execpt_table)
(.glue_7)
(.glue_7t)
(.vfp11_veneer)
(.ARM.extab)
(.gnu.linkonce.armextab.)
} > ps7_ddr_0

.init : {
KEEP (*(.init))
} > ps7_ddr_0

.fini : {
KEEP (*(.fini))
} > ps7_ddr_0

.rodata : {
__rodata_start = .;
(.rodata)
(.rodata.)
(.gnu.linkonce.r.*)
__rodata_end = .;
} > ps7_ddr_0

.rodata1 : {
__rodata1_start = .;
(.rodata1)
(.rodata1.*)
__rodata1_end = .;
} > ps7_ddr_0

.sdata2 : {
__sdata2_start = .;
(.sdata2)
(.sdata2.)
(.gnu.linkonce.s2.*)
__sdata2_end = .;
} > ps7_ddr_0

.sbss2 : {
__sbss2_start = .;
(.sbss2)
(.sbss2.)
(.gnu.linkonce.sb2.*)
__sbss2_end = .;
} > ps7_ddr_0

.data : {
__data_start = .;
(.data)
(.data.)
(.gnu.linkonce.d.)
(.jcr)
(.got)
(.got.plt)
__data_end = .;
} > ps7_ddr_0

.data1 : {
__data1_start = .;
(.data1)
(.data1.*)
__data1_end = .;
} > ps7_ddr_0

.got : {
*(.got)
} > ps7_ddr_0

.ctors : {
CTOR_LIST = .;
CTORS_LIST = .;
KEEP (crtbegin.o(.ctors))
KEEP ((EXCLUDE_FILE(crtend.o) .ctors))
KEEP ((SORT(.ctors.)))
KEEP ((.ctors))
CTOR_END = .;
CTORS_END = .;
} > ps7_ddr_0

.dtors : {
DTOR_LIST = .;
DTORS_LIST = .;
KEEP (crtbegin.o(.dtors))
KEEP ((EXCLUDE_FILE(crtend.o) .dtors))
KEEP ((SORT(.dtors.)))
KEEP ((.dtors))
DTOR_END = .;
DTORS_END = .;
} > ps7_ddr_0

.fixup : {
__fixup_start = .;
*(.fixup)
__fixup_end = .;
} > ps7_ddr_0

.eh_frame : {
*(.eh_frame)
} > ps7_ddr_0

.eh_framehdr : {
__eh_framehdr_start = .;
*(.eh_framehdr)
__eh_framehdr_end = .;
} > ps7_ddr_0

.gcc_except_table : {
*(.gcc_except_table)
} > ps7_ddr_0

.mmu_tbl (ALIGN(16384)) : {
__mmu_tbl_start = .;
*(.mmu_tbl)
__mmu_tbl_end = .;
} > ps7_ddr_0

.ARM.exidx : {
__exidx_start = .;
(.ARM.exidx)
(.gnu.linkonce.armexidix..*)
__exidx_end = .;
} > ps7_ddr_0

.preinit_array : {
__preinit_array_start = .;
KEEP ((SORT(.preinit_array.)))
KEEP (*(.preinit_array))
__preinit_array_end = .;
} > ps7_ddr_0

.init_array : {
__init_array_start = .;
KEEP ((SORT(.init_array.)))
KEEP (*(.init_array))
__init_array_end = .;
} > ps7_ddr_0

.fini_array : {
__fini_array_start = .;
KEEP ((SORT(.fini_array.)))
KEEP (*(.fini_array))
__fini_array_end = .;
} > ps7_ddr_0

.ARM.attributes : {
__ARM.attributes_start = .;
*(.ARM.attributes)
__ARM.attributes_end = .;
} > ps7_ddr_0

.sdata : {
__sdata_start = .;
(.sdata)
(.sdata.)
(.gnu.linkonce.s.*)
__sdata_end = .;
} > ps7_ddr_0

.sbss (NOLOAD) : {
__sbss_start = .;
(.sbss)
(.sbss.)
(.gnu.linkonce.sb.*)
__sbss_end = .;
} > ps7_ddr_0

.tdata : {
__tdata_start = .;
(.tdata)
(.tdata.)
(.gnu.linkonce.td.*)
__tdata_end = .;
} > ps7_ddr_0

.tbss : {
__tbss_start = .;
(.tbss)
(.tbss.)
(.gnu.linkonce.tb.*)
__tbss_end = .;
} > ps7_ddr_0

.bss (NOLOAD) : {
__bss_start = .;
(.bss)
(.bss.)
(.gnu.linkonce.b.)
(COMMON)
__bss_end = .;
} > ps7_ddr_0

SDA_BASE = __sdata_start + ((__sbss_end - __sdata_start) / 2 );

SDA2_BASE = __sdata2_start + ((__sbss2_end - __sdata2_start) / 2 );

/* Generate Stack and Heap definitions */

.heap (NOLOAD) : {
. = ALIGN(16);
_heap = .;
HeapBase = .;
_heap_start = .;
. += _HEAP_SIZE;
_heap_end = .;
HeapLimit = .;
} > ps7_ddr_0

.stack (NOLOAD) : {
. = ALIGN(16);
_stack_end = .;
. += _STACK_SIZE;
. = ALIGN(16);
_stack = .;
__stack = _stack;
. = ALIGN(16);
_irq_stack_end = .;
. += _IRQ_STACK_SIZE;
. = ALIGN(16);
__irq_stack = .;
_supervisor_stack_end = .;
. += _SUPERVISOR_STACK_SIZE;
. = ALIGN(16);
__supervisor_stack = .;
_abort_stack_end = .;
. += _ABORT_STACK_SIZE;
. = ALIGN(16);
__abort_stack = .;
_fiq_stack_end = .;
. += _FIQ_STACK_SIZE;
. = ALIGN(16);
__fiq_stack = .;
_undef_stack_end = .;
. += _UNDEF_STACK_SIZE;
. = ALIGN(16);
__undef_stack = .;
} > ps7_ddr_0

_end = .;
}

然后利用__attribute__进行分配地址。u32 ak5394_m1[60] __attribute__((section(".ak5394M1Section")));//hpy test PS read DDR文章来源地址https://www.toymoban.com/news/detail-516360.html

串口显示验证

到了这里,关于4.1.3 vivado中AXI写DDR说明的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 紫光FPGA DDR3 IP使用和注意事项(axi4协议)

    紫光DDR3 IP使用 对于紫光ddr3 IP核的使用需要注意事情。 阅读ddr ip手册: 1、注意:对于写地址通道,axi_awvalid要一直拉高,axi_awready才会拉高。使用的芯片型号时PG2L100H-6FBG676,不同的型号IP核接口和axi的握手协议也不一样(一定要注意),这点要注意,这也给我挖了一个很大的

    2024年04月12日
    浏览(51)
  • fpga 通过axi master读写PS侧DDR的仿真和上板测试

           FPGA和ARM数据交互是ZYNQ系统中非常重要的内容。PS提供了供FPGA读写的AXI-HP接口用于两者的高速通信和数据交互。一般的,我们会采用AXI DMA的方式去传输数据,DMA代码基本是是C编写,对于FPGA开发者来说不利于维护和debug。本文提供一种手写AXI_MASTER接口用于PL 向DDR指定位

    2024年04月12日
    浏览(39)
  • 【正点原子FPGA连载】第二十章AXI4接口之DDR读写实验 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南

    1)实验平台:正点原子MPSoC开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id=692450874670 3)全套实验源码+手册+视频下载地址: http://www.openedv.com/thread-340252-1-1.html Xilinx从Spartan-6和Virtex-6系列开始使用AXI协议来连接IP核。在ZYNQ MPSOC器件中,Xilinx在IP核中继续使用AXI协议。本章

    2024年02月02日
    浏览(53)
  • DDR3(AXI接口例程)知识点笔记

    本文以7035开发板中的DDR3master例程对DDR3中所涉及的知识点梳理下笔记。 ① DDR支持的突发长度是2,4,8 。即如果芯片的数据位宽是16bit的话那么接口数据位宽是32bit,64bit以及128bit。因为 L-Bank一次就存取两倍于芯片位宽的数据,所以芯片至少也要进行两次传输才可以。我认为芯片

    2024年02月13日
    浏览(48)
  • DDR3 AXI4 IP核读写仿真实验(2)

    上篇blog中记录了DDR3 AXI4接口的IP配置详情,这一文章则是记录自己在项目工程以及学习中对于DDR3的读写测试。先讲一下大概的工程架构:产生16位的自加数写进写FIFO中,当FIFO中的数达到一次突发长度后将其全部读出写进DDR3中,再检测到DDR3中数达到1024之后全部读出写入到读

    2024年02月13日
    浏览(46)
  • ZYNQ AXI4总线访问DDR3实现图像数据乒乓存储与显示

    目录 前言 一、添加端口 二、添加局部变量 三、例化读写FIFO 四、内部变量修改,设置一次读写进行多少次突发操作 五、写地址 六、读地址 七、状态机 1.写状态机 2.读状态机 总结 在Altera FPGA进行图像处理时,我们采用的存储芯片为SDRAM,当时参照正点原子的例程是封装SDR

    2024年02月02日
    浏览(69)
  • ZYNQ通过AXI DMA实现PL发送连续大量数据到PS DDR

    硬件:ZYNQ7100 软件:Vivado 2017.4、Xilinx SDK 2017.4   ZYNQ PL 和 PS 的通信方式有 AXI GPIO、BRAM、DDR等。对于数据量较少、地址不连续、长度规则的情况,BRAM 比较适用。而对于传输速度要求高、数据量大、地址连续的情况,比如 ADC,可以通过 AXI DMA 来完成。 1、硬件设计 1.1 ZYNQ7

    2024年02月04日
    浏览(44)
  • ZYNQ使用AXI4-HP接口总线读取DDR中的数据

    最近笔者在做项目的时候需要使用zynq中的AXI4-HP总线在PL端读取DDR中的数据这种功能,但是网上很多历程对于这方面只是创建了一个官方提供的IP核用于测试,并且每次写入和读取的长度为4K字节。所以为了满足我自己的项目需求,笔者将官方提供的测试IP核上做修改,主要实现

    2023年04月15日
    浏览(46)
  • 【FPGA】 xilinx vivado中AXI4通信协议详解

    AXI是ARM 1996年提出的微控制器总线家族AMBA中的一部分。AXI的第一个版本出现在AMBA3.0,发布于2003年。当前的最新的版本发布于2010年。AXI 4总线和别的总线一样,都用来传输bits信息 (包含了数据或者地址) 。AXI4总线有三种类型,分别是AXI4、AXI4-Lite、AXI4-Stream AXI4:主要面向高性能

    2024年04月28日
    浏览(44)
  • 【FPGA】十三、Vivado MIG IP核实现DDR3控制器(1)

    文章目录 前言 一、DDR3基础知识 二、MIG  IP核的配置 三、DDR3 IP核用户端接口时序 1、DDR3 IP核接口说明 2、DDR3 IP核读写时序 ① 写命令时序:  ② 写数据时序:  ③ 读数据时序: 总结         我们在进行FPGA开发应用当中,经常会用到存储器来保存数据,常用的存储器有RO

    2024年02月16日
    浏览(82)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包