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.

EDMA3 LLD transfer not happening on C6636 K2H

Other Parts Discussed in Thread: TCI6636K2H

Hi,

I cannot get the DMA transfer to happen with the DSP 0 core neither with the EDMA3 LLD nor with CSL functions.

With the LLD I do the following:

Uint32 edma3InstanceId = 0;
Uint32 edma3RegionId = 4;

Error_Block eb;
Semaphore_Params semParams;
EDMA3_DRV_Result edma3Result;
EDMA3_DRV_Handle hEdma;

// these are linked from the EDMA3 LLD package samples:
extern EDMA3_DRV_InstanceInitConfig sampleInstInitConfig[][EDMA3_MAX_REGIONS];
extern EDMA3_RM_InstanceInitConfig defInstInitConfig[][EDMA3_MAX_REGIONS];
extern EDMA3_DRV_GblConfigParams sampleEdma3GblCfgParams[];



// Allocate memory for the test

    Uint8* dmaSrc = (Uint8 *)malloc(1024); // becomes 0x00823800
    Uint8* dmaDst = (Uint8 *)malloc(1024); // becomes 0x00823C08

// Configure Resource Manager, semaphore and create the driver instance

    EDMA3_DRV_GblConfigParams *globalConfig = &sampleEdma3GblCfgParams[edma3InstanceId];
    EDMA3_DRV_MiscParam miscParam;
    miscParam.isSlave = FALSE; // ARM+DSP = specify if master; single-CPU = use FALSE
    EDMA3_DRV_create(edma3InstanceId, globalConfig, (void *)&miscParam);

    EDMA3_DRV_InstanceInitConfig *instanceConfig = &sampleInstInitConfig[edma3InstanceId][edma3RegionId];
    EDMA3_DRV_InitConfig initCfg;
    initCfg.isMaster = TRUE; // Single-CPU processor, choose TRUE
    initCfg.regionId = edma3RegionId;
    initCfg.drvInstInitConfig = instanceConfig;
    initCfg.gblerrCb = NULL;
    initCfg.gblerrData = NULL;

    Semaphore_Params_init(&semParams);
    initCfg.drvSemHandle = Semaphore_create(1, &semParams, &eb);

// open driver

    hEdma = MY_EDMA3_DRV_open(edma3InstanceId, (void*)&initCfg, &edma3Result);

// request DMA channel
    Uint32 LCh = EDMA3_DRV_HW_CHANNEL_EVENT_32; // GPIO 0 event
    EDMA3_RM_EventQueue evtQueue = 0;
    Uint32 Tcc = EDMA3_DRV_TCC_ANY; // becomes to 32
    edma3Result = MY_EDMA3_DRV_requestChannel(hEdma, &LCh, &Tcc, evtQueue, (EDMA3_RM_TccCallback)&edma_isr,
        (void*)&g_isrArg);

    Uint32 paramPhyAddr = 0; // becomes 0x02706400
    edma3Result = EDMA3_DRV_getPaRAMPhyAddr(hEdma, LCh, &paramPhyAddr);

// setup the transfer or 256 bytes from dmaSrc ---> dmaDst
    EDMA3_DRV_PaRAMRegs paramSet;
    memset(&paramSet, 0, sizeof(EDMA3_DRV_PaRAMRegs));
    paramSet.srcAddr    = (uint32_t)(dmaSrc);
    paramSet.destAddr   = (uint32_t)(dmaDst);
    paramSet.srcBIdx    = 0;
    paramSet.destBIdx   = 0;
    paramSet.srcCIdx    = 0;
    paramSet.destCIdx   = 0;
    paramSet.aCnt       = 0x0100;
    paramSet.bCnt       = 1;
    paramSet.cCnt       = 1;
    paramSet.bCntReload = 0;
    paramSet.linkAddr   = 0xFFFF;
    paramSet.opt = 0x00100008 | (Tcc << 12);;
    edma3Result = EDMA3_DRV_setPaRAM(hEdma, LCh, &paramSet);

    memset((void*)dmaSrc, 0xff, 1024); // fill source test data with 0xff
    memset((void*)dmaDst, 0, 1024); // fill the destination test data with zeros

