This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

AM62D-Q1: C7x DRU waits indefinitely

Part Number: AM62D-Q1
Other Parts Discussed in Thread: SYSCONFIG

Hi,

I’m looking for detailed documentation or reference material related to DRU (Data Routing Unit) on C7x. I haven’t been able to find sufficient information—could you please point me to the relevant documents or guides?

In parallel, I’m working on a FreeRTOS application on C7x using DRU.

I started by referring to the example available at: awe_sdk_am62dx_11_02_23_10\mcu_plus_sdk\am62dx\source\tisp\test\misc\TISP_blockCopy_superNode\TISP_blockCopy_superNode_test.cpp

The example builds and runs correctly. However, in my application, I’m facing an issue where the following line in DmaUtilsAutoInc3d_wait() hangs indefinitely:

while ((eflRegisterVal & waitWord) != waitWord)

The data transfer itself seems to have occurred correctly—I can see that the source buffer data has been copied to the destination buffer. However, the completion/wait condition is not being satisfied, causing the function to block.

Could you help identify what might be causing this issue, and also share any available DRU documentation?

below is the details about setup:

EVM - AM62D

SDK Version - 11.02.23.10

Thanks in advance.

  • Hi Gayathri,
    I am looking into the query. Please expect response within a day or two.

    Thanks,
    Shreyansh

  • Hi Gayathri,
    Can you share more details about your software? Are you using any other peripherals which is also using UDMA?

    Thanks,
    Shreyansh

  • Hi Shreyansh,

    I am working with DRU  to perform a simple memory copy from a source buffer to a destination buffer.
    The shared code is intended to demonstrate how I am using the APIs in my application and may not be fully validated or correct.

    Below is the sequence I am following:

    Initialize DRU using DmaUtilsAutoInc3d_init()
    Setup transfer properties (transferDim, transferProp)
    Prepare TR using DmaUtilsAutoInc3d_prepareTr()
    Configure the channel using DmaUtilsAutoInc3d_configure()
    Trigger the transfer using DmaUtilsAutoInc3d_trigger()
    Wait for completion using DmaUtilsAutoInc3d_wait()

    Issue:

    The code gets stuck in DmaUtilsAutoInc3d_wait() and never returns
    This suggests that the transfer completion event/interrupt is not being received

    To answer your question about the use of other peripherals using udma:

    this DRU transfer is part of a larger application where I am also using McASP for audio data handling.

    Thanks,

    Gayathri 



  • #include "drivers/dmautils/src/dmautils_autoincrement_3d_priv.h"
    #define DRU_LOCAL_EVENT_START_DEFAULT (128U) /* Default for AM62A/AM62D/AM275X ref: clec spec */
    #define DRU_NUM_OF_CHANNELS (16U)
    #define UDMA_TEST_NUM_BYTES         (256*4)

    uint32_t data_in_bytes = UDMA_TEST_NUM_BYTES;
    int32_t gdataBuf[UDMA_ALIGN_SIZE(UDMA_TEST_NUM_BYTES)] __attribute__((section(".staticData")));

    __attribute__((section(".ddrData"), aligned(128))) uint8_t    gUdmaSrcBuf[UDMA_TEST_NUM_BYTES];
    __attribute__((section(".l2sramData"), aligned(128))) uint8_t gUdmaDstBuf[UDMA_TEST_NUM_BYTES];

    uint8_t *pTrMemChs[4];
    Udma_DrvObjectInt _udmaDrvObj;
    struct DRUParams
        {
            DmaUtilsAutoInc3d_TransferDim transferDim;
            uint8_t *pTrMemChs;
            DmaUtilsAutoInc3d_TrPrepareParam trPrepParam;
            DmaUtilsAutoInc3d_TransferProp   transferProp;
            uint8_t *srcPtr;
            uint8_t *dstPtr;
            uint8_t *dmaUtilsContext;
            uint32_t *chIdIn;
            uint32_t *chIdOut;
        };
        DRUParams druParams;

    APP_INIT()
    {
      App_dmautilsClecInitDru()
      druParams.srcPtr = gUdmaSrcBuf;  
      druParams.dstPtr = gUdmaDstBuf;

      uint32_t transferSize = DMAUTILSAUTOINC3D_SYNC_2D;

      druInitTransferProp( &druParams, data_in_bytes);
      configure_channel( &druParams,0,transferSize, druParams.srcPtr, druParams.dstPtr);
      auto ctx = (DmaUtilsAutoInc3d_Context*)druParams.dmaUtilsContext;
      dru_write_trigger(&druParams, 0);
      wait(&druParams);
      printf("Transfer completed\r\n");
    }
    druInitTransferProp( DRUParams *druParams, uint32_t length)
    {
       int64_t _numChannels = 1; //num of DRU channels
       int32_t numTRs = 1; //number of TRs per transfer
       uint32_t retVal = UDMA_SOK;
       Udma_DrvHandle drvHandle;

       druParams->dmaUtilsContext = (uint8_t *) memalign(128, DmaUtilsAutoInc3d_getContextSize(_numChannels));
       if (druParams->dmaUtilsContext == nullptr)
       {
          printf("[DRU_INIT] ERROR: Failed to allocate DmaUtils context!\r\n");
       }
     
       for (size_t ch = 0; ch < _numChannels; ch++)
       {
          pTrMemChs[ch] = (uint8_t *) memalign(128, DmaUtilsAutoInc3d_getTrMemReq(numTRs));
          if (pTrMemChs[ch] == nullptr)
          {
             printf("[DRU_INIT] ERROR: Failed to allocate TRPD for channel %zu!\r\n", ch);
          }
       }
       drvHandle = setUdmaDrvHandle();

       DmaUtilsAutoInc3d_InitParam initParams;
       DmaUtilsAutoInc3d_ChannelInitParam chInitParams[_numChannels];

       initParams.contextSize     = DmaUtilsAutoInc3d_getContextSize(_numChannels);
       initParams.numChannels     = _numChannels;
       initParams.traceLogLevel   = 1;
       initParams.udmaDrvHandle   = drvHandle;
       initParams.DmaUtilsVprintf = vprintf;

       for (int32_t ch = 0; ch < _numChannels; ch++)
       {
          chInitParams[ch].dmaQueNo = 0;
          chInitParams[ch].druOwner = DMAUTILSAUTOINC3D_DRUOWNER_DIRECT_TR;
       }

       retVal = DmaUtilsAutoInc3d_init(druParams->dmaUtilsContext, &initParams, chInitParams);

       if (retVal != UDMA_SOK)
       {
         printf("[DRU_INIT] ERROR: DmaUtilsAutoInc3d_init failed with code %u!\r\n", retVal);
         return;
       }
       

       druParams->transferDim.sicnt0 = length * sizeof(int32_t);
       druParams->transferDim.sicnt1 = 1U;
       druParams->transferDim.sicnt2 = 1U;
       druParams->transferDim.sicnt3 = 1U;
       druParams->transferDim.sdim1  = druParams->transferDim.sicnt0;
       druParams->transferDim.sdim2  = (druParams->transferDim.sicnt0 * druParams->transferDim.sicnt1);
       druParams->transferDim.sdim3  = (druParams->transferDim.sicnt0 * druParams->transferDim.sicnt1 * druParams->transferDim.sicnt2);
       
       druParams->transferDim.dicnt0 = length * sizeof(int32_t);
       druParams->transferDim.dicnt1 = 1U;
       druParams->transferDim.dicnt2 = 1U;
       druParams->transferDim.dicnt3 = 1U;
       druParams->transferDim.ddim1  = druParams->transferDim.dicnt0;
       druParams->transferDim.ddim2  = (druParams->transferDim.dicnt0 * druParams->transferDim.dicnt1);
       druParams->transferDim.ddim3  = (druParams->transferDim.dicnt0 * druParams->transferDim.dicnt1 * druParams->transferDim.dicnt2);

       printf("[DRU_INIT] druInitTransferProp COMPLETE\r\n");
    }
    uint32_t configure_channel( DRUParams *druParams,uint32_t ch,uint32_t syncType,uint8_t *srcPtr,uint8_t *dstPtr)
    {
       uint32_t                  retVal = UDMA_SOK;
       
       // Verify pTrMemChs is properly initialized
       if (pTrMemChs[ch] == nullptr)
       {
          printf("[Error] pTrMemChs[%u] is NULL - DRU not properly initialized!\r\n", ch);
       }
       
       druParams->trPrepParam.channelId = ch;
       druParams->trPrepParam.numTRs    = 1;
       druParams->trPrepParam.trMem     = pTrMemChs[ch];
       druParams->trPrepParam.trMemSize = DmaUtilsAutoInc3d_getTrMemReq(1); //num of Trs

       // ========== CIRCULAR BUFFER CONFIGURATION ==========
       druParams->transferProp.circProp.circDir       = DMAUTILSAUTOINC3D_CIRCDIR_SRC;
       druParams->transferProp.circProp.circSize1     = 0;
       druParams->transferProp.circProp.circSize2     = 0;
       druParams->transferProp.circProp.addrModeIcnt0 = DMAUTILSAUTOINC3D_ADDR_LINEAR;
       druParams->transferProp.circProp.addrModeIcnt1 = DMAUTILSAUTOINC3D_ADDR_LINEAR;
       druParams->transferProp.circProp.addrModeIcnt2 = DMAUTILSAUTOINC3D_ADDR_LINEAR;
       druParams->transferProp.circProp.addrModeIcnt3 = DMAUTILSAUTOINC3D_ADDR_LINEAR;
       druParams->transferProp.syncType          = syncType;
       druParams->transferProp.dmaDfmt           = DMAUTILSAUTOINC3D_DFMT_NONE;
       druParams->transferProp.ioPointers.srcPtr = srcPtr;
       druParams->transferProp.ioPointers.dstPtr = dstPtr;
       druParams->transferProp.transferDim       = druParams->transferDim;
       retVal = DmaUtilsAutoInc3d_prepareTr(&druParams->trPrepParam, &druParams->transferProp);

       if (UDMA_SOK != retVal)
       {
          printf("[DRU_CFG_CH] ERROR: TR prepare failed! Code=%u\r\n", retVal);
       }
       else
       {
          printf("[DRU_CFG_CH] Configuring channel %u...\r\n", ch);
          retVal = DmaUtilsAutoInc3d_configure(druParams->dmaUtilsContext, ch,pTrMemChs[ch], druParams->trPrepParam.numTRs);
          if (UDMA_SOK != retVal)
          {
             printf("[DRU_CFG_CH] ERROR: Channel configure failed! Code=%u\r\n", retVal);
          }
          else
          {
             printf("[DRU_CFG_CH] Channel configure SUCCESS\r\n");
          }
       }
       return retVal;
    }  
    uint32_t  dru_write_trigger(DRUParams *druParams,uint32_t ch)
    {
       printf("[DRU_TRIGGER] Triggering DRU channel %u...\r\n", ch);  
       uint32_t retVal = DmaUtilsAutoInc3d_trigger(druParams->dmaUtilsContext, ch);
       if (retVal != UDMA_SOK)
       {
          printf("[DRU_TRIGGER] ERROR: Trigger failed! Code=%u\r\n", retVal);
       }
       else
       {
          printf("[DRU_TRIGGER] Trigger issued successfully\r\n");
       }
       return retVal;
    }
    void StdMuteModule::wait(DRUParams *druParams)
    {
        printf("[DRU_WAIT] About to call DmaUtilsAutoInc3d_wait (blocking until ISR posts semaphore)\r\n");
        DmaUtilsAutoInc3d_wait(druParams->dmaUtilsContext, 0);//0-ch
        printf("[DRU_WAIT] DmaUtilsAutoInc3d_wait returned - ISR fired and DMA complete!\r\n");
    }

    void  App_dmautilsClecInitDru(void)
    {
       printf("[CLEC_INIT] Initializing CLEC event routing for DRU channels...\r\n");
       
       CSL_ClecEventConfig cfgClec;
       CSL_CLEC_EVTRegs   *clecBaseAddr;
       uint32_t            clusterId;

       clusterId = CSL_clecGetC7xClusterId();
       printf("[CLEC_INIT] C7x Cluster ID: %u\r\n", clusterId);

       if (clusterId == CSL_C75_CPU_CLUSTER_NUM_C75_1) {
          clecBaseAddr = (CSL_CLEC_EVTRegs *) CSL_C7X256V0_CLEC_BASE;
          printf("[CLEC_INIT] Using CLEC base for C75_1\r\n");
       }
    #if (CSL_C7X256V_MAIN_CNT == 2U)
       else if (clusterId == CSL_C75_CPU_CLUSTER_NUM_C75_2) {
          clecBaseAddr = (CSL_CLEC_EVTRegs *) CSL_C7X256V1_CLEC_BASE;
          }
    #endif
       else {
          clecBaseAddr = (CSL_CLEC_EVTRegs *) NULL;
         
       }
          uint32_t i;
          uint32_t dru_input_start = DRU_LOCAL_EVENT_START_DEFAULT;
          uint32_t dru_input_num   = DRU_NUM_OF_CHANNELS;      
         
          /* Only configuring 16 channels */
          for (i = dru_input_start; i < (dru_input_start + dru_input_num); i++)
          {
             /* Configure CLEC */
             cfgClec.secureClaimEnable = FALSE;
             cfgClec.evtSendEnable     = TRUE;
             cfgClec.rtMap             = CSL_CLEC_RTMAP_CPU_ALL;
             cfgClec.extEvtNum         = 0;
             cfgClec.c7xEvtNum         = (i - dru_input_start) + 32;
             CSL_clecConfigEvent(clecBaseAddr, i, &cfgClec);
          }
    }
  • Hi Gayathri,

    Can you use interrupt number 25 and let me know if it works? Interrupt number 32 is also used by MCASP which might be conflicting in your application.

             cfgClec.c7xEvtNum         = (i - dru_input_start) + 32;

    Instead of 32 here, use 25.

    And, can you also enable the skipGlobalEvenReg flag in the udma in sysconfig?

    Thanks,
    Shreyansh


  • Hi Shreyansh,

         I have used interrupt number 25 instead of 32. now it is working.
    Thank you for your guidance. 

         Could you point me to the relevant documentation about DRU.
          I'd like to understand more about it.

    Thanks,

    Gayathri    

  • Hi Gayathri,
    Thanks for the confirmation.

     Could you point me to the relevant documentation about DRU.
          I'd like to understand more about it.

    Let me check internally, and get back to you.

    Thanks,
    Shreyansh

  • Hi,
    Thanks for your earlier explanation—it helped me resolve the issue.

    While moving forward, I have another doubt. I have configured multiple TRs within a single DRU channel.

    1. Is it possible to trigger one TR at a time within the same channel?

    2. Does DmaUtilsAutoInc3d_trigger() trigger all configured TRs in a single call?

    3. If I want to trigger only one TR at a time, is there any specific configuration or flag that needs to be set?

    Could you please clarify how TR triggering works in this case?

    Thanks,

    Gayathri