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.

QDMA Function Does Not Work

Hello,

Can anyone tell me why my QDMA function runs but when I print out srcBuff1 and dstBuff1, dstBuff1 is not filled with srcBuff1?

/* Global Variables */
Uint8 srcBuff1[512];
Uint8 dstBuff1[512];

/* EDMA Setup */
#define PCIE_DMA_NOT_INITIALIZED -1
#define PCIE_DMA_TRANSFER_FAIL -1
#define PCIE_DMA_NOT_CLOSED -1
#define SUCCESS 0

/*****************************************************************************
* Function: Transfer srcBuff to dstBuff
****************************************************************************/
int DMA_All_in_One_Transfer(void) {

CSL_Edma3Handle hModule;
CSL_Edma3Obj edmaObj;
CSL_Edma3ParamHandle hParamBlock;
CSL_Edma3ChannelObj chObj;
CSL_Edma3CmdIntr regionIntr;
CSL_Edma3CmdDrae regionAccess;
CSL_Edma3ChannelHandle hChannel;
CSL_Edma3ParamSetup myParamSetup;
CSL_Edma3Context context;
CSL_Edma3ChannelAttr chAttr;
CSL_Edma3CmdQrae qraeSetup;
CSL_Status status;

Uint32 channelNum = 16;
Uint32 instNum= 0;
int regionNum = -1;
Uint32 loopIndex;

printf ("Testing EDMA(%d), (Shadow) Region %d, for QDMA Channel %d...\n",
instNum, regionNum, channelNum);

/* Initialize data */

for (loopIndex = 0; loopIndex < 256; loopIndex++) {
srcBuff1[loopIndex] = loopIndex;
dstBuff1[loopIndex] = 0;
}

/* Module initialization */
if (CSL_edma3Init(&context) != CSL_SOK)
{
printf ("Error: EDMA module initialization failed\n");
return PCIE_DMA_NOT_INITIALIZED;
}

/* Module level open */
hModule = CSL_edma3Open(&edmaObj, instNum, NULL, &status);
if ((hModule == NULL) || (status != CSL_SOK))
{
printf ("Error: EDMA module open failed\n");
return PCIE_DMA_NOT_INITIALIZED;
}

/* Is this for GLOBAL or SHADOW Region */
if (regionNum != CSL_EDMA3_REGION_GLOBAL)
{
/* Shadow Region: Enable DRAE enable(Bits 0-15) it. */
regionAccess.region = regionNum;
regionAccess.drae = 0xFFFF;
regionAccess.draeh = 0x0000;
if (CSL_edma3HwControl(hModule,CSL_EDMA3_CMD_DMAREGION_ENABLE, &regionAccess) != CSL_SOK)
{
printf ("Error: EDMA region enable command failed\n");
return -1;
}

/* Enable access for all QDMA channels in the SHADOW Region. */
qraeSetup.region = regionNum;
qraeSetup.qrae = 0xFF;
if (CSL_edma3HwControl(hModule,CSL_EDMA3_CMD_QDMAREGION_ENABLE, &qraeSetup) != CSL_SOK)
{
printf ("Error: EDMA QDMA region enable command failed\n");
return -1;
}
}

/* QDMA Channel Open */
chAttr.regionNum = CSL_EDMA3_REGION_GLOBAL;
chAttr.chaNum = channelNum;
hChannel = CSL_edma3ChannelOpen(&chObj, instNum, &chAttr, &status);
if ((hChannel == NULL) || (status != CSL_SOK))
{
printf ("Error: EDMA channel open failed\n");
return PCIE_DMA_NOT_INITIALIZED;
}

/* Map QDMA Channel to the Param Block 1 */
CSL_edma3HwChannelSetupParam (hChannel, 1);

/* Setup the trigger word for the QDMA Channel. */
CSL_edma3HwChannelSetupTriggerWord(hChannel, 7);

/* Block Parameter Entry Handle */
hParamBlock = CSL_edma3GetParamHandle(hChannel, 1, &status);
if (hParamBlock == NULL)
{
printf ("Error: EDMA get handle for param entry 1 failed\n");
return PCIE_DMA_NOT_INITIALIZED;
}

/* Setup param entry */
myParamSetup.option = CSL_EDMA3_OPT_MAKE(CSL_EDMA3_ITCCH_DIS, \
CSL_EDMA3_TCCH_DIS, \
CSL_EDMA3_ITCINT_DIS, \
CSL_EDMA3_TCINT_EN,\
0,
CSL_EDMA3_TCC_NORMAL,\
CSL_EDMA3_FIFOWIDTH_NONE, \
CSL_EDMA3_STATIC_EN, \
CSL_EDMA3_SYNC_AB, \
CSL_EDMA3_ADDRMODE_INCR, \
CSL_EDMA3_ADDRMODE_INCR);
myParamSetup.srcAddr = (Uint32)srcBuff1;
myParamSetup.aCntbCnt = CSL_EDMA3_CNT_MAKE(256, 1);
myParamSetup.dstAddr = (Uint32)dstBuff1;
myParamSetup.srcDstBidx = CSL_EDMA3_BIDX_MAKE(1, 1);
myParamSetup.linkBcntrld= CSL_EDMA3_LINKBCNTRLD_MAKE(CSL_EDMA3_LINK_NULL, 0);
myParamSetup.srcDstCidx = CSL_EDMA3_CIDX_MAKE(0,0);
myParamSetup.cCnt = 1;

/* Setup Block to operate with this PARAM Entry. */
if (CSL_edma3ParamSetup(hParamBlock, &myParamSetup) != CSL_SOK)
{
printf ("Error: EDMA param setup failed\n");
return PCIE_DMA_TRANSFER_FAIL;
}

/* Enable Channel */
if (CSL_edma3HwChannelControl(hChannel,CSL_EDMA3_CMD_CHANNEL_ENABLE, NULL) != CSL_SOK)
{
printf ("Error: EDMA channel enable command failed\n");
return PCIE_DMA_NOT_INITIALIZED;
}

/* Trigger the word by writing to the trigger word... */
if (CSL_edma3ParamWriteWord(hParamBlock, 7, 1) != CSL_SOK)
{
printf ("Error: EDMA param write word failed\n");
return PCIE_DMA_TRANSFER_FAIL;
}

/* Poll IPR bit */
regionIntr.region = regionNum;
do {
CSL_edma3GetHwStatus(hModule,CSL_EDMA3_QUERY_INTRPEND,&regionIntr);
} while (!(regionIntr.intr & 0x1));

/* Clear pending interrupt */
if (CSL_edma3HwControl(hModule,CSL_EDMA3_CMD_INTRPEND_CLEAR, &regionIntr) != CSL_SOK)
{
printf ("Error: EDMA clear interrupt pend command failed\n");
return PCIE_DMA_TRANSFER_FAIL;
}

printf ("Data Transmission via DMA Module Successful\n");

/* Disable the channel */
CSL_edma3HwChannelControl(hChannel,CSL_EDMA3_CMD_CHANNEL_DISABLE, NULL);

/* Close channel */
if (CSL_edma3ChannelClose(hChannel) != CSL_SOK)
{
printf("Error: EDMA channel close failed\n");
return PCIE_DMA_NOT_CLOSED;
}

/* Close EDMA module */
if (CSL_edma3Close(hModule) != CSL_SOK)
{
printf("Error: EDMA module close failed\n");
return PCIE_DMA_NOT_CLOSED;
}
printf ("DMA Module Closed Successfully\n");
return SUCCESS;
}