So far all the above has succeeded without any errors. I have checked the return values in each step although not included in the code above.

Now the contents of PaRAM at 0x02706400 is:

00120004    00823800
00010100    00823C08
00000000    0000FFFF
00000000    00000001

The event enable registers EER and EERH are both zero, also for the shadow region. I don't know why but forcing them to 1 makes no difference.

The interrupt enable register IERH = 1, IPRH = 0.

// init the transfer

    edma3Result = MY_EDMA3_DRV_enableTransfer(hEdma, LCh, EDMA3_DRV_TRIG_MODE_MANUAL);

The result is OK, the PaRAM changes to:
00000000    00000000
00000000    00000000
00000000    0000FFFF
00000000    00000000

as expected.

The interrupt pending register IPRH becomes 1. (Tcc = 32)

But the contents of dmaDst has not changed to 0xff as expected. The contents of dmaSrc is also not changed.

Have I forgotten something? I have heard about memory protection. Do I need to deal with it somehow?

The similar transfer succeeds with ARM core without problems but not with the DSP. What can be the difference between these 2 environments? The operating HW is the same after all.

The test data arrays seem be allocated from the L2 SRAM. Can this cause problems? When I tested it with ARM core I used DDR3 memory.

Best regards,

Ari

  • Please refer to the following keystone 1 EDMA example and modify it for keystone 2.
    C:\ti\pdk_C6678_1_1_2_6\packages\ti\csl\example\edma
  • Hi,

    after weeks of hitting head into wall I finally got it working by a "nasty trick", see below.

    The reason for not moving the data was because my test code used for some reason L1 cache memory. When trying the same in DDR3 there were no transfer problems any more. But then I encountered a problem with the completion interrupt.

    The example mentioned above helped a lot although I had already tried all of it several times before and I actually did not find exactly that example from net, but one similar enough.

    I found out that in order to enable EDMA3 completion interrupt for a certain channel a correct shadow region must be used. This worked fine for the requestChannel() function call which at first failed because not knowing this. But next the completion interrupt never happened.

    The nasty trick was to rewrite the function "registerEdma3Interrupts" (found it from "...\edma3_lld_02_11_13_17\packages\ti\sdo\edma3\drv\sample\src\platforms\sample_tci6636k2h_int_reg.c") like this:

    // edma3Id = 0 in my case

    /* edma3RegionId depends on the channel, see member "ownDmaChannels" for each region in the struct "sampleInstInitConfig[NUM_EDMA3_INSTANCES][EDMA3_MAX_REGIONS]" found in "sample_tci6638k2h_cfg.c". This file is in the same folder than "sample_tci6636k2h_int_reg.c". */

    void registerEdma3Interrupts (unsigned int edma3Id)
    {
        static UInt32 cookie = 0;
        Int eventId = 0;    /* GEM event id */
        unsigned int numTc = 0;

        /* Use CP_INTC0 for DSP core 0-3 and CP_INTC1 for DSP core 4-7 */
        unsigned int cpIntcNum = (dsp_num > 3)? 1: 0;

        /* Disabling the global interrupts */
        cookie = Hwi_disable();

        /* Transfer completion ISR */
        CpIntc_dispatchPlug(ccXferCompInt[edma3Id][edma3RegionId],
                            myEdma3ComplHandler,
                            edma3Id,
                            TRUE);
        CpIntc_mapSysIntToHostInt(cpIntcNum, ccXferCompInt[edma3Id][edma3RegionId], CIC_OUTPUT_TC);
        CpIntc_enableHostInt(cpIntcNum, CIC_OUTPUT_TC);
        eventId = INTC_TC_EVENT_ID; //getEventId(ccXferHostInt[edma3Id][edma3RegionId]);
        EventCombiner_dispatchPlug (eventId, CpIntc_dispatch, CIC_OUTPUT_TC, TRUE);
        EventCombiner_enableEvent(eventId);

        /* CC Error ISR */
        CpIntc_dispatchPlug(ccErrorInt[edma3Id], myEdma3EvtMissHandler,
                            edma3Id, TRUE);
        CpIntc_mapSysIntToHostInt(cpIntcNum, ccErrorInt[edma3Id], CIC_OUTPUT_ERR);
        /* TC Error ISR */
        while (numTc < numEdma3Tc[edma3Id]) {
            CpIntc_dispatchPlug(tcErrorInt[edma3Id][numTc],
                                (CpIntc_FuncPtr )(ptrEdma3TcIsrHandler[numTc]),
                                edma3Id, TRUE);
            CpIntc_mapSysIntToHostInt(cpIntcNum, tcErrorInt[edma3Id][numTc], CIC_OUTPUT_ERR);
            numTc++;
        }
        /* Enable the host interrupt which is common for both CC and TC error */
        CpIntc_enableHostInt(cpIntcNum, CIC_OUTPUT_ERR);
        eventId = INTC_ERR_EVENT_ID; // getEventId(edma3ErrHostInt[edma3Id][edma3RegionId]);

        EventCombiner_dispatchPlug (eventId, CpIntc_dispatch, CIC_OUTPUT_ERR, TRUE);
        EventCombiner_enableEvent(eventId);

        Hwi_enableInterrupt(hwiInterrupt);

        /* enable the 'global' switch */
        CpIntc_enableAllHostInts(cpIntcNum);

        /* Restore interrupts */
        Hwi_restore(cookie);
    }

    The basic change in the function above when compared to the original in "sample_tci6636k2h_int_reg.c" is to use edma3RegionId instead of the DSP core Id and force the CIC output and event ID be constants. I don't know if this is a good trick or not and why the sample code was written so that it could not work, but now it works for me.

    I also replaced the driver interrupt handlers by my own so I don't need to write the callback function (given in requestChannel()) any more.

    static void myEdma3ComplHandler (const EDMA3_RM_Obj *rmObj)
    {

        volatile EDMA3_CCRL_Regs *ptrEdmaccRegs = NULL;
        volatile EDMA3_CCRL_ShadowRegs *shadowRegs = NULL;
        volatile Uint32 isIPR;
        volatile Uint32* isICR;
        int r;
        int b;

    // do your own processing here
    //    g_interruptCounter2++;

    // finally clear the interrupt
        ptrEdmaccRegs =
                (volatile EDMA3_CCRL_Regs *)EDMA_CHANNEL_CONTROLLER0_BASE;
        shadowRegs = (volatile EDMA3_CCRL_ShadowRegs *)
                                    (&ptrEdmaccRegs->SHADOW[edma3RegionId]);

        for (r = 0; r < 2; r++) {
            isIPR = (0 == r) ? shadowRegs->IPR : shadowRegs->IPRH;
            isICR = (0 == r) ? &shadowRegs->ICR : &shadowRegs->ICRH;
            b = 1;
            while (isIPR) {
                if (isIPR & 1) {
                    // process TCC

                    // clear IPR bit
                    *isICR = b;
                }
                isIPR >>= 1;
                b <<= 1;
            }
        }
    }

    static void myEdma3EvtMissHandler (const EDMA3_RM_Obj *rmObj)
    {

    // implementation is very similar to the transfer completion interrupt handler above

    // finally for clearing the interrupt just read EMR/EMRH register and according to its contencts clear bits in the registers EMCR/EMCRH and shadow's SECR/SECRH.

    }

    As the CIC outputs and events I use the following constants instead of taking them from the arrays provided in "sample_tci6636k2h_int_reg.c".

    #define CIC_OUTPUT_TC    68    // host INT
    #define CIC_OUTPUT_ERR    73    // host INT
    #define INTC_TC_EVENT_ID    26    // CIC out 68 + 10 * DSP coreId --> one event to each DSP core
    #define INTC_ERR_EVENT_ID    31    // CIC out 73 + 10 * DSP coreId --> one event to each DSP core

    I hope this helps somebody battling desperately with the same problem.

    BRS, Ari

  • Hi,

    Glad, that your problem got fixed and as well, this could help other e2e community members facing the similar issue.

    Thanks once again.

    Regards,
    Sivaraj K