EDMA 通道0能工作正常,当换成别的通道,比如说EDMA 通道1,OPT中TCC值保持不变。
传送完成,在IPR(IPRH)中置的不是TCC的那一位(ier对应的那一位),而是IPR(IPRH)别的位。
只有通道0是正常的,试了几个其他通道,发现最后结果都是iprh变成0x04000000,并且无法进入中断服务函数。
请问可能是什么原因造成的?
在网上看到有类似的错误,说是地址映射错误,但没有详细讲,可能是哪个地址映射错误?为什么只有通道0可以正常工作?
Nancy Wang:
是通过什么方式触发的?能否把相关代码贴出来看一下。
user4504841:
回复 Nancy Wang:
/******************************************************************************** @函数名称fpga_emif16_edma_test* @函数说明DSP-FPGA EMIF16+DMA通信测试* @输入参数无* @输出参数无* @返回参数无*******************************************************************************/ unsigned int chType= EDMA3_CHANNEL_TYPE_DMA; unsigned int chNum= 0; //使用通道号 unsigned int tccNum= 0; unsigned int edmaTC= 0; unsigned int syncType= EDMA3_SYNC_A; unsigned int trigMode= EDMA3_TRIG_MODE_MANUAL; unsigned int evtQ= 0; // 使用的事件队列 EDMA3CCPaRAMEntry paramSet; //unsigned int edma_paRAMId1 = 1; //unsigned int edma_paRAMId2 = 2;unsigned int transfer_times = 0;//实际传输次数volatile char *srcBuff; volatile char *dstBuff;unsigned short emif_wbuffer[EMIF_BUFFER_LENGTH]; unsigned short emif_rbuffer[EMIF_BUFFER_LENGTH]; unsigned short temp_rbuffer[EMIF_BUFFER_LENGTH];void fpga_emif16_edma_test(void) {volatile unsigned int status = FALSE;printf("EMIF EDMA testing...\r\n");EDMA3Init(SOC_EDMA30CC_0_REGS, evtQ);EDMA3InterruptInit();unsigned int i = 0;/*初始化数据缓冲区*/for (i = 0; i < EMIF_BUFFER_LENGTH; i++){emif_wbuffer[i] = (unsigned short)(i+15);emif_rbuffer[i] = 0xEFEF;}emif_wbuffer[0] = 0;emif_wbuffer[EMIF_BUFFER_LENGTH-1] = 0;/*向FPGA写数据*/printf( "Reading %d words from FPGA\r\n", EMIF_BUFFER_LENGTH );srcBuff = (char *)(SOC_EMIFA_CS1_ADDR);dstBuff = (char *)(emif_rbuffer);edma_test();volatile unsigned int EMIFA_error_count = 0;/*检查EMIFA传输的数据是否正确 */printf("Checking data...\n");for (i = 0; i<EMIF_BUFFER_LENGTH; i++){if (emif_wbuffer[i] != emif_rbuffer[i]){EMIFA_error_count++;}}/* 报告通信结果*/if (EMIFA_error_count){printf( "EMIFA_error_count=%d\n", EMIFA_error_count);while(1);}else{printf("All data read successful!\n");printf("EMIFA transfers complete!\n");}while(1); }/******************************************************************************** @函数名称edma_test* @函数说明edma测试* @输入参数无* @输出参数无* @返回参数无*******************************************************************************/ unsigned int edma_test(void) {volatile unsigned int index = 0;volatile unsigned int count = 0;unsigned int retVal = 0u;unsigned int numenabled = 0u;unsigned int acnt = MAX_ACOUNT;unsigned int bcnt = MAX_BCOUNT;unsigned int ccnt = MAX_CCOUNT;// 申请 DMA 通道和 TCCretVal = EDMA3RequestChannel(SOC_EDMA30CC_0_REGS, chType, chNum, tccNum, evtQ);// 注册回调函数cb_Fxn[tccNum] = &callback;if (TRUE == retVal){/*Set params for channel 0*/// 给参数 RAM 赋值paramSet.srcAddr= (unsigned int)(srcBuff);paramSet.destAddr= (unsigned int)(dstBuff);paramSet.aCnt = (unsigned short)acnt;paramSet.bCnt = (unsigned short)bcnt;paramSet.cCnt = (unsigned short)ccnt;// 设置 SRC / DES 索引paramSet.srcBIdx = (short)acnt;paramSet.destBIdx = (short)acnt;paramSet.srcCIdx = (short)acnt;paramSet.destCIdx = (short)acnt;//paramSet.linkAddr = (unsigned short)EDMA3CC_OPT(edma_paRAMId1);paramSet.linkAddr = (unsigned short)0xFFFFu;paramSet.bCntReload = (unsigned short)0u;paramSet.opt = 0u;// Src 及 Dest 使用 INCR 模式paramSet.opt &= 0xFFFFFFFCu;// Transfer complete chaining enable//paramSet.opt |= ((1 << EDMA3CC_OPT_TCCHEN_SHIFT) & EDMA3CC_OPT_TCCHEN);// Intermediate transfer completion interrupt enable//paramSet.opt |= ((1 << EDMA3CC_OPT_ITCCHEN_SHIFT) & EDMA3CC_OPT_ITCCHEN);// 编程 TCCparamSet.opt |= ((tccNum << EDMA3CC_OPT_TCC_SHIFT) & EDMA3CC_OPT_TCC);// 使能 Intermediate & Final 传输完成中断paramSet.opt |= (1 << EDMA3CC_OPT_ITCINTEN_SHIFT);paramSet.opt |= (1 << EDMA3CC_OPT_TCINTEN_SHIFT);// A Sync 传输模式paramSet.opt &= 0xFFFFFFFBu;// 写参数 RAMEDMA3SetPaRAM(SOC_EDMA30CC_0_REGS, chNum, ¶mSet);/*Set params for edma_paRAMId1*/ //paramSet.linkAddr = (unsigned short)EDMA3CC_OPT(edma_paRAMId1); //EDMA3SetPaRAM(SOC_EDMA30CC_0_REGS, edma_paRAMId1, ¶mSet);/*Set params for edma_paRAMId2*///paramSet.linkAddr = (unsigned short)EDMA3CC_OPT(edma_paRAMId1);//EDMA3SetPaRAM(SOC_EDMA30CC_0_REGS, edma_paRAMId2, ¶mSet);}if (TRUE == retVal){// A Sync 传输模式numenabled = bcnt * ccnt;transfer_times = 0;/*EMIFA+EDMA传输速率测试 */global.last_timer = global.timer;for (index = 0; index < numenabled; index++){irqRaised = 0;// 按照计算的次数使能传输retVal = EDMA3EnableTransfer(SOC_EDMA30CC_0_REGS, chNum, EDMA3_TRIG_MODE_MANUAL);if (TRUE != retVal){printf("edma3Test: EDMA3EnableTransfer Failed.\r\n");break;}// 等待中断服务函数执行完成while (irqRaised == 0u){}// 检测传输完成状态if (irqRaised < 0){// 发生错误时终止printf("\r\nedma3Test: Event Miss Occured!!!\r\n");// 清除错误标志位EDMA3ClearErrorBits(SOC_EDMA30CC_0_REGS, chNum, evtQ);break;}}printf("The rate of emif_edma_rate is %02fM/s.\r\n", (float)EMIF_BUFFER_LENGTH*TEST_TIMES/((global.timer - global.last_timer)*1000));//EDMA3EnableTransfer(SOC_EDMA30CC_0_REGS, chNum, EDMA3_TRIG_MODE_MANUAL);}if (TRUE == retVal){// 释放先前分配的通道retVal = EDMA3FreeChannel(SOC_EDMA30CC_0_REGS, EDMA3_CHANNEL_TYPE_DMA, chNum, EDMA3_TRIG_MODE_MANUAL, tccNum, evtQ);// 取消注册回调函数cb_Fxn[tccNum] = NULL;}return retVal; }只有chNum=0和tccNum=0的时候可以正常工作,这两个换成其他通道值均无法正常工作。
user4504841:
回复 Nancy Wang:
另外在C6654手册中看到EDMA完成中断和错误中断中断号分别为22和16:
但是在TI的驱动库中C:\ti\pdk_c665x_2_0_14\packages\ti\csl\src\ip\edma\V1\edma.h中看到定义的中断号有出入,分别为11和12:
edma.h
是不是定义错了?
user4504841:
回复 Nancy Wang:
初始化及配置相关代码:
/***\briefEDMA3 Initialization**This function initializes the EDMA3 Driver*Clears the error specific registers (EMCR/EMCRh, QEMCR, CCERRCLR) &*initialize the Queue Number Registers**\parambaseAddMemory address of the EDMA instance used.\n**\paramqueNumEvent Queue Number to which the channel*will be mapped (valid only for the*Master Channel (DMA/QDMA) request).\n**\return None**\noteThe regionId is the shadow region(0 or 1) used and the,*Event Queue used is either (0 or 1). There are only four shadow*regions and only two event Queues*/ void EDMA3Init(unsigned int baseAdd,unsigned int queNum) {unsigned int count = 0;unsigned int i = 0;#ifdef _TMS320C6X/* For DSP, regionId is assigned here and used globally in the driver */regionId = (unsigned int)1u; #else/* FOR ARM, regionId is assigned here and used globally in the driver*/regionId = (unsigned int)0u; #endif/* Clear the Event miss Registers*/HWREG(baseAdd + EDMA3CC_EMCR) = EDMA3_SET_ALL_BITS;HWREG(baseAdd + EDMA3CC_EMCRH) = EDMA3_SET_ALL_BITS;HWREG(baseAdd + EDMA3CC_QEMCR) = EDMA3_SET_ALL_BITS;/* Clear CCERR register*/HWREG(baseAdd + EDMA3CC_CCERRCLR) = EDMA3_SET_ALL_BITS;/* FOR TYPE EDMA*//* Enable the DMA (0 - 64) channels in the DRAE and DRAEH register */HWREG(baseAdd + EDMA3CC_DRAE(regionId)) = EDMA3_SET_ALL_BITS;HWREG(baseAdd + EDMA3CC_DRAEH(regionId)) = EDMA3_SET_ALL_BITS;if((EDMA_REVID_AM335X == EDMAVersionGet())){for(i = 0; i < 64; i++){/* All events are one to one mapped with the channels */HWREG(baseAdd + EDMA3CC_DCHMAP(i)) = i << 5;}}/* Initialize the DMA Queue Number Registers*/for (count = 0;count < SOC_EDMA3_NUM_DMACH; count++){HWREG(baseAdd + EDMA3CC_DMAQNUM(count >> 3u)) &=EDMA3CC_DMAQNUM_CLR(count);HWREG(baseAdd + EDMA3CC_DMAQNUM(count >> 3u)) |=EDMA3CC_DMAQNUM_SET(count,queNum);}/* FOR TYPE QDMA *//* Enable the DMA (0 - 64) channels in the DRAE register*/HWREG(baseAdd + EDMA3CC_QRAE(regionId)) = EDMA3_SET_ALL_BITS;/* Initialize the QDMA Queue Number Registers*/for (count = 0;count < SOC_EDMA3_NUM_QDMACH; count++){HWREG(baseAdd + EDMA3CC_QDMAQNUM) &= EDMA3CC_QDMAQNUM_CLR(count);HWREG(baseAdd + EDMA3CC_QDMAQNUM) |=EDMA3CC_QDMAQNUM_SET(count,queNum);} }/****************************************************************************/ /**/ /*EDMA3 中断初始化*/ /**/ /****************************************************************************/ void EDMA3InterruptInit() {CICDisableGlobalHostInt(SOC_CIC_0_REGS);CICEventMap(SOC_CIC_0_REGS, CIC_INT_EDMA3_0_CC0_INT1, uiCIC_out_num);CICEventMap(SOC_CIC_0_REGS, CIC_INT_EDMA3_0_CC0_ERRINT, uiCIC_out_num+1);CICEnableGlobalHostInt(SOC_CIC_0_REGS);// 传输完成中断IntRegister(C66X_MASK_INT7, EDMA3CCComplIsr);IntEventMap(C66X_MASK_INT7, SYS_INT_CIC0_OUT0_20);IntEnable(C66X_MASK_INT7);// 传输错误中断IntRegister(C66X_MASK_INT8, EDMA3CCErrIsr);IntEventMap(C66X_MASK_INT8, SYS_INT_CIC0_OUT1_20);IntEnable(C66X_MASK_INT8); }/***\brief Request a DMA/QDMA/Link channel.**Each channel (DMA/QDMA/Link) must be requestedbefore initiating a DMA*transfer on that channel.**This API is used to allocate a logical channel (DMA/QDMA/Link) along with*the associated resources. For DMA and QDMA channels, TCC and PaRAM Set are*also allocated along with the requested channel.**User can request a specific logical channel by passing the channel number*in 'chNum'.**For DMA/QDMA channels, after allocating all the EDMA3 resources, this API*sets the TCC field of the OPT PaRAM Word with the allocated TCC. It also sets*the event queue for the channel allocated. The event queue needs to be*specified by the user.**For DMA channel, it also sets the DCHMAP register.**For QDMA channel, it sets the QCHMAP register and CCNT as trigger word and*enables the QDMA channel by writing to the QEESR register.**\parambaseAddMemory address of the EDMA instance used.\n**\paramchtype(DMA/QDMA) Channel*For Example: For DMA it is*EDMA3_CHANNEL_TYPE_DMA.\n**\paramchNumThis is the channel number requested for a*particular event.\n**\paramtccNumThe channel number on which the*completion/error interrupt is generated.*Not used if user requested for a Link*channel.\n**\paramevtQNumEvent Queue Number to which the channel*will be mapped (valid only for the*Master Channel (DMA/QDMA) request).\n**\returnTRUE if parameters are valid, else FALSE*/ unsigned int EDMA3RequestChannel(unsigned int baseAdd,unsigned int chType,unsigned int chNum,unsigned int tccNum,unsigned int evtQNum) {unsigned int retVal = FALSE;if (chNum < SOC_EDMA3_NUM_DMACH){/* Enable the DMA channel in the enabled in the shadow region* specific register*/EDMA3EnableChInShadowReg(baseAdd, chType, chNum);EDMA3MapChToEvtQ( baseAdd, chType, chNum, evtQNum);if (EDMA3_CHANNEL_TYPE_DMA == chType){/* Interrupt channel nums are < 32 */if (tccNum < SOC_EDMA3_NUM_DMACH){/* Enable the Event Interrupt*/EDMA3EnableEvtIntr(baseAdd, chNum);retVal = TRUE;}HWREG(baseAdd + EDMA3CC_OPT(chNum)) &= EDMA3CC_OPT_TCC_CLR;HWREG(baseAdd + EDMA3CC_OPT(chNum)) |= EDMA3CC_OPT_TCC_SET(chNum);}else if (EDMA3_CHANNEL_TYPE_QDMA== chType){/* Interrupt channel nums are < 8 */if (tccNum < SOC_EDMA3_NUM_QDMACH){/* Enable the Event Interrupt*/EDMA3EnableEvtIntr(baseAdd, chNum);retVal = TRUE;}HWREG(baseAdd + EDMA3CC_OPT(chNum)) &= EDMA3CC_OPT_TCC_CLR;HWREG(baseAdd + EDMA3CC_OPT(chNum)) |= EDMA3CC_OPT_TCC_SET(chNum);}}return retVal; }/*** \briefCopy the user specified PaRAM Set onto the PaRAM Set associated*with the logical channel (DMA/Link).** This API takes a PaRAM Set as input and copies it onto the actual PaRAM Set* associated with the logical channel. OPT field of the PaRAM Set is written* first and the CCNT field is written last.*** \parambaseAddMemory address of the EDMA instance used.\n** \paramchNumLogical Channel whose PaRAM set is*requested.\n** \paramnewPaRAMParameter RAM set to be copied onto existing*PaRAM.\n** \returnNone*/ void EDMA3SetPaRAM(unsigned int baseAdd,unsigned int chNum,EDMA3CCPaRAMEntry* newPaRAM) {unsigned int PaRAMId = chNum; /* PaRAM mapped to channel Number*/unsigned int i = 0;unsigned int *sr = (unsigned int *)newPaRAM;volatile unsigned int *ds;ds = (unsigned int *)(baseAdd + EDMA3CC_OPT(PaRAMId));for(i=0; i < EDMA3CC_PARAM_ENTRY_FIELDS; i++){*ds = *sr;ds++;sr++;} }/***\briefStart EDMA transfer on the specified channel.**There are multiple ways to trigger an EDMA3 transfer. The triggering mode*option allows choosing from the available triggering modes: Event,*Manual or QDMA.**In event triggered, a peripheral or an externally generated event triggers*the transfer. This API clears the Event and Event Miss Register and then*enables the DMA channel by writing to the EESR.**In manual triggered mode, CPU manually triggers a transfer by writing a 1*in the Event Set Register ESR. This API writes to the ESR to start the*transfer.**In QDMA triggered mode, a QDMA transfer is triggered when a CPU (or other*EDMA3 programmer) writes to the trigger word of the QDMA channel PaRAM set*(auto-triggered) or when the EDMA3CC performs a link update on a PaRAM set*that has been mapped to a QDMA channel (link triggered). This API enables*the QDMA channel by writing to the QEESR register.**\parambaseAddMemory address of the EDMA instance used.\n**\paramchNumChannel being used to enable transfer.\n**\paramtrigModeMode of triggering start of transfer (Manual,*QDMA or Event).\n**trigMode can have values:*EDMA3_TRIG_MODE_MANUAL\n*EDMA3_TRIG_MODE_QDMA\n*EDMA3_TRIG_MODE_EVENT\n**\returnretValTRUE or FALSE depending on the param passed.\n**/ unsigned int EDMA3EnableTransfer(unsigned int baseAdd,unsigned int chNum,unsigned int trigMode) {unsigned int retVal = FALSE;switch (trigMode){case EDMA3_TRIG_MODE_MANUAL :if (chNum < SOC_EDMA3_NUM_DMACH){EDMA3SetEvt(baseAdd, chNum);retVal = TRUE;}break;case EDMA3_TRIG_MODE_QDMA :if (chNum < SOC_EDMA3_NUM_QDMACH){EDMA3EnableQdmaEvt(baseAdd, chNum);retVal = TRUE;}break;case EDMA3_TRIG_MODE_EVENT :if (chNum < SOC_EDMA3_NUM_DMACH){/*clear SECR & EMCR to clean any previous NULL request*/EDMA3ClrMissEvt(baseAdd, chNum);/* Set EESR to enable event*/EDMA3EnableDmaEvt(baseAdd, chNum);retVal = TRUE;}break;default :retVal = FALSE;break;}return retVal; }
Nancy Wang:
回复 user4504841:
改变通道之后,数据搬移成功了吗?可以通过查看param中参数是否更新来确定。
user4504841:
回复 Nancy Wang:
数据没有搬运成功,param中参数也没有更新。
只有chNum = 0 & tccNum = 0时可以搬运成功,这两个值任何一个更改之后都无法搬运成功。
Nancy Wang:
回复 user4504841:
CICEventMap(SOC_CIC_0_REGS, CIC_INT_EDMA3_0_CC0_ERRINT, uiCIC_out_num+1)中CIC_INT_EDMA3_0_CC0_ERRINT的值是16吗?
不清楚头文件中定义的变量是指什么?在程序中能查到此变量应用在哪里吗?可以参考看一下。
Nancy Wang:
回复 user4504841:
感谢分享!