In main, I call the function then read out part of the buffers:

DMA_All_in_One_Transfer();

/*Print out a section of the buffers */
Uint32 i;

for (i = 0; i < 16; i++)
{
System_printf("srcBuff1[%d]: %d\n", i, srcBuff1[i]);
System_printf("dstBuff1[%d]: %d\n", i, dstBuff1[i]);
}

Any suggestion of changes I can make to my code would be helpful.

Thx
Charles 

  • It would appear that you're transferring srcBuff1 -> dstBuff1 with the QDMA, but you're updating the data in RCdataStore.content and looking at the data in RCdataStore.content and CopydataStore.content and I'm not seeing anything that's defining that CopydataStore.content is dstBuff1.

    Best Regards,

    Chad

  • Apologies, it appears I must have captured an older project version than I thought.
    I have edited my original post to reflect the changes required. 
    The current version does have these fields corrected to replace RCdataStore with srcBuff1 and CopydataStore with dstBuff1.
    In any case, both pairs of buffers are located in DDR so each pair is identical  (although obviously they must be used globally as you point out).

    However, the same problem still persists. Is there any addition background setup that I may be overlooking?

    Thx

    Charles

  • Ok, that probably explains it.  It's a cache coherency issue.  EDMA (used by QDMA) is going to directly access the DDR memory in this case.  So the transfers are there.  However, you most likely already have this data cached in L1D/L2 memory spaces. 

    You'll want to invalidate the cache for that space before the CPU tries to access it as cache coherency is not maintained between EDMA writes to external memory spaces and L1/L2 spaces.  That way it can be re-cached.

    You should also be able to observe it using a memory window in CCS.  You have the option to show you what's at the physical memory address as well as what's in cache.

    Best Regards,

    Chad

  • Another thing you can do real quickly is move the buffers to Local L2 Memory space and try it again.

    Best Regards,
    Chad

  • Hi Chad,

    Thanks for the advice, I have created a new data section for two buffers in L2SRAM and I am using the following lines to invalidate the cache before printing the buffer's contents:

    in Global setup:

    #pragma DATA_SECTION(srcBuffL2SRAM, ".srcBuffL2SRAMSec")
    #pragma DATA_ALIGN(srcBuffL2SRAM, 256)
    #pragma DATA_SECTION(dstBuffL2SRAM, ".dstBuffL2SRAMSec")
    #pragma DATA_ALIGN(dstBuffL2SRAM, 256)

    struct srcBuffL2SRAM_s {
    uint8_t buffer[512];
    } srcBuffL2SRAM;
    struct dstBuffL2SRAM_s {
    uint8_t buffer[512];
    } dstBuffL2SRAM;

    in main (after running the QDMA transfer):

    unsigned int key;

    /* Disable Interrupts */

    key = _disable_interrupts();

    CSL_XMC_invalidatePrefetchBuffer();

    CACHE_invL1d ((void *)srcBuffL2SRAM.buffer, 512, CACHE_WAIT);
    CACHE_invL2 ((void *)srcBuffL2SRAM.buffer, 512, CACHE_WAIT);
    CACHE_invL1d ((void *)dstBuffL2SRAM.buffer, 512, CACHE_WAIT);
    CACHE_invL2 ((void *)dstBuffL2SRAM.buffer, 512, CACHE_WAIT);
    _mfence();

    /* Re-enable Interrupts. */
    _restore_interrupts(key);

    When I print the buffers, they are as they were before, with srcBuffL2SRAM initialised and dstBuffL2SRAM still all 0.

    I am also using the memory browser to directly view the memory spaces for the buffers. I can see the same results as with the print statements and toggling the cache overlay does not change any of the values.

    Am I doing the invalidation wrong? I took it from the EDMA_test example provided in the pdk_C6678 csl package.

    The code for the data sections and the structs came from looking at the code used in the PCI example project which used the same system for a dstBuf.

    Could the EDMA module be triggering the interrupt to complete the transfer incorrectly when in fact no transfer took place?

    Thanks
    Charles 

  • Charles,

    Can you .zip up the project and post it here and I'll have someone from my team take a look at it.

    Best Regards,

    Chad

  • Chad,

    I actually had a colleague look over my code since I last posted who advised doing a cache writeback after initialising the buffers.

    This appears to have solved the problem. I was about to post on here to tell you before you replied.

    Thank you for your advice nonetheless, we were in the right area.

    I have verified your earlier post as and answer as it was effectively the solution, I just had to get the right code in the right places :).

    Charles

  • On a different note,

    Will the code above use EDMACC0 by default because the instNum parameter is set to 0?

    Will it also use TC0 by default as I have not explicitly set the channel to a setup queue? (by using CSL_edma3HwChannelSetupQue())

    From the C6678 datasheet on page 151 I asssume this will give me a DBS of 128 bytes, is this correct?

    http://www.ti.com/lit/ds/symlink/tms320c6678.pdf

    Thanks

    Charles

  • Yes, the Instance Number is for the CC#, I'm not 100% positive that it would default to TC0, but I'd assume so.  That said, the only alternative is TC1, and both are are identicale w/ DBS of 128B.

    Best Regards,

    Chad