zynq dma的dma怎么配置sg模式

【ZYNQ-7000开发之四】在PS端使用AXI DMA传输的步骤 - FPGA&硬件语言专区 - OpenHW技术社区
后使用快捷导航没有帐号?
查看: 423|回复: 0
【ZYNQ-7000开发之四】在PS端使用AXI DMA传输的步骤
主题帖子积分
金牌会员, 积分 2250, 距离下一级还需 750 积分
金牌会员, 积分 2250, 距离下一级还需 750 积分
本篇文章简要总结下AXI DMA在ZYNQ PS端的初始化方法。本文摘抄自,更加详细的内容请参考官方文档,这里只提取了关键部分。 AXI DMA有两种模式,Direct Register Mode(不支持Scatter Gather)和& &Scatter Gather Mode。
AXI DMA用于AXI4 memory mapped和AXI4-Stream之间的转换
Scatter Gather Mode性能更好,更消耗逻辑资源,使用更复杂一些。
Direct Register Mode则相反。
AXI DMA更加详细的介绍请参考:
使用AXI DMA传输的步骤:
非Scatter Gather mode
To use the Simple mode DMA engine for transfers, the following setup is required:DMA Initialization using
function. This step initializes a driver instance for the given DMA engine and resets the engine.
Enable interrupts if chosen to use interrupt mode. The application is responsible for setting up the interrupt system, which includes providing and connecting interrupt handlers and call back functions, before enabling the interrupts.
Set the buffer address and length field in respective channels to start the DMA transfer
使用Scatter Gather mode To use the SG mode DMA engine for transfers, the following setup are required:DMA Initialization using
function. This step initializes a driver instance for the given DMA engine and resets the engine.
BD Ring creation. A BD ring is needed per DMA channel and can be built by calling .
Enable interrupts if chose to use interrupt mode. The application is responsible for setting up the interrupt system, which includes providing and connecting interrupt handlers and call back functions, before enabling the interrupts.
Start a DMA transfer: Call
to start a transfer for the first time or after a reset, and
if the channel is already started. Calling
when a DMA channel is not running will not put the BDs to the hardware, and the BDs will be processed later when the DMA channel is started through .
How to start DMA transactionsThe user application uses
to submit BDs to the hardware to start DMA transfers.For both channels, if the DMA engine is currently stopped (using ), the newly added BDs will be accepted but not processed until the DMA engine is started, using , or resumed, using .
Post-Processing 这个不是很了解Software Post-Processing on completed DMA transactionsIf the interrupt system has been set up and the interrupts are enabled, a DMA channels notifies the software about the completion of a transfer through interrupts. Otherwise, the user application can poll for completions of the BDs, using
or .Once BDs are finished by a channel, the application first needs to fetch them from the channel using .
On the TX side, the application now could free the data buffers attached to those BDs as the data in the buffers has been transmitted.
On the RX side, the application now could use the received data in the buffers attached to those BDs.
For both channels, completed BDs need to be put back to the Free group using , so they can be used for future transactions.
On the RX side, it is the application's responsibility to have BDs ready to receive data at any time. Otherwise, the RX channel refuses to accept any data if it has no RX BDs.
作者:RZJM_PB
联系电话: 3-8062
Powered byCategories
您可以选择一种方式赞助本站Adam Taylor MicroZed系列之28: Zynq PS/PL详解之DMA(part8) | 电子创新网赛灵思中文社区
在我上一篇博客里,我们达成一个观点,就是使用DMA(直接内存访问)的好处很明显,我之前在也提到使用AXI接口的DMA的好处。
虽然达成这样一个观点,但我们还有一个值得思考的问题,DMA到底是什么?
最基本的,一旦处理器配置好传输方式之后,DMA可以自己完成内存数据的搬进或者搬出,而不需要处理器的介入。如果使用方法得当,DMA可以显著地提高系统性能。
在讨论Zynq DMA的设计细节之前,让我们先要解释几个DMA控制器的原则:
典型的DMA控制器可以工作在以下三种模式:
1、 突发模式-以一个连续的操作方式来传输一个完整的数据包,在许多应用中,DMA的突发模式传输会拒绝处理器的总线访问,对于不同的系统而言,这有利有弊(可以是件好事,也可能是一件非常糟糕的事情。)
2、 周期挪用模式-跟处理器一起交替完成单独的DMA字节或者字传输的总线访问,这种模式可以防止处理器无法访问总线。
3、 透明模式-效率最高的传输模式,只有在处理器在执行任务而不需要访问外部系统总线的时候,DMA才能传输数据。
DMA控制器支持scatter/gather操作,这是一个非常有用的特性,这个特性允许多个数据源的数据传输到同一个目的地址,或者同一个源地址的数据传输到不同的目的地址(也可以称为“buffers”)
Zyng SoC是基于ARM内核的处理系统,它有一个DMA控制器,该DMA控制器连接在Zynq的AXI4中央互连架构上,通过AXI总线来传输数据,它在系统存储器和Zynq的可编程逻辑单元(PL)之间完成64位的AXI总线传输。如下图所示,Zynq DMA有8个通道,可以同时执行8个DMA传输操作。
尽管Zynq DMA可以在系统存储器到PL(包括PL中的Zynq外设)之间发起双向传输,但是它不支持在Zynq PS的外设之间发起传输,因为,这些外设没有支持DMA操作的流控制信号。然而,在Zynq SoC中,有一些IO外设,它们自身有DMA控制器,可以支持IOP和系统存储器之间的高速数据传输。这些外设包括:
1、 以太网控制器
2、 SDIO控制器
3、 USB控制器
4、 器件配置控制器
如果器件采用了ARM TrustZone技术,Zynq SoC也可以支持安全寄存器访问。
赛灵思则提供了一个简单有用的驱动文件(xdmaps.h),这个文件可以用在BSP中来配置和初始化DMA传输。在我的下一篇博客中,会讲到如何用这个文件来实现一个简单的DMA传输。
原文链接:
(C) Copyright 2014 Xilinx Inc.
如需转载,请注明出处
11629 次点击
开发板推荐
FPGA开发交流群
3 天 23 小时之前
1 周 1 天之前
1 周 1 天之前
2 周 1 小时之前
2 周 3 小时之前
2 周 3 小时之前
2 周 18 小时之前
2 周 3 天之前
2 周 3 天之前
3 周 6 天之前你的位置:
【转载】Xilinx Zedboard ZYNQ AXI-Stream IP调试日记
来源 : /zhaoyongke/blog/
Xilinx AXI-Stream IP调试日记目录
【参赛手记】AXI-Stream接口开发详细流程
本文是AXI-Stream IP调试日记的终结篇。看到这里,可能大家都还对Stream没有一个直观的认识。其实Stream并不陌生,在我们学c++编程时,一定会包含,这样就可以完成控制终端对程序的输入输出了。如果还是不够直观,想象一下水流,是连续不断的,向某一方向,以固定的速度输送的接口。以我们看视频为例,视频文件本来是保存在硬盘里的,怎么播放呢,不能一下子把整个文件都显示到屏幕上,而是以一定速度,连续不断地输出到屏幕上(每秒若干帧),这个过程就是流Stream接口完成的。Xilinx提供的流式IP核有很多用途,可以实现音频流、视频流、数据流到内存或者相反方向的传输。有人问了,内存是PS控制的,怎么才能把PS里DDR2的内容以Stream形式发出去呢(例如以固定速度送往DA,完成信号发生器的设计)?答案就是利用AXI总线做转换。ZYNQ的PS部分是ARM Cortex A9系列,支持AXI4,AXI-Lite总线。PL部分也有相应AXI总线接口,这样就能完成PS到PL的互联。仅仅这样还不够,需要PL部分实现流式转换,即AXI-Stream接口实现。Xilinx提供的从AXI到AXI-Stream转换的IP核有:AXI-DMA,AXI-Datamover,AXI-FIFO-MM2S以及AXI-vDMA等。这些IP核可以在XPS中看到。这里要和大家说明白一点,就是AXI总线和接口的区别。总线是一种标准化接口,由数据线、地址线、控制线等构成,具有一定的强制性。接口是其物理实现,即在硬件上的分配。在ZYNQ中,支持AXI-Lite,AXI4和AXI-Stream三种总线,但PS与PL之间的接口却只支持前两种,AXI-Stream只能在PL中实现,不能直接和PS相连,必须通过AXI-Lite或AXI4转接。PS与PL之间的物理接口有9个,包括4个AXI-GP接口和4个AXI-HP接口、1个AXI-ACP接口。AXI-DMA:实现从PS内存到PL高速传输高速通道AXI-HPAXI-Stream的转换AXI-FIFO-MM2S:实现从PS内存到PL通用传输通道AXI-GPAXI-Stream的转换AXI-Datamover:实现从PS内存到PL高速传输高速通道AXI-HPAXI-Stream的转换,只不过这次是完全由PL控制的,PS是完全被动的。AXI-VDMA:实现从PS内存到PL高速传输高速通道AXI-HPAXI-Stream的转换,只不过是专门针对视频、图像等二维数据的。除了上面的还有一个AXI-CDMA IP核,这个是由PL完成的将数据从内存的一个位置搬移到另一个位置,无需CPU来插手。这个和我们这里用的Stream没有关系,所以不表。上面的IP是完成总线协议转换,如果需要做某些处理(如变换、迭代、训练……),则需要生成一个自定义Stream类型IP,与上面的Stream接口连接起来,实现数据输入输出。用户的功能在自定义Stream类型IP中实现。 下面讲一个例子,来加深对上面介绍内容的理解。软件:ISE 14.21.先建立PlanAhead工程,一直做到进入XPS,具体流程见官方文档CTT。2.在XPS中,添加一个AXI-DMA模块,配置界面如下图所示其余参数默认。SG模块如果选上,那么后面软件控制会相对复杂一些。这里不选,采用Simple模式。3.选菜单Hardware->Createor Import Peripheral。。。,设计自定义IP。名称起为my_stream_ip,自动版本为1.00a。遇到Bus Interface选择AXI4-Stream类型,一直点下一步到最后结束。该类型IP的生成过程比AXI4-Lite和AXI4都要简单。4.添加一个my_stream_ip到系统中,连接图见下。my_stream_ip实现了先接受8个字的数据,求和,然后将和发送回去(发送8次)。上图连接方式说明是AXI-DMA发送给my_stream_ip,然后my_stream_ip又发回AXI-DMA。同时看到AXI-DMA和PS连接是通过HP0传输数据,由GP0控制其传输的进行。5.以上连接是有问题的(主要是XPS的bug),需要一项项修改。
首先是HP0的地址区间报错,可以先点Zynq标签,然后单击HP0绿线,在弹出的配置对话框中将HP0的地址区间改为我们ZED Board 上DDR2区间0xx1FFFFFFF,像下图这样:
在高版本ISE14.5中,这个bug已经修复,不需要改。之后就是AXI-DMA和my_stream_ip的连线问题。本来都是Stream 接口,按理说是标准接口,不应该有差异。但事实就是这样,XPS界面掩饰之下,问题层出不穷。我们右击my_stream_ip,选择View MPD,将内容改为:##############################################################################
##Filename:
E:\work\FPGA\ZynqProjects\axi_dma_final\axi_dma_final.srcs\sources_1\edk\system\pcores/my_stream_ip_v1_00_a/data/my_stream_ip_v2_1_0.mpd
## Description:
Microprocessor Peripheral Description
Sat May 11 19:51:06 2013 (by Create and Import Peripheral Wizard)
##############################################################################BEGIN my_stream_ip## Peripheral Options
OPTION IPTYPE = PERIPHERAL
OPTION IMP_NETLIST = TRUE
OPTION HDL = VERILOG
## Bus Interfaces
BUS_INTERFACE BUS=M_AXIS, BUS_STD=AXIS, BUS_TYPE=INITIATOR
BUS_INTERFACE BUS=S_AXIS, BUS_STD=AXIS, BUS_TYPE=TARGET## Parameters
PARAMETER C_S_AXIS_PROTOCOL = GENERIC, DT = string, TYPE =NON_HDL, ASSIGNMENT = CONSTANT, BUS = S_AXIS
PARAMETER C_S_AXIS_TDATA_WIDTH = 32, DT = integer, TYPE =NON_HDL, ASSIGNMENT = CONSTANT, BUS = S_AXIS
PARAMETER C_M_AXIS_PROTOCOL = GENERIC, DT = string, TYPE =NON_HDL, ASSIGNMENT = CONSTANT, BUS = M_AXIS
PARAMETER C_M_AXIS_TDATA_WIDTH = 32, DT = integer, TYPE =NON_HDL, ASSIGNMENT = CONSTANT, BUS = M_AXIS
## Peripheral ports
PORT ACLK = "", DIR=I, SIGIS=CLK, BUS=M_AXIS:S_AXIS
PORTARESETN = ARESETN, DIR=I, INITIALVAL = VCC
PORT S_AXIS_TREADY = TREADY, DIR=O, BUS=S_AXIS
PORT S_AXIS_TDATA = TDATA, DIR=I, VEC=[31:0], BUS=S_AXIS
PORT S_AXIS_TLAST = TLAST, DIR=I, BUS=S_AXIS
PORT S_AXIS_TVALID = TVALID, DIR=I, BUS=S_AXIS
PORT M_AXIS_TVALID = TVALID, DIR=O, BUS=M_AXIS
PORT M_AXIS_TDATA = TDATA, DIR=O, VEC=[31:0], BUS=M_AXIS
PORT M_AXIS_TLAST = TLAST, DIR=O, BUS=M_AXIS
PORT M_AXIS_TREADY = TREADY, DIR=I, BUS=M_AXIS
PORTM_AXIS_TKEEP = TKEEP, DIR=O, VEC=[3:0], BUS=M_AXIS
END这里存在两个问题:一个是ARESETN,在连接时AXI-DMA上没有合适的引脚与之相连,于是默认就接地了。接地不就复位了嘛!所以要显式声明接VCC。另一个问题是TKEEP信号,在上一篇文章AXI-Stream调试日记(三)里说过了,这里加上这个引脚,才能准确地将数据发回AXI-DMA。保存MPD文件,关闭。再次右击my_stream_ip,选择Browse HDL Sources。。。,打开my_stream_ip.v(或者my_stream_ip.vhd),内容改为:module my_stream_ip
// ADD USER PORTS BELOW THIS LINE
// -- USER ports added here
// ADD USER PORTS ABOVE THIS LINE
// DO NOT EDIT BELOW THISLINE ////////////////////
// Bus protocol ports, do not add or delete.
S_AXIS_TREADY,
S_AXIS_TDATA,
S_AXIS_TLAST,
S_AXIS_TVALID,
M_AXIS_TVALID,
M_AXIS_TDATA,
M_AXIS_TLAST,
M_AXIS_TREADY,
M_AXIS_TKEEP
// DO NOT EDIT ABOVE THIS LINE////////////////////
);// ADD USER PORTS BELOW THIS LINE
// -- USER ports added here
// ADD USER PORTS ABOVE THIS LINEinput
S_AXIS_TREADY;
S_AXIS_TDATA;
S_AXIS_TLAST;
S_AXIS_TVALID;
M_AXIS_TVALID;
M_AXIS_TDATA;
M_AXIS_TLAST;
M_AXIS_TREADY;
M_AXIS_TKEEP;
// ADD USER PARAMETERS BELOW THIS LINE
// --USER parameters added here
// ADD USER PARAMETERS ABOVE THIS LINE
//----------------------------------------
// Implementation Section
//----------------------------------------
// In this section, we povide an example implementation of MODULE my_stream_ip
// that does the following:
// 1. Read all inputs
// 2. Add each input to the contents of register 'sum' which
acts as an accumulator
// 3. After all the inputs have been read, write out the
content of 'sum' into the output streamNUMBER_OF_OUTPUT_WORDS times
// You will need to modify this example for
// MODULE my_stream_ip to implement your coprocessor
// Total number of input data.
localparam NUMBER_OF_INPUT_WORDS
// Total number of output data
localparam NUMBER_OF_OUTPUT_WORDS = 8;
// Define the states of state machine
localparam Idle
localparam Read_Inputs = 3'b010;
localparam Write_Outputs
// Accumulator to hold sum of inputs read at anypoint in time
reg [31:0]
// Counters to store the number inputs read &outputs written
reg [NUMBER_OF_INPUT_WORDS - 1:0] nr_of_
reg [NUMBER_OF_OUTPUT_WORDS - 1:0] nr_of_
// CAUTION:
// The sequence in which data are read in should be
// consistent with the sequence they are written in the
// driver's my_stream_ip.c file
assign S_AXIS_TREADY
= (state ==Read_Inputs);
assign M_AXIS_TVALID = (state == Write_Outputs);
assign M_AXIS_TDATA =
assign M_AXIS_TLAST =
(nr_of_writes == 1);
assignM_AXIS_TKEEP = 4'b1111;
always @(posedge ACLK)
// process The_SW_accelerator
if(!ARESETN)
// Synchronous reset (active low)
// CAUTION: makesure your reset polarity is consistent with the
// system resetpolarity
nr_of_reads <= 0;
nr_of_writes <=0;
case (state)
if(S_AXIS_TVALID == 1)
nr_of_reads <= NUMBER_OF_INPUT_WORDS - 1;
Read_Inputs:
if(S_AXIS_TVALID == 1)
// Coprocessor function (Adding) happens here
<= sum + S_AXIS_TDATA;
if (nr_of_reads == 0)
<= Write_O
nr_of_writes <= NUMBER_OF_OUTPUT_WORDS - 1;
nr_of_reads <= nr_of_reads - 1;
Write_Outputs:
if(M_AXIS_TREADY == 1)
if (nr_of_writes == 0)
state <= I
nr_of_writes <= nr_of_writes - 1;
endendmodule
这里修正了bug。VHDL代码见后面附件1. 完成上述更改后,点XPS菜单Project->RescanUser Repositories,实现用户配置更新。6.点Port标签,引脚连接。这里重点是将所有带CLK字样的都连接到PS7_FCLK_CLK0.如下图所示。7.点击Addresses标签,看看AXI-DMA是否分配了控制端口地址注意,如果你的axi-dma地址和途中不一样,那么在后面软件编写时一定要修改成你的地址。8.点Project->Design Rule Check;没错时,点Hardware->GenerateNetlist,完成后关闭XPS。9.在PlanAhead中完成综合、实现、出Bit步骤。其实上一步已经完成了综合,所以这一步速度就会非常快。10 导出SDK工程。建立Helloworld工程。将Helloworld.c里面的内容改为如下代码: #include
#include "platform.h"
#include "xil_cache.h" #define sendram ((int *)0x)
#define recvram ((int *)0x)
#define sizeofbuffer 32void print(char *str);
#define WITH_SG 0
#define AXI_DMA_BASE 0x#define MM2S_DMACR 0
#define MM2S_DMASR 1
#if WITH_SG
#define MM2S_CURDESC 2
#define MM2S_TAILDESC 4
#define MM2S_SA 6
#define MM2S_LENGTH 10
#define S2MM_DMACR 12
#define S2MM_DMASR 13
#if WITH_SG
#define S2MM_CURDESC 14
#define S2MM_TAILDESC 16
#define S2MM_DA 18
#define S2MM_LENGTH 22
#endifvoid debug_axi_dma_register(unsigned int * p)
printf("MM2S_DMACR = 0x%x\n",*(p+MM2S_DMACR));
printf("MM2S_DMASR = 0x%x\n",*(p+MM2S_DMASR));
#if WITH_SG
printf("MM2S_CURDESC = 0x%x\n",*(p+MM2S_CURDESC));
printf("MM2S_TAILDESC = 0x%x\n",*(p+MM2S_TAILDESC));
printf("MM2S_SA = 0x%x\n",*(p+MM2S_SA));
printf("MM2S_LENGTH = 0x%x\n",*(p+MM2S_LENGTH));
printf("S2MM_DMACR = 0x%x\n",*(p+S2MM_DMACR));
printf("S2MM_DMACSR = 0x%x\n",*(p+S2MM_DMASR));
#if WITH_SG
printf("S2MM_CURDESC = 0x%x\n",*(p+S2MM_CURDESC));
printf("S2MM_TAILDESC = 0x%x\n",*(p+S2MM_TAILDESC));
printf("S2MM_DA = 0x%x\n",*(p+S2MM_DA));
printf("S2MM_LENGTH = 0x%x\n",*(p+S2MM_LENGTH));
void init_axi_dma_simple(unsigned int * p)
*(p+MM2S_DMACR) = 0x04;
//reset send axi dma
while(*(p+MM2S_DMACR)&0x04);
*(p+S2MM_DMACR) = 0x04;
//reset send axi dma
while(*(p+S2MM_DMACR)&0x04);
*(p+MM2S_DMACR)=1;
while((*(p+MM2S_DMASR)&0x01));
*(p+S2MM_DMACR)=1;
while((*(p+S2MM_DMASR)&0x01));
*(p+MM2S_SA) = (unsigned int )
*(p+S2MM_DA) = (unsigned int )
Xil_DCacheFlushRange((u32)sendram,sizeofbuffer);
*(p+S2MM_LENGTH) =//sizeof(recvram);
*(p+MM2S_LENGTH) =//sizeof(sendram);
while(!(*(p+MM2S_DMASR)&0x1000)); //wait for send ok}
void init_sendbuffer()
for(i=0;i<100;i++)
sendram=i*2;//50*sinf(2*3.14*i/10);
void show_recvbuffer()
printf("Recv contents are:\n");
for(i=0;i<100;i++)
printf("%d\t",recvram);
printf("\r\n");
void show_sendbuffer()
printf("Send contents are:\n");
for(i=0;i<100;i++)
printf("%d\t",sendram);
printf("\r\n");
int main()
unsigned int status=0;
init_platform();
init_sendbuffer();
init_axi_dma_simple((unsigned int*)AXI_DMA_BASE);
printf("Hello World\n\rPlease input data:");
scanf("%x",&status);
printf("Got 0x%x\n",status);
debug_axi_dma_register((unsigned int *)AXI_DMA_BASE);
if(status==0)
show_sendbuffer();
show_recvbuffer();
cleanup_platform();
保存,等待生成elf。然后连接板子,下载bit文件,Run App,打开串口终端,等待输出。发送的内容为连续的偶数0~14,接收到数据为56,只是个数为7个而不是8个。这个是因为我们的my_stream_ip的TLAST信号提前到达造成的(是故意这么做的,没问题)。好了,到这里,Stream接口例子就完成了。希望本文对正在调试stream接口的童鞋们有帮助。前面的文章对XPS痛批了一顿,现在回过头来,发现其实如果没有前面的那些尝试,也能解决问题,只不过对Stream接口的认识没有特别深入而已。Chipscope调试是和AXi总线协议的一次亲密接触,让我知道了问题所在,从而在后面的问题解决中提供更好的方式。否定之否定原则再一次发挥作用了。
【参赛手记】AXI-StreamIP调试日记(一)
前言:项目中用到Stream类型总线,便于处理连续数据流。本来以为AXIStream总线很简单,应该不会有问题,但恍惚一月过去了,中间遇到许多坎坷,绝大部分都是软件问题。环境:Windows XP 32bit;ISE14.2;超级终端;使用IP:AXI-Stream-FIFO,自定义Stream类型IPBSP:裸机正文:首先按照常规开发流程做了个最简单的实验,即
(1)建立PlanAhead工程
(2)添加Embeded IP
(3)添加AXI-Stream-FIFO IP
(4)生成自定义IP,选择类型为Stream,收发寄存器都是8个
(5)添加自定义StreamIP,将对应总线连接上,Stream对Stream接口,Lite对GP接口
(6)关闭XPS,综合,实现,出bit
(7)导出到SDK
(8)根据system.mcs里面的例子,写一简单的测试程序
(9)下载bit,下载程序,运行
(10)观察输出。测试代码很简单,如下所示。#include
#include "platform.h"
#include "xllfifo.h"
//包含AXI-FIFO-Stream控制接口头文件
#define r1 t1
//收发都是一个模块完成的,所以。。。
XLlFifot1;
//AXI-FIFO Stream控制模块
int sendram[8] = {1,2,3,4,5,6,7,8};
//发送缓冲区
int recvram[8] = {0,0,0,0,0,0,0,0};
//接收缓冲区
void print(char *str);#define AXI_FIFO_BASE 0x
//AXI-FIFO模块内存映射地址//下面都是寄存器偏移量(按字计,不是字节,因为这里使用unsigned int指针)
#define ISR 0
#define IER 1
#define TDFR 2
#define TDFV 3
#define TDFD 4
#define TLF 5
#define RDFR 6
#define RDFO 7
#define RDFD 8
#define RLF 9
#define LLR 10//用于调试,打印关键寄存器的值
void debug_register(unsigned int * p)
printf("ISR = 0x%x\n",*(p+ISR));
if(*(p+ISR))
unsigned int t = *(p+ISR);
*(p+ISR)=t&0
printf("ISR = 0x%x\n",*(p+ISR));
printf("IER = 0x%x\n",*(p+IER));
printf("TDFR = 0x%x\n",*(p+TDFR));
printf("TDFV = 0x%x\n",*(p+TDFV));
printf("TDFD = 0x%x\n",*(p+TDFD));
printf("TLF = 0x%x\n",*(p+TLF));
printf("RDFR = 0x%x\n",*(p+RDFR));
printf("RDFO = 0x%x\n",*(p+RDFO));
// printf("RDFD = 0x%x\n",*(p+RDFD));
// printf("RLF = 0x%x\n",*(p+RLF));
//千万别轻易读这个,会复位的!
printf("LLR = 0x%x\n",*(p+LLR));
int main()
{ int status=0;
//接收字节数
init_platform();
printf("Hello World\n\r");//
debug_register((unsigned int*)AXI_FIFO_BASE);
XLlFifo_Initialize(&t1,AXI_FIFO_BASE);//初始化AXI-FIFO模块
XLlFifo_Initialize(&r1,0x);//由于收发一体,故只需初始化一次
XLlFifo_Write(&t1,sendram,8*4);//写发送缓冲区的内容到发送FIFO
XLlFifo_TxSetLen(&r1,8*4);//启动发送过程
print("Transmit begin!\n\r");
debug_register((unsigned int *)AXI_FIFO_BASE);
if(XLlFifo_RxOccupancy(&r1))
//如果接收FIFO中有内容
rxlen=XLlFifo_RxGetLen(&r1);//先获取其长度
printf("Rcv Length:%d\n",rxlen);
XLlFifo_Read(&r1, recvram,rxlen);//读取接收内容
int sum=0,i;
for(i = 0;i<8;i++)
if(recvram!=sendram)//如果接收不等于发送
printf("Error in index%d\n",i);//那么就报错,并报告接收内容
sum++;//错误计数
if(sum==0)
printf("Success!\n");//无错,则成功
print("Transmit done!\n\r");
cleanup_platform();
的确很简单的代码,但是输出却表示收到任何东西,直接跳出了if(XLlFifo_RxOccupancy(&r1))
{},然后结束。不理解为什么,于是又做了如下尝试:XPS中去掉自定义IP,而是直接将AXI-FIFO的Stream端回环,发送连到接收,这样再关闭XPS,综合,实现,出bit,导出SDK,下载bit,下载elf,运行,居然运行成功!输出"Success!".
【参赛手记】AXI-StreamIP调试日记(二)
前言:项目中用到Stream类型总线,便于处理连续数据流。本来以为AXIStream总线很简单,应该不会有问题,但恍惚一月过去了,中间遇到许多坎坷,绝大部分都是软件问题(个人很鄙视用GUI操作,但还没有找到一种完全不用GUI的开发方法。如果有,吾愿毅然卸掉XPS!)环境:Windows XP 32bit;ISE14.2;超级终端;使用IP:AXI-Stream-FIFO,自定义Stream类型IPBSP:裸机正文:上回书说到,一旦去掉自定义Stream IP,就能正常使用AXI-FIFO-Stream模块了。停止前进,扎营御敌。通过Xilinx Forum搜索相关问题,看到有人提到是Stream 接口不一致造成的。回去找到XXX\ISE_DS\EDK\hw\XilinxProcessorIPLib\pcores\axi_fifo_mm_s_v2_01_a\data\
axi_fifo_mm_s_v2_1_0.mpd 文件,其中有接口内容如下:PORT AXI_STR_TXC_ACLK = ACLK, DIR = I, BUS = AXI_STR_TXC, SIGIS= CLK, INITIALVAL = VCC
PORT mm2s_cntrl_reset_out_n = ARESETN, DIR = O, BUS = AXI_STR_TXC, SIGIS = RST
PORT AXI_STR_TXC_TVALID = TVALID, DIR = O, BUS = AXI_STR_TXC, INITIALVAL = GND
PORT AXI_STR_TXC_TREADY = TREADY, DIR = I, BUS = AXI_STR_TXC
PORT AXI_STR_TXC_TLAST = TLAST, DIR = O, BUS = AXI_STR_TXC, INITIALVAL = GND
PORTAXI_STR_TXC_TKEEP
= TKEEP, DIR = O, BUS = AXI_STR_TXC,INITIALVAL = VCC, VEC = [((C_S_AXI_DATA_WIDTH/8)-1):0], ENDIAN = LITTLE
PORT AXI_STR_TXC_TDATA = TDATA, DIR = O, BUS = AXI_STR_TXC, INITIALVAL = GND,VEC = [(C_S_AXI_DATA_WIDTH-1):0], ENDIAN = LITTLE
PORT AXI_STR_TXD_ACLK = ACLK, DIR = I, BUS = AXI_STR_TXD, SIGIS = CLK,INITIALVAL = VCC
PORT mm2s_prmry_reset_out_n = ARESETN, DIR = O, BUS = AXI_STR_TXD, SIGIS = RST
PORT AXI_STR_TXD_TVALID = TVALID, DIR = O, BUS = AXI_STR_TXD, INITIALVAL = GND
PORT AXI_STR_TXD_TREADY = TREADY, DIR = I, BUS = AXI_STR_TXD
PORT AXI_STR_TXD_TLAST = TLAST, DIR = O, BUS = AXI_STR_TXD, INITIALVAL = GND
PORTAXI_STR_TXD_TKEEP
= TKEEP, DIR = O, BUS =AXI_STR_TXD, INITIALVAL = VCC, VEC = [((C_S_AXI_DATA_WIDTH/8)-1):0], ENDIAN =LITTLE
PORTAXI_STR_TXD_TDEST
= TDEST, DIR = O, BUS =AXI_STR_TXD, INITIALVAL = VCC, VEC = [3:0], ENDIAN = LITTLE
PORT AXI_STR_TXD_TDATA = TDATA, DIR = O, BUS = AXI_STR_TXD, INITIALVAL = GND,VEC = [(C_S_AXI_DATA_WIDTH-1):0], ENDIAN = LITTLE
PORT AXI_STR_RXD_ACLK = ACLK, DIR = I, BUS = AXI_STR_RXD, SIGIS = CLK,INITIALVAL = VCC
PORT s2mm_prmry_reset_out_n = ARESETN, DIR = O, BUS = AXI_STR_RXD, SIGIS = RST
PORT AXI_STR_RXD_TVALID = TVALID, DIR = I, BUS = AXI_STR_RXD
PORT AXI_STR_RXD_TREADY = TREADY, DIR = O, BUS = AXI_STR_RXD, INITIALVAL = GND
PORT AXI_STR_RXD_TLAST = TLAST, DIR = I, BUS = AXI_STR_RXD
PORTAXI_STR_RXD_TKEEP
= TKEEP, DIR = I, BUS =AXI_STR_RXD, VEC = [((C_S_AXI_DATA_WIDTH/8)-1):0], ENDIAN = LITTLE
PORTAXI_STR_RXD_TDEST
= TDEST, DIR = I, BUS =AXI_STR_RXD, VEC = [3:0], ENDIAN = LITTLE
PORT AXI_STR_RXD_TDATA = TDATA, DIR = I, BUS = AXI_STR_RXD, VEC =[(C_S_AXI_DATA_WIDTH-1):0], ENDIAN = LITTLE这个是AXI-FIFO-Stream 这个IP核的引脚描述,看到有TKEEP和TDEST这两个接口,在数据位宽32bit情况下这两个接口都是4bit的。再看我们利用大名鼎鼎的XPS自定义IP向导生成的Stream 类型IP核,是怎么定义对外接口的。module my_stream_fir
// ADD USER PORTS BELOW THIS LINE
// -- USER ports added here
// ADD USER PORTS ABOVE THIS LINE
// DO NOT EDIT BELOW THIS LINE ////////////////////
// Bus protocol ports, do not add or delete.
S_AXIS_TREADY,
S_AXIS_TDATA,
S_AXIS_TLAST,
S_AXIS_TVALID,
M_AXIS_TVALID,
M_AXIS_TDATA,
M_AXIS_TLAST,
M_AXIS_TREADY
// DO NOT EDIT ABOVE THIS LINE ////////////////////
);哈,直接忽略掉了TDEST和TKEEP,好轻松随意!莫非就是因为这两个引脚造成的无法通信?其实这时,最应该做的一件事,就是搞清楚TKEEP和TDEST到底是什么意思。ARM官方文档上有说明,这里先卖个关子,暂时不表。我们先看看这两个信号到底是谁引起无法通信的。Q1:在XPS里,想把某总线的一部分信号线断开,一部分信号线连上,这个功能可以用GUI实现吗?我没有用XPS做这件事。我觉得XPS简直就是鸡肋,灵活性极差,很多功能都不支持,不同的IP核接口的各种不匹配!我本来想在XPS中添加一个AXI-Stream总线监视器Chipscope IP,但是一直报错,说TDEST位宽不一致,查了一下chipscope_axi_monitor_v2_1_0.mpd这个档案,发现有一句PARAMETER C_MON_AXI_S_TDEST_WIDTH = 1,而AXI-FIFO-Stream的TDEST宽度固定为4bit,导致不能连接。XPS中不能直接修改自带IP的MPD!论坛上有人修改MHS文件来实现匹配,觉得不够直接。于是,用了一计瞒天过海,不让XPS知道连接方式,而是将AXI-FIFO-Stream的TXD和RXD引脚全部设为External,我们可以轻松绕开XPS这个傻×,做自己想做的事。关掉XPS,在PlanAhead里面生成顶层模块,代码如下://-----------------------------------------------------------------------------
// module_1_stub.v
//-----------------------------------------------------------------------------module module_1_stub
processing_system7_0_MIO,
processing_system7_0_PS_SRSTB,
processing_system7_0_PS_CLK,
processing_system7_0_PS_PORB,
processing_system7_0_DDR_Clk,
processing_system7_0_DDR_Clk_n,
processing_system7_0_DDR_CKE,
processing_system7_0_DDR_CS_n,
processing_system7_0_DDR_RAS_n,
processing_system7_0_DDR_CAS_n,
processing_system7_0_DDR_WEB_pin,
processing_system7_0_DDR_BankAddr,
processing_system7_0_DDR_Addr,
processing_system7_0_DDR_ODT,
processing_system7_0_DDR_DRSTB,
processing_system7_0_DDR_DQ,
processing_system7_0_DDR_DM,
processing_system7_0_DDR_DQS,
processing_system7_0_DDR_DQS_n,
processing_system7_0_DDR_VRN,
processing_system7_0_DDR_VRP//删除和Stream IP相关的引脚,我们并不是真的连接到物理引脚,而是在顶层模块里实现连接
inout [53:0] processing_system7_0_MIO;
input processing_system7_0_PS_SRSTB;
input processing_system7_0_PS_CLK;
input processing_system7_0_PS_PORB;
inout processing_system7_0_DDR_C
inout processing_system7_0_DDR_Clk_n;
inout processing_system7_0_DDR_CKE;
inout processing_system7_0_DDR_CS_n;
inout processing_system7_0_DDR_RAS_n;
inout processing_system7_0_DDR_CAS_n;
output processing_system7_0_DDR_WEB_
inout [2:0] processing_system7_0_DDR_BankA
inout [14:0] processing_system7_0_DDR_A
inout processing_system7_0_DDR_ODT;
inout processing_system7_0_DDR_DRSTB;
inout [31:0] processing_system7_0_DDR_DQ;
inout [3:0] processing_system7_0_DDR_DM;
inout [3:0] processing_system7_0_DDR_DQS;
inout [3:0] processing_system7_0_DDR_DQS_n;
inout processing_system7_0_DDR_VRN;
inout processing_system7_0_DDR_VRP;
//下面这一堆本来是input或output,这里都改成wire类型
wire axi_fifo_mm_s_0_mm2s_prmry_reset_out_n_
wire axi_fifo_mm_s_0_AXI_STR_TXD_TVALID_
wire axi_fifo_mm_s_0_AXI_STR_TXD_TREADY_
wire axi_fifo_mm_s_0_AXI_STR_TXD_TLAST_
wire [3:0] axi_fifo_mm_s_0_AXI_STR_TXD_TKEEP_
wire [3:0] axi_fifo_mm_s_0_AXI_STR_TXD_TDEST_
wire [31:0] axi_fifo_mm_s_0_AXI_STR_TXD_TDATA_
wire axi_fifo_mm_s_0_s2mm_prmry_reset_out_n_
wire axi_fifo_mm_s_0_AXI_STR_RXD_TVALID_
wire axi_fifo_mm_s_0_AXI_STR_RXD_TREADY_
wire axi_fifo_mm_s_0_AXI_STR_RXD_TLAST_
wire [3:0] axi_fifo_mm_s_0_AXI_STR_RXD_TKEEP_
wire [3:0] axi_fifo_mm_s_0_AXI_STR_RXD_TDEST_
wire [31:0] axi_fifo_mm_s_0_AXI_STR_RXD_TDATA_
wire processing_system7_0_FCLK_CLK0_
//这个也顺便从XPS里引出,方便做同步时钟//下面实现手动连接总线引脚,先全都连上assign axi_fifo_mm_s_0_AXI_STR_RXD_TVALID_pin =axi_fifo_mm_s_0_AXI_STR_TXD_TVALID_
assign axi_fifo_mm_s_0_AXI_STR_TXD_TREADY_pin =axi_fifo_mm_s_0_AXI_STR_RXD_TREADY_
assign axi_fifo_mm_s_0_AXI_STR_RXD_TLAST_pin =axi_fifo_mm_s_0_AXI_STR_TXD_TLAST_
assign axi_fifo_mm_s_0_AXI_STR_RXD_TKEEP_pin = axi_fifo_mm_s_0_AXI_STR_TXD_TKEEP_
assign axi_fifo_mm_s_0_AXI_STR_RXD_TDEST_pin =axi_fifo_mm_s_0_AXI_STR_TXD_TDEST_
assign axi_fifo_mm_s_0_AXI_STR_RXD_TDATA_pin =axi_fifo_mm_s_0_AXI_STR_TXD_TDATA_
(* BOX_TYPE = "user_black_box" *)
module_1_i (
.processing_system7_0_MIO (processing_system7_0_MIO ),
.processing_system7_0_PS_SRSTB (processing_system7_0_PS_SRSTB ),
.processing_system7_0_PS_CLK (processing_system7_0_PS_CLK ),
.processing_system7_0_PS_PORB ( processing_system7_0_PS_PORB),
.processing_system7_0_DDR_Clk (processing_system7_0_DDR_Clk ),
.processing_system7_0_DDR_Clk_n (processing_system7_0_DDR_Clk_n ),
.processing_system7_0_DDR_CKE (processing_system7_0_DDR_CKE ),
.processing_system7_0_DDR_CS_n (processing_system7_0_DDR_CS_n ),
.processing_system7_0_DDR_RAS_n (processing_system7_0_DDR_RAS_n ),
.processing_system7_0_DDR_CAS_n (processing_system7_0_DDR_CAS_n ),
.processing_system7_0_DDR_WEB_pin (processing_system7_0_DDR_WEB_pin ),
.processing_system7_0_DDR_BankAddr (processing_system7_0_DDR_BankAddr ),
.processing_system7_0_DDR_Addr (processing_system7_0_DDR_Addr ),
.processing_system7_0_DDR_ODT (processing_system7_0_DDR_ODT ),
.processing_system7_0_DDR_DRSTB (processing_system7_0_DDR_DRSTB ),
.processing_system7_0_DDR_DQ (processing_system7_0_DDR_DQ ),
.processing_system7_0_DDR_DM (processing_system7_0_DDR_DM ),
.processing_system7_0_DDR_DQS (processing_system7_0_DDR_DQS ),
.processing_system7_0_DDR_DQS_n (processing_system7_0_DDR_DQS_n ),
.processing_system7_0_DDR_VRN (processing_system7_0_DDR_VRN ),
.processing_system7_0_DDR_VRP (processing_system7_0_DDR_VRP ),
.axi_fifo_mm_s_0_AXI_STR_TXD_ACLK_pin (axi_fifo_mm_s_0_AXI_STR_TXD_ACLK_pin ),
.axi_fifo_mm_s_0_mm2s_prmry_reset_out_n_pin (axi_fifo_mm_s_0_mm2s_prmry_reset_out_n_pin ),
.axi_fifo_mm_s_0_AXI_STR_TXD_TVALID_pin (axi_fifo_mm_s_0_AXI_STR_TXD_TVALID_pin ),
.axi_fifo_mm_s_0_AXI_STR_TXD_TREADY_pin (axi_fifo_mm_s_0_AXI_STR_TXD_TREADY_pin ),
.axi_fifo_mm_s_0_AXI_STR_TXD_TLAST_pin (axi_fifo_mm_s_0_AXI_STR_TXD_TLAST_pin ),
.axi_fifo_mm_s_0_AXI_STR_TXD_TKEEP_pin (axi_fifo_mm_s_0_AXI_STR_TXD_TKEEP_pin ),
.axi_fifo_mm_s_0_AXI_STR_TXD_TDEST_pin (axi_fifo_mm_s_0_AXI_STR_TXD_TDEST_pin ),
.axi_fifo_mm_s_0_AXI_STR_TXD_TDATA_pin (axi_fifo_mm_s_0_AXI_STR_TXD_TDATA_pin ),
.axi_fifo_mm_s_0_AXI_STR_RXD_ACLK_pin (axi_fifo_mm_s_0_AXI_STR_RXD_ACLK_pin ),
.axi_fifo_mm_s_0_s2mm_prmry_reset_out_n_pin (axi_fifo_mm_s_0_s2mm_prmry_reset_out_n_pin ),
.axi_fifo_mm_s_0_AXI_STR_RXD_TVALID_pin (axi_fifo_mm_s_0_AXI_STR_RXD_TVALID_pin ),
.axi_fifo_mm_s_0_AXI_STR_RXD_TREADY_pin (axi_fifo_mm_s_0_AXI_STR_RXD_TREADY_pin ),
.axi_fifo_mm_s_0_AXI_STR_RXD_TLAST_pin (axi_fifo_mm_s_0_AXI_STR_RXD_TLAST_pin ),
.axi_fifo_mm_s_0_AXI_STR_RXD_TKEEP_pin (axi_fifo_mm_s_0_AXI_STR_RXD_TKEEP_pin ),
.axi_fifo_mm_s_0_AXI_STR_RXD_TDEST_pin (axi_fifo_mm_s_0_AXI_STR_RXD_TDEST_pin ),
.axi_fifo_mm_s_0_AXI_STR_RXD_TDATA_pin (axi_fifo_mm_s_0_AXI_STR_RXD_TDATA_pin ),
.processing_system7_0_FCLK_CLK3_pin (processing_system7_0_FCLK_CLK3_pin )
//为了便于观察,添加了Chipscope模块,一会可以看波形的!
wire [35:0]
chipscope_icon_v1_06_a_0 myicon (
.CONTROL0(mycontrol) // INOUT BUS[35:0]
chipscope_ila_v1_05_a_0 myila (
.CONTROL(mycontrol), // INOUT BUS[35:0]
.CLK(processing_system7_0_FCLK_CLK0_pin),// IN
.TRIG0({axi_fifo_mm_s_0_AXI_STR_RXD_TVALID_pin,
axi_fifo_mm_s_0_AXI_STR_TXD_TREADY_pin,
axi_fifo_mm_s_0_AXI_STR_RXD_TLAST_pin,
axi_fifo_mm_s_0_AXI_STR_RXD_TKEEP_pin,
axi_fifo_mm_s_0_AXI_STR_RXD_TDEST_pin,
axi_fifo_mm_s_0_AXI_STR_RXD_TDATA_pin}) // IN BUS [42:0]
endmodule 好了,这回再综合,实现,出bit,导出SDK,下载bit,下载elf,运行。结果正常!先讲到这里,下次再做对照试验。
【参赛手记】AXI-Stream IP调试日记(三) 
前言:项目中用到Stream类型总线,便于处理连续数据流。本来以为AXIStream总线很简单,应该不会有问题,但恍惚一月过去了,中间遇到许多坎坷,绝大部分都是软件问题(个人很鄙视用GUI操作,但还没有找到一种完全不用GUI的开发方法。如果有,吾愿毅然卸掉XPS!)环境:Windows XP 32bit;ISE 14.2;超级终端;使用IP:AXI-Stream-FIFO,自定义Stream类型IPBSP:裸机正文:书接上回。为了和前面的实验形成对照,我们需要保证每次只有一个量是不同的。首先,为了便于Chipscope调试,我们将软件代码稍微修改,改成一个死循环,不至于运行一次就清场,Chipscope不好捕捉。再说一句Xilinx的坏话吧,SDK和Chipscope协调真是费劲,如果想先下载、运行elf,再用chipscope捕捉信号,程序运行快得让你措手不及。如果先让Chipscope一直处于捕捉状态,后下载代码,你妹呀,SDK直接挂掉,说JTAG电缆没连!看来这俩软件是互斥的,不能同时占用JTAG,所以必须修改代码,让代码运行起来之后就不再需要SDK的支持,而是我们手动通过串口来控制软件的执行。软件代码如下: #include#include"platform.h"#include"xllfifo.h"#define r1 t1XLlFifo t1;int sendram[8] ={1,2,3,4,5,6,7,8};int recvram[8] ={0,0,0,0,0,0,0,0};void print(char*str); #defineAXI_FIFO_BASE 0x#define ISR 0#define IER 1#define TDFR 2#define TDFV 3#define TDFD 4#define TLF 5#define RDFR 6#define RDFO 7#define RDFD 8#define RLF 9#define LLR 10voiddebug_register(unsigned int * p){
printf("ISR = 0x%x\n",*(p+ISR));
if(*(p+ISR))
unsigned int t = *(p+ISR);
*(p+ISR)=t&0
printf("ISR = 0x%x\n",*(p+ISR));
printf("IER = 0x%x\n",*(p+IER));
printf("TDFR = 0x%x\n",*(p+TDFR));
printf("TDFV = 0x%x\n",*(p+TDFV));
printf("TDFD = 0x%x\n",*(p+TDFD));
printf("TLF = 0x%x\n",*(p+TLF));
printf("RDFR = 0x%x\n",*(p+RDFR));
printf("RDFO = 0x%x\n",*(p+RDFO));//
printf("RDFD = 0x%x\n",*(p+RDFD));//
printf("RLF = 0x%x\n",*(p+RLF));
printf("LLR = 0x%x\n",*(p+LLR));}int main(){
int status=0;
init_platform();
printf("Hello World\n\r");
//死循环,进去出不来了…………………………
debug_register((unsigned int *)AXI_FIFO_BASE);
XLlFifo_Initialize(&t1,AXI_FIFO_BASE); //
XLlFifo_Initialize(&r1,0x);
XLlFifo_Write(&t1,sendram,8*4);
XLlFifo_TxSetLen(&r1,8*4);
print("Transmit begin!\n\r");//
debug_register((unsigned int *)AXI_FIFO_BASE);
if(XLlFifo_RxOccupancy(&r1))
rxlen=XLlFifo_RxGetLen(&r1);
printf("Rcv Length:%d\n",rxlen);
XLlFifo_Read(&r1, recvram,rxlen);
int sum=0,i;
for(i = 0;i<8;i++)
if(recvram!=sendram)
printf("Error in index %d,value = %d\n",i,recvram);
if(sum==0)
printf("Success!\n");
print("Transmit done!\n\r");
scanf("%d",&status);
//串口输入一个数,然后放行。这样可以手动控制软件运行
cleanup_platform();
return 0;} 这样,打开Chipscope,先连接设备,设置一下总线名称以利于阅读,捕获得到波形如下图所示可见TDATA,TLAST,TVALID波形完全正确,按照顺序发送走了1,2,3,4,5,6,7,8.。TDEST一直等于4’b0000,TKEEP一直等于4’b1111。好了,对照试验要进行了。实验1:乐不思蜀
将顶层模块中TDEST连线注释掉。//assign
axi_fifo_mm_s_0_AXI_STR_RXD_TDEST_pin =axi_fifo_mm_s_0_AXI_STR_TXD_TDEST_经过试验发现,不影响试验的正确性!实验2:兵粮寸断将顶层模块中TKEEP连线注释掉。//assign
axi_fifo_mm_s_0_AXI_STR_RXD_TKEEP_pin =axi_fifo_mm_s_0_AXI_STR_TXD_TKEEP_
同时将实验1中的注释打开。经过实验发现,接收数据字节数为4,与发送字节数32相比大相径庭。 看一下Chipscope波形:可见,当TKEEP信号为4‘b0000时,数据完全不能通行(即所谓“兵粮寸断”)。找到了数据不通的原因,我们就可以解释TDEST和TKEEP信号的含义了。TKEEP信号位宽数=TDATA字节数TKEEP某一bit负责监视TDATA相应字节。如果该字节有效,则对应bit=1;否则,bit=0时,认为该字节为NULL字节,空字节,无效字节,接收端直接丢弃。TDEST在多机通信中用于指定接收端地址。由于本实验不涉及多机通信,只是点对点通信,所以该信号不起作用。有了上面的基础,我又做了一个尝试,将TDEST和TKEEP都断开,RXD端TKEEP直接赋值为4'b1111,RXD端TDEST直接赋值为4'b0000.实验结果表明完全正确!
【参赛手记】AXI总线学习 
自从拿到ZED板卡,就开始接触ARM+FPGA这个神奇的架构。AXI,是这两者之间最佳的通信手段。xps中用户自定义IP核可以拥有AXI-Lite,AXI4,AXI-Stream,PLB和FSL这些接口。其中AXI-Lite具有轻量级,结构简单的特点,适合小批量数据、简单控制场合。AXI4和AXI-Lite差不多,只是增加了一项功能就是突发传输,可以连续对一片地址进行一次性读写。上面两种均采用内存映射控制方式,即ARM将用户自定义IP编入某一地址进行访问,读写时就像在读写自己的片内RAM,编程也很方便,开发难度较低。代价就是资源占用过多,需要额外的读地址线、写地址线、读数据线、写数据线、写应答线这些信号线,而且传输速度受限(主要是因为采用AXI-GP物理接口,带宽很低)。另外一种AXI接口就是AXI-Stream,这是一种连续传输的接口技术,速度能达到很高,而且不需要地址线(有点像FIFO,你就一直读或一直写就行)。这类IP不能通过上面的内存映射方式控制,必须有一个转换装置,例如AXI-Interconnector,AXI-DMA模块就能实现内存映射到流式接口的转换,但编程较复杂,调试起来没有内存映射方式直观,必须要通过芯片内部调试接口(Chipscope)来观察。AXI-Stream适用的场合有很多:视频流处理;通信协议转换;数字信号处理;无线通信等。其本质都是针对数值流构建的数据通路,从信源(例如ARM内存、DMA、无线接收前端等)到信宿(例如HDMI显示器、音频输出等)构建起连续的数据流。这种接口适合做实时信号处理。当然,实际处理中也有分块和不分块的情况,典型分块情况就是计算FFT。后面两种貌似在ZED上面用处不大,都是Microblaze的接口。不过应该也有桥接IP。没有研究。我们项目中属于典型的流式数据,从射频前端、ADC采集到信号传输到DDR2内存,组织为时分复用或并行通路来传输数值数据到自定义IP,并携带额外信息(当前帧均衡器的系数),利用控制流通道传输过去。处理结果仍传回DDR2中,交给主机显示或存储为文件。和DDR2的通信需要借助AXI-HP物理接口,PL部分为master,负责数据搬移。通过以上论述,应该比较清楚的看到整个数据走向了。具体实施细节还需要进一步研究。
【参赛手记】System Generator与XPS连接的方法 
【项目信息】
基于ZED-Board实现的宽带实时自适应均衡系统由于项目需要用到DSP算法实现,考虑用SystemGenerator辅助设计算法,但在参赛赠送的书里没有相关知识,需要自己动手摸索。还好在Matlab Simulink 内包含库XilinxBlocksets里右键发现了帮助文档,进入之后了解了怎么用Xilinx器件来完成算法设计,并生成网表。最重要的器件应该是Gatewayin和gatewayout,将matlab内的模块与Xilinx模块隔离,实现数位精度变换。这两个元件相当于input和output,在生成实例的时候可以看到。 看了帮助文档后,做个实验,只用PL部分,不用PS部分,用Project Navigator新建一个工程,添加一个SysGen模块,里面什么都不用做,直接将Gatewayin连接到Gatewayout,位数设为8bit,无小数部分。然后新建顶层verilog模块,生成一个SysGen的实例(有模板可用),将输入通过UCF约束到电路板的SW,输出约束到LED,生成.bit,下载到PL上,很容易就成功实现了。在此基础上,再次进入matlab,在Gatewayin和Gatewayout之间加入一个移位器模块,设为左移,重新生成.bit下载,也成功了。 单独的DSP模块显然功能很有限,必须要和双核ARM9连接起来才有价值。新建planahead工程,参考懒兔子的自定义IP部分,生成mygpio模块,然后连接到AXI总线,这时不要连接到外部引脚,而是连接到顶层模块的内部信号线。在planahead里面,新建SysGen模块,搭建自己的算法,生成模块,回到planahead。之前的内部信号线连接到SysGen模块的输入。还是像懒兔子一样导出软件工程,开发方法没有差别。下载.bit文件配置PL部分,然后运行程序。这时就可以发现,你通过串口写到slave寄存器里的值,通过SysGen模块的处理,就能迅速反馈给你。这就说明,通过planahead顶层模块可以实现SysGen和XPS的互联,属于系统互联,这里涉及到两个系统,一个是DSP子系统,一个是PS子系统,二者都在planahead顶层模块被实例化,然后用信号线互联。这是最近两天的摸索,算法实现总算有了点眉目。另外看到在SysGen里面支持AXI4总线,而且可以导出为XPS工程,还有待进一步研究,找到更紧密的连接方式,这样可以进一步提高数据在DSP模块和XPS之间的传输效率。如果大家有什么好的建议,请不要吝啬及时告诉我一声~~~~ 时间真是快,还有很多值得去研究的内容,包括GAL均衡算法优化,多种算法(LMS,RLS,基于小波的。。。)性能对比,盲均衡技术实现(CMA,DF)等。。。除了算法实现外还有信号类型分析(DRM,DTV,GSM,4G),时不我与,不再多说,回去继续埋头学习。。。}

我要回帖

更多关于 zynq axidma 中断 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信