TI中文支持网
TI专业的中文技术问题搜集分享网站

这是一个将 EDMA搬数 应用于 PCIE 地址段的部分代码,搬不动数,求指教……

这是一个将  EDMA搬数 应用于 PCIE 地址段的部分代码,平台为C6678,结合一个EDMA的基础例程,已经实现了L2   DDR3  MSMC之间的互搬,但是PCIE的地址段就搬不动,是不是通道选择的问题,请问选择的通道之间有什么区别么?

2-24 KeyStone Architecture Peripheral Component Interconnect Express (PCIe) User Guide SPRUGS6D—September 2013
Submit Documentation Feedback
Chapter 2—Architecture www.ti.com
2.9.3.2 Memory Read Transfer
The following example details how to perform an EDMA transfer from PCIe memory
to the device destination (for example, L2 or EMIF). For the EDMA configuration,
please see the EDMA user’s guide.
Example 2-5 Memory Read
/* Configure PCIESS module and prepare transfer parameters*/
/* Initialize the PCIESS module */
/* Define payload size and buffer size */
pcie_max_payload = 128; /* Assume pcie maximum payload size is 128 bytes */
buff_size= 2048; /* Assume the transfer buffer size 2048 bytes */
/* Define PCIe data starting address for EDMA transfer */
pcieAddr = <PCIe data starting address defined in device-specific data manual>

/* Setup EDMA module and enable the DMA region */
/* Setup EDMA PARAM */
/* The OPT register contains following bit fields:
ITCCHEN = 0x0; TCCHEN = 0x0; ITCINTEN = 0x0; TCINTEN = 0x1;
TCC = 0x0; TCCMODE = 0x0; FWID = 0x0; STATIC = 0x0; SYNCDIM = 0x1; DAM
= 0x0; SAM = 0x0 */
paramSetup_pcie.option = CSL_EDMA3_OPT_MAKE(0,0,0,1,0,0,0,0,1,0,0);
paramSetup_pcie.aCntbCnt = CSL_EDMA3_CNT_MAKE(pcie_max_payload,
buff_size/pcie_max_payload);
paramSetup_pcie.srcDstBidx =
CSL_EDMA3_BIDX_MAKE(pcie_max_payload,pcie_max_payload);
paramSetup_pcie.srcDstCidx = CSL_EDMA3_CIDX_MAKE(0,0);
paramSetup_pcie.cCnt = 1;
paramSetup_pcie.linkBcntrld =
CSL_EDMA3_LINKBCNTRLD_MAKE(CSL_EDMA3_LINK_NULL,0);
paramSetup_pcie.srcAddr = (Uint32)pcieAddr;
paramSetup_pcie.dstAddr = (Uint32)dstAddr;
/* Setup EDMA Channel */
/* Enable the EDMA Channel */
/* Wait for a transmit completion */
End of Example 2-5

EDMA的例子为:

#include <stdio.h>
#include <math.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <ti/csl/csl_chip.h>
#include <c6x.h>

#include <ti/csl/csl_chip.h>
#include <ti/csl/src/intc/csl_intc.h>
#include <ti/csl/csl_cpintcAux.h>
#include "csl_edma3.h"
#include "csl_edma3Aux.h"

#pragma DATA_SECTION(srcbuf,".EXRAM") //DDR3 0x80000000
#pragma DATA_SECTION(dstbuf,".MSRAM") //共享内存 0x0C000000

unsigned char srcbuf[512],dstbuf[512];

CSL_Edma3ParamHandle hParamPing;
CSL_Edma3ParamSetup myParamSetup;
CSL_Edma3ChannelHandle hChannel;
CSL_Edma3Handle hMoudle;

