Part Number:TMS320C6678
Hi,
I am using all cores of the C6678 for parallel data processing. The different concurrent tasks issue EDMA requests and wait busily for the respective completion interrupts. It is possible to concurrently issue transfer requests by different DSP cores to the channel controller? Or is there a general limitation with several cores accessing the same EDMA CC?
I use the CSL for the EDMA calls. For this question let's assume that I use only the channel controller CSL_EDMA3_TPCC0.
The program works fine if I use only one core. If several cores are used, interrupts are missed and the system hangs while waiting busily.
- There is at maximum one EDMA transfer ongoing for each core.
- If I ensure mutual exclusive access to the EDMA channel controller (covering the EDMA setup until the completion interrupt), I can safely use up to all eight cores.
I suspect one of the following problems:
- The EDMA CC queues are not initialized correctly.
- There is a problem with the interrupt registration or the assignment of the shadow regions.
Do you see a problem with my EDMA initialization? Is there anything else that has to be done differently?
Thank you!
P.S.: Here are the most important parts of the code I am using:
bool edmaTransfer() { // is called concurrently CSL_Edma3Handle hModule; CSL_Edma3ChannelHandle hChannel; CSL_Edma3CmdIntr regionIntr; CSL_Edma3Context context; CSL_Edma3Obj edmaObj; CSL_Edma3CmdDrae regionAccess; CSL_Edma3ChannelAttr chAttr; CSL_Edma3ChannelObj chObj; CSL_Edma3ParamHandle hParamStart; CSL_Status statusCode; CSL_InstNum ccNum = 0; uint8_t channelNum = ccNum; /* Module Initialization */ if (! initEdmaHandle(channelNum, ccNum, context, edmaObj, statusCode, regionAccess, chAttr, chObj, hModule, regionIntr, hChannel, hParamStart)) { return false; } // Set EDMA loop index space CSL_Edma3ParamSetup paramSetup; if (! setEdmaParams(paramSetup, channelNum)) { return false; } /* Setup the Ping Entry which loaded after the Pong entry gets exhausted */ if (CSL_edma3ParamSetup(hParamStart,¶mSetup) != CSL_SOK) { return false; } /* Enable channel */ if (CSL_edma3HwChannelControl(hChannel,CSL_EDMA3_CMD_CHANNEL_ENABLE, NULL) != CSL_SOK) { return false; } if ((statusCode = CSL_edma3HwChannelControl(hChannel,CSL_EDMA3_CMD_CHANNEL_SET,NULL)) != CSL_SOK) { return false; } do { /* Poll on interrupt bit 0 */ CSL_edma3GetHwStatus(hModule,CSL_EDMA3_QUERY_INTRPEND, ®ionIntr); } while (!(regionIntr.intr & (0x1 << channelNum))); /* Clear interrupt bit 0 */ if (CSL_edma3HwControl(hModule,CSL_EDMA3_CMD_INTRPEND_CLEAR, ®ionIntr) != CSL_SOK) { return false; } /* Close channel */ if (CSL_edma3ChannelClose(hChannel) != CSL_SOK) { return false; } /* Close EDMA module */ if (CSL_edma3Close(hModule) != CSL_SOK) { return false; } return true; } bool initEdmaHandle(uint8_t channelNum, CSL_InstNum instNum, CSL_Edma3Context& context, CSL_Edma3Obj& edmaObj, CSL_Status& statusCode, CSL_Edma3CmdDrae& regionAccess, CSL_Edma3ChannelAttr& chAttr, CSL_Edma3ChannelObj& chObj, CSL_Edma3Handle& hModule, CSL_Edma3CmdIntr& regionIntr, CSL_Edma3ChannelHandle& hChannel, CSL_Edma3ParamHandle& hParamStart) { int32_t regionNum = DNUM; // core number /* Module Initialization */ if (CSL_edma3Init(&context) != CSL_SOK) { return false; } /* Module level open */ hModule = CSL_edma3Open(&edmaObj, instNum, NULL, &statusCode); if ((hModule == NULL) || (statusCode != CSL_SOK)) { return false; } // sprugs5b 2.9.1: // If the channel is used in the context of a shadow region and you intend for the shadow region interrupt to be asserted, // then ensure that the bit corresponding to the TCC code is enabled in IER/IERH // and in the corresponding shadow region's DMA region access registers (DRAE/DRAEH). regionAccess.region = regionNum; regionAccess.drae = (0x1 << channelNum); regionAccess.draeh = 0x0; if (CSL_edma3HwControl(hModule, CSL_EDMA3_CMD_DMAREGION_ENABLE, ®ionAccess) != CSL_SOK) { return false; } /* Interrupt enable (Bits 0-11) for the shadow region 5 */ regionIntr.region = regionNum; regionIntr.intr = (0x1 << channelNum); regionIntr.intrh = 0x0000; if (CSL_edma3HwControl(hModule, CSL_EDMA3_CMD_INTR_ENABLE, ®ionIntr) != CSL_SOK) { return false; } /* Open the channel in context of the specified region number. */ chAttr.regionNum = regionNum; chAttr.chaNum = channelNum; hChannel = CSL_edma3ChannelOpen(&chObj, instNum, &chAttr, &statusCode); if ((hChannel == NULL) || (statusCode != CSL_SOK)) { return false; } int PaRAM_Set = DNUM; // core number /* Map the DMA Channel to the appropriate PARAM Block. We start with PING * which is located at PARAM Block 1. */ if (CSL_edma3HwChannelSetupParam(hChannel, PaRAM_Set) != CSL_SOK) { return false; } /* Obtain a handle to parameter set 1 */ hParamStart = CSL_edma3GetParamHandle(hChannel, PaRAM_Set, &statusCode); if (hParamStart == NULL) { return false; } return true; } // Calculate index space for EDMA transfer - values like aCnt, bCnt are calculated and stored elsewhere. bool setEdmaParams(CSL_Edma3ParamSetup& paramSetup, uint8_t channelNum) const { // Set EDMA parameters paramSetup.option = CSL_EDMA3_OPT_MAKE( CSL_EDMA3_ITCCH_DIS, CSL_EDMA3_TCCH_DIS,\ CSL_EDMA3_ITCINT_DIS, CSL_EDMA3_TCINT_EN, channelNum, CSL_EDMA3_TCC_NORMAL,\ CSL_EDMA3_FIFOWIDTH_NONE, CSL_EDMA3_STATIC_DIS, CSL_EDMA3_SYNC_AB,\ CSL_EDMA3_ADDRMODE_INCR, CSL_EDMA3_ADDRMODE_INCR ); paramSetup.aCntbCnt = CSL_EDMA3_CNT_MAKE(aCnt, bCnt); paramSetup.srcDstBidx = CSL_EDMA3_BIDX_MAKE(aCnt, aCnt); paramSetup.srcDstCidx = CSL_EDMA3_CIDX_MAKE(0, 0); paramSetup.cCnt = 1; paramSetup.linkBcntrld= CSL_EDMA3_LINKBCNTRLD_MAKE(CSL_EDMA3_LINK_NULL, 0); // no linked transfer paramSetup.srcAddr = reinterpret_cast<uint32_t>(makeAddressGlobal(src)); paramSetup.dstAddr = reinterpret_cast<uint32_t>(makeAddressGlobal(dest)); return true; }