int Edma3Example()
{
CSL_Edma3Obj edmaObj;
CSL_Edma3ChannelObj chObj;
CSL_Edma3CmdIntr regionIntr;
CSL_Edma3Context context;
CSL_Edma3ChannelAttr chAttr;
CSL_Status status;

unsigned char channelNum = 0;
unsigned char instNum = 1;

CSL_edma3Init(&context);

hMoudle = CSL_edma3Open(&edmaObj,instNum,NULL,&status);

chAttr.regionNum = CSL_EDMA3_REGION_GLOBAL;
chAttr.chaNum = channelNum;
hChannel = CSL_edma3ChannelOpen(&chObj,instNum,&chAttr,&status);

CSL_edma3HwChannelSetupQue(hChannel,CSL_EDMA3_QUE_0);

CSL_edma3MapDMAChannelToParamBlock(hMoudle,channelNum,0);

hParamPing = CSL_edma3GetParamHandle(hChannel,0,&status);

regionIntr.region = CSL_EDMA3_REGION_GLOBAL;
regionIntr.intr = 0x1;
regionIntr.intrh = 0x0;
CSL_edma3HwControl(hMoudle,CSL_EDMA3_CMD_INTR_ENABLE,&regionIntr);

myParamSetup.option = 0x00100008;
myParamSetup.srcAddr = (Uint32)srcbuf;
myParamSetup.aCntbCnt = 0x00010040;
myParamSetup.dstAddr = (Uint32)dstbuf;
myParamSetup.srcDstBidx = 0x0;
myParamSetup.linkBcntrld = 0x0000ffff;
myParamSetup.srcDstCidx = 0x0;
myParamSetup.cCnt = 0x00000001;
CSL_edma3ParamSetup(hParamPing,&myParamSetup);

CSL_edma3HwChannelControl(hChannel,CSL_EDMA3_CMD_CHANNEL_SET,NULL);

regionIntr.region = CSL_EDMA3_REGION_GLOBAL;
regionIntr.intr = 0x0;
regionIntr.intrh = 0x0;
do
{
CSL_edma3GetHwStatus(hMoudle,CSL_EDMA3_QUERY_INTRPEND,&regionIntr);
}
while (!(regionIntr.intr & 0x1));

CSL_edma3HwControl(hMoudle,CSL_EDMA3_CMD_INTRPEND_CLEAR,&regionIntr);

CSL_edma3ChannelClose(hChannel);

CSL_edma3Close(hMoudle);

return 0;
}

void main()
{
int i,j;

for(i=0;i<512;i++)
{
srcbuf[i] = 0xFF; //src为数据发送端,存放在DDR3上
dstbuf[i] = 0x00; //dst为数据接收端,存放在MSMC上
//数据搬了64个下来
}

printf("srcbuf的地址为0x%08x=%d,dstbuf的地址为0x%08x=%d\n",srcbuf,srcbuf[0],dstbuf,dstbuf[0]);
Edma3Example();
printf("srcbuf的地址为0x%08x=%d,dstbuf的地址为0x%08x=%d\n",srcbuf,srcbuf[0],dstbuf,dstbuf[0]);
printf("dstbuf[0] = %d\n",dstbuf[0]);
printf("dstbuf[63] = %d\n",dstbuf[63]);
printf("dstbuf[64] = %d\n",dstbuf[64]);

}

对应的CMD文件为:

-c
-heap 0x2000
-stack 0x2000

MEMORY
{
VECTORS: origin=0x10800000 length=0x00000400
LL2MEM: origin=0x10800400 length=0x0007FC00
MSMCRAM: origin=0x0C000000 length=0x00400000
DDR3RAM: origin=0x80000000 length=0x20000000
}

SECTIONS
{
.csl_vect > VECTORS
.text > LL2MEM
.data > LL2MEM
.fasttext > LL2MEM
.cinit > LL2MEM
.bss > LL2MEM
.const > LL2MEM
.far > LL2MEM
.switch > LL2MEM
.sysmem > LL2MEM
.cio > LL2MEM
.heap > LL2MEM
.fardata > LL2MEM
.neardata > LL2MEM
.rodata > LL2MEM
.INRAM > LL2MEM
.MSRAM > MSMCRAM
.EXRAM > DDR3RAM
}

lieying fan:

我参考了www.ti.com/lit/sprugs6d,就是官网提供的pcie user guide文档,里面在用edma搬移0X60000000地址段的数据时,提供了一个例程,我使用myParamSetup.option=0x00100008这种设置,可以实现内存之间的搬移,但是如果配置源地址和目的地址为0X60000000时,就不能实现正常搬移,将myParamSetup.option修改为0x00100004,还是搬不动数,我想问一下会是edma通道选择的问题么?

Andy Yin1:

参考下面STK的PCIe例程先对PCIe进行初始化。

http://www.deyisupport.com/question_answer/dsp_arm/c6000_multicore/f/53/t/47664.aspx

lieying fan:

回复 Andy Yin1:

现在的问题是,用edma搬数或者直接地址调用,只能对一个32bit空间进行操作,一旦超过这个限制,搬移的数就都是零,我确信应该是pcie的哪个东西配置有问题,各位大神有没有解决办法?

lieying fan:

回复 lieying fan:

之前查看一个帖子,网址忘了,上面只提到一句话,说是需要配置EDMA通道链,进行传输,正在尝试。但是又一个问题来了,我之前用

int Edma3Example(){ CSL_Edma3Obj edmaObj; CSL_Edma3ChannelObj chObj; CSL_Edma3CmdIntr regionIntr; CSL_Edma3Context context; CSL_Edma3ChannelAttr chAttr; CSL_Status status;

unsigned char channelNum = 0; unsigned char instNum = 1;

CSL_edma3Init(&context);

hMoudle = CSL_edma3Open(&edmaObj,instNum,NULL,&status);

chAttr.regionNum = CSL_EDMA3_REGION_GLOBAL; chAttr.chaNum = channelNum; hChannel = CSL_edma3ChannelOpen(&chObj,instNum,&chAttr,&status);

CSL_edma3HwChannelSetupQue(hChannel,CSL_EDMA3_QUE_0);

CSL_edma3MapDMAChannelToParamBlock(hMoudle,channelNum,0);

hParamPing = CSL_edma3GetParamHandle(hChannel,0,&status);

regionIntr.region = CSL_EDMA3_REGION_GLOBAL; regionIntr.intr = 0x1; regionIntr.intrh = 0x0; CSL_edma3HwControl(hMoudle,CSL_EDMA3_CMD_INTR_ENABLE,&regionIntr);

//Clear cache CACHE_wbInvAllL1d(CACHE_WAIT); CACHE_wbInvAllL2(CACHE_WAIT); _mfence(); _mfence();

myParamSetup.option = 0x00100008; myParamSetup.srcAddr = (Uint32)srcbuf; myParamSetup.aCntbCnt = 0x00010040; myParamSetup.dstAddr = (Uint32)dstbuf; myParamSetup.srcDstBidx = 0x0; myParamSetup.linkBcntrld = 0x0000ffff; myParamSetup.srcDstCidx = 0x0; myParamSetup.cCnt = 0x00000001; CSL_edma3ParamSetup(hParamPing,&myParamSetup);

CSL_edma3HwChannelControl(hChannel,CSL_EDMA3_CMD_CHANNEL_SET,NULL);

regionIntr.region = CSL_EDMA3_REGION_GLOBAL; regionIntr.intr = 0x0; regionIntr.intrh = 0x0; do { CSL_edma3GetHwStatus(hMoudle,CSL_EDMA3_QUERY_INTRPEND,&regionIntr); } while (!(regionIntr.intr & 0x1));

CSL_XMC_invalidatePrefetchBuffer();

CSL_edma3HwControl(hMoudle,CSL_EDMA3_CMD_INTRPEND_CLEAR,&regionIntr);

CSL_edma3ChannelClose(hChannel);

CSL_edma3Close(hMoudle);

return 0;}

这个函数,在一个自编译的子工程中使用,没有问题。进行了如下操作,将DDR3的数据搬移到MSMC上,然后清空MSMC的存储区域,再将DDR3的数据搬移到MSMC已经清空的存储区中,采用单步执行的命令,可以看到MSMC存储区的数据交替变化,前后采用了一样的传输通道号。然后我将这个基于csl函数的edma引入到我的另一个大工程文件中,进行相同的操作,发现通道只能调用一次,就是edma第二次的搬移没有启动,但是我单步执行发现,传输PARARAM参数都传递进去了,就是CSL_edma3HwChannelControl(hChannel,CSL_EDMA3_CMD_CHANNEL_SET,NULL);没响应,不知道什么原因,既然CSL号称可移植性很强,这个小函数不至于还有什么没有配置完整吧?但是为什么单独测试的时候没有问题?为什么放在大工程中,edma的相同通道就只能使用一次呢?测试过换用不同通道进行搬移,是可以的。但是如果在循环中调用EDMA我总不至于设置EDMA CHannel++吧?

lieying fan:

回复 lieying fan:

现在讨论一下PCIE 使用EDMA传输的问题,既然PCIE端因为某种限制导致每次传输只能使用32bit的窗口,那么,考虑用EDMA()函数每次搬移0x0004,执行相同的操作512次,这样可以保证搬移512*32bit的存储区。但是问题来了,512次搬移的累加时间已经超出了我每个处理周期的时间限制Ts,我想应该是每次通道打开又关闭耗费了一定的时间,于是我在考虑能不能够在不关闭通道的情况下进行512次搬移,设置Acount=0x0004,Bcount=1,Count=1,然后myParamSetup.option = 0x00500004启用通道链,myParamSetup【1】.linkBcntrld = 0x00004020,myParamSetup【2】.linkBcntrld = 0x00004040……myParamSetup【512】.linkBcntrld = 0x0000FFFF,这样只需要开启一个通道O,就可以连续转载512次PARAMSET,传输完成后,只有myParamSetup【1】的参数会被更新,下次执行相同的读写操作,只需要重新配置myParamSetup【1】,而不需要对myParamSetup【2-512】进行配置。试了一把,发现可以实现传输。但是问题又来了,通道还是不能被二次使用。

一天以后,我在调用EDMA的for(i=0;i<10;i++)循环内添加了EDMA_INIT()函数,然后单步执行,发现有时候通道又能用,我逐个检查了EDMA的寄存器初始化前后的配置,发现,每次传输后,SER二级事件寄存器,EMR事件MISS寄存器会被置位,查阅文档发现,说是有传输事件被忽略,导致传输错误,于是我检查了之前成功传输的512个int整形数据,发现,确实有误码存在,那么这种方法出现了一个致命问题。

于是,还得从PCIE的地址翻译下手。

lieying fan:

回复 lieying fan:

函数继续上一个问题,之前发现有误码,是因为搬移地址为共享内存,共享内存处于写保护状态,结果造成搬移的数据出现异常,于是更改地址为ddr3地址段,重新测试,发现,方法有效,但是下次使用前,要手动设置各种清除寄存器进行清楚操作,但是事实证明,这种操作勉强能用。但是问题又来了,我无法使用其他的通道进行正常的搬移操作了,感觉受到了干扰,我想把用上述通道链方法搬出来的数搬移到其他地址上使用,结果每次搬到第23个int整形的数时,edma就停止工作了,但是之前的那种512个通道链的传输就没有问题。但是如果,我在使用完csl_edma()之后,加一条打印语句,搬移的结果就是正确无误的。会不会是打印给了edma将数据从总线上搬到目的地址的时间呢?但是edma传输完成不是会把通道对应位的ipr置位的么,难道while循环那里做了判断,等待传输完成,但实际上传输并没有结束么?那也太不可能了吧!求解释

studying:

回复 lieying fan:

您好,我想请问下PCIe 2.0支持同时双向传输数据么?

赞(0)
未经允许不得转载:TI中文支持网 » 这是一个将 EDMA搬数 应用于 PCIE 地址段的部分代码,搬不动数,求指教……
分享到: 更多 (0)