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.

RTOS/PROCESSOR-SDK-AM437X: EDMA3 interrupt mux

Part Number: PROCESSOR-SDK-AM437X


Tool/software: TI-RTOS

Hi, 

I'm wondering about the options for setting up interrupts.

In my application setup I'm using ARM main cpu and ICSS - PRU collaboration. PRU collect data and send it to DDR memory where ARM process this data.
Idea is that PRU work as "custom" periphery and EDMA write from PRU 1-D buffer (from internal PRU memory) to circular 2-D buffer (in DDR). 

Now if I present current operation flow.

ARM use library :

#include <ti/sdo/edma3/drv/sample/bios6_edma3_drv_sample.h>
#include <ti/sdo/edma3/drv/src/edma3.h>

I request "main" chanell and "link" chanels.

    EDMA_ch_context.G_tcc = EDMA3_DRV_TCC_ANY;
    EDMA_ch_context.G_chId = EDMA3_DRV_DMA_CHANNEL_ANY;
    edmaResult = EDMA3_DRV_requestChannel(hEdma, &EDMA_ch_context.G_chId, &EDMA_ch_context.G_tcc,
                                              (EDMA3_RM_EventQueue)1,
                                              NULL, NULL);
    for(x = 0; x < numOfLinkChannels; x++){
    	EDMA_ch_context.tcc[x] = EDMA3_DRV_TCC_ANY;
    	EDMA_ch_context.chId[x] = EDMA3_DRV_LINK_CHANNEL;
        edmaResult = EDMA3_DRV_requestChannel(hEdma, &EDMA_ch_context.chId[x], &EDMA_ch_context.tcc[x],
                                                  (EDMA3_RM_EventQueue)1,
                                                  NULL, NULL);
    }

In this case I don't use callback (but I would like to in future).

OPT field is constant for all channels:

    //*************OPT*********************
    opt.reg = 0;
    /* Src & Dest are in INCR modes */
    opt.reg_bit.sam = 0;
    opt.reg_bit.dam = 0;
    /* Program the TCC */
    opt.reg |= ((EDMA_ch_context.G_tcc << (0x0000000Cu)) & (0x0003F000u));
    /* Enable Intermediate & Final transfer completion interrupt */
    opt.reg_bit.itcinten = 1;
    opt.reg_bit.tcinten= 1;
    opt.reg_bit.syncdim = 1;//AB-sync

Now I define "testLinkingStruct"-struct which is then written to PRU (so PRU can found flags in EDMA registers).

    testLinkingStruct.dmaReg.ch = EDMA_ch_context.G_chId;
    testLinkingStruct.dmaReg.tcc = EDMA_ch_context.G_tcc;
    testLinkingStruct.dmaReg.tccMask = (uint32_t)(1UL << EDMA_ch_context.G_tcc);
    testLinkingStruct.dmaReg.triggerType = (uint32_t*)&edma3DrvChBoundRes[edma3Id][EDMA_ch_context.G_chId].trigMode;

	if(EDMA_ch_context.G_chId < 32){
	    testLinkingStruct.dmaReg.ESRx = (uint32_t*)&drvInst->shadowRegs->ESR;
	    testLinkingStruct.dmaReg.ICRx = (uint32_t*)&drvInst->shadowRegs->ICR;
	    testLinkingStruct.dmaReg.IPRx = (uint32_t*)&drvInst->shadowRegs->IPR;
		testLinkingStruct.dmaReg.channelMask = (uint32_t)(1UL << EDMA_ch_context.G_chId);
	}
	else{
	    testLinkingStruct.dmaReg.ESRx = (uint32_t*)&drvInst->shadowRegs->ESRH;
	    testLinkingStruct.dmaReg.ICRx = (uint32_t*)&drvInst->shadowRegs->ICRH;
	    testLinkingStruct.dmaReg.IPRx = (uint32_t*)&drvInst->shadowRegs->IPRH;
		testLinkingStruct.dmaReg.channelMask = (uint32_t)(1UL << (EDMA_ch_context.G_chId-32));
	}

Then when PRU has data ready to transmit it can trigger transfer as:

    	*(testLinkingStruct.dmaReg.ESRx) |= testLinkingStruct.dmaReg.channelMask;//start transfer
    	*(testLinkingStruct.dmaReg.triggerType) = 0;

Which is equivalent to  

EDMA3_DRV_enableTransfer

from my uderstanding.....

Then PRU collect new data, but before it transfer new chunk of data it need to check if previous transfer was complete - that why Intermediate interrupt is needed

while(! (*(testLinkingStruct.dmaReg.IPRx) & testLinkingStruct.dmaReg.tccMask));

Which is equalent to

EDMA3_DRV_checkAndClearTcc

Now when total number of cCnt is complete, PRU send msg to ARM that total transfer of data chunk is complete. And this bother me...


I wish to make callback function on ARM when tcinten happen, but also need itcinten for PRU previous transfer complete check.
Is any option for this kind functionality? Can I pull any other register (insted of IPR) with PRU to check previous transfer complete, so I can use callback on ARM side on tcinten?

 

Any suggestion?

  • The RTOS team have been notified. They will respond here.


  • Marko Kastelic said:

    Then PRU collect new data, but before it transfer new chunk of data it need to check if previous transfer was complete - that why Intermediate interrupt is needed

    while(! (*(testLinkingStruct.dmaReg.IPRx) & testLinkingStruct.dmaReg.tccMask));

    Which is equalent to

    EDMA3_DRV_checkAndClearTcc



    Here I miss add line for complete description:

    *(testLinkingStruct.dmaReg.ICRx) |= testLinkingStruct.dmaReg.tccMask; //clear


  • Hi,

    I saw you used multiple channels for EDMA transfer, you mentioned that they are linked. Do you mean they are chained together?
    - Linking is the feature of loading a new PaRam to a channel upon completion of the channel current transfer. Upon completion of a transfer, the transfer parameters are reloaded with new PaRam parameter set addressed by the 16-bit link address field of the current parameter set.
    - The channel chaining capability for the EDMA3 allows the completion of an EDMA3 channel transfer to trigger another EDMA3 channel transfer. That is, after one EDMA channel completes, the second channel starts without CPU intervention.

    Please check EDMA user guide www.ti.com/.../sprugs5b.pdf section 2.8 and 2.9.

    Regards, Eric
  • Is my code strange? I think I use (I hope soo....) Linking.

    As you can see I request linking channel. Then I link channel to channel (fro drv function prospective) so they work as circuit buffer (they have dif. DEST buffer locations). Chaining isn't option becouse PRU manual triger ab-sync transfer on each new sample.

    Should I post the complite code?

    My Q is actualy how to handle inter-tranfer with pru and complete transfer with ARM without pulling on ARM side.

  • my code for channels init:

        EDMA_ch_context.G_tcc = EDMA3_DRV_TCC_ANY;
        EDMA_ch_context.G_chId = EDMA3_DRV_DMA_CHANNEL_ANY;
        edmaResult = EDMA3_DRV_requestChannel(hEdma, &EDMA_ch_context.G_chId, &EDMA_ch_context.G_tcc,
                                                  (EDMA3_RM_EventQueue)1,
                                                  NULL, NULL);
        for(x = 0; x < numOfChunks; x++){
        	EDMA_ch_context.tcc[x] = EDMA3_DRV_TCC_ANY;
        	EDMA_ch_context.chId[x] = EDMA3_DRV_LINK_CHANNEL;
            edmaResult = EDMA3_DRV_requestChannel(hEdma, &EDMA_ch_context.chId[x], &EDMA_ch_context.tcc[x],
                                                      (EDMA3_RM_EventQueue)1,
                                                      NULL, NULL);
        }
        //*************OPT*********************
        opt.reg = 0;
        /* Src & Dest are in INCR modes */
        opt.reg_bit.sam = 0;
        opt.reg_bit.dam = 0;
        /* Program the TCC */
        opt.reg |= ((EDMA_ch_context.G_tcc << (0x0000000Cu)) & (0x0003F000u));
        /* Enable Intermediate & Final transfer completion interrupt */
        opt.reg_bit.itcinten = 1;
        opt.reg_bit.tcinten= 1;
        opt.reg_bit.syncdim = 1;//AB-sync
    
        skipSpace = (int)((uint64_t)&_dstTEST_LINK[1][0] - (uint64_t)&_dstTEST_LINK[0][0]);
        skipSpace = bufferLen*sizeof(uint32_t);
    
        PARAMparamSet.opt = opt.reg;
        PARAMparamSet.srcAddr= (uint32_t) testSrcBuff;
    
        PARAMparamSet.aCnt = sizeof(uint32_t);
        PARAMparamSet.bCnt = ADC_SAMPLE_SIZE_INT;
        PARAMparamSet.bCnt = numberOfADC+1;
        PARAMparamSet.cCnt = CHUNK_SAMPLE_LINK_TEST;
        PARAMparamSet.cCnt = lenDataChunk;
        PARAMparamSet.bCntReload = PARAMparamSet.bCnt*PARAMparamSet.aCnt;//ADC_SAMPLE_SIZE_INT * dataSizeB;
        PARAMparamSet.srcBIdx = sizeof(uint32_t);
        PARAMparamSet.destBIdx = skipSpace;
        PARAMparamSet.srcCIdx = 0;
        PARAMparamSet.linkAddr = 0xFFFF;
        PARAMparamSet.destCIdx =  -((int32_t)&_dstTEST_LINK[0][0] - (int32_t)&_dstTEST_LINK[0][1]);
        PARAMparamSet.destCIdx =  (int)sizeof(uint32_t);
    
        PARAMparamSet.destAddr = (uint32_t) &_dstTEST_LINK[0][0];
        PARAMparamSet.destAddr = (uint32_t) destAddr;
        edmaResult = EDMA3_DRV_setPaRAM (hEdma, EDMA_ch_context.G_chId, &PARAMparamSet);
    
        for(x = 0; x < numOfChunks; x++){
            PARAMparamSet.destAddr = (uint32_t) &_dstTEST_LINK[0][CHUNK_SAMPLE_LINK_TEST*x];
            PARAMparamSet.destAddr = (uint32_t) (destAddr+(lenDataChunk*x));
            edmaResult = EDMA3_DRV_setPaRAM (hEdma, EDMA_ch_context.chId[x], &PARAMparamSet);
        }
    
    
        edmaResult = EDMA3_DRV_linkChannel (hEdma, EDMA_ch_context.G_chId, EDMA_ch_context.chId[1]);
        for(x = 0; x < numOfChunks-1; x++){
        	edmaResult = EDMA3_DRV_linkChannel (hEdma, EDMA_ch_context.chId[x], EDMA_ch_context.chId[x+1]);
        }
        edmaResult = EDMA3_DRV_linkChannel (hEdma, EDMA_ch_context.chId[numOfChunks-1], EDMA_ch_context.chId[0]);
    
        drvInst = (EDMA3_DRV_Instance *)hEdma;
        edma3Id = ((EDMA3_DRV_Object *)drvInst->pDrvObjectHandle)->phyCtrllerInstId;
    
        testLinkingStruct.dmaReg.ch = EDMA_ch_context.G_chId;
        testLinkingStruct.dmaReg.tcc = EDMA_ch_context.G_tcc;
        testLinkingStruct.dmaReg.tccMask = (uint32_t)(1UL << EDMA_ch_context.G_tcc);
        testLinkingStruct.dmaReg.triggerType = (uint32_t*)&edma3DrvChBoundRes[edma3Id][EDMA_ch_context.G_chId].trigMode;
    
    	if(EDMA_ch_context.G_chId < 32){
    	    testLinkingStruct.dmaReg.ESRx = (uint32_t*)&drvInst->shadowRegs->ESR;
    	    testLinkingStruct.dmaReg.ICRx = (uint32_t*)&drvInst->shadowRegs->ICR;
    	    testLinkingStruct.dmaReg.IPRx = (uint32_t*)&drvInst->shadowRegs->IPR;
    	    testLinkingStruct.dmaReg.channelMask = (uint32_t)(1UL << EDMA_ch_context.G_chId);
    	}
    	else{
    	    testLinkingStruct.dmaReg.ESRx = (uint32_t*)&drvInst->shadowRegs->ESRH;
    	    testLinkingStruct.dmaReg.ICRx = (uint32_t*)&drvInst->shadowRegs->ICRH;
    	    testLinkingStruct.dmaReg.IPRx = (uint32_t*)&drvInst->shadowRegs->IPRH;
    	    testLinkingStruct.dmaReg.channelMask = (uint32_t)(1UL << (EDMA_ch_context.G_chId-32));
    	}

    G_chId = "global channel"

    chId[x] = are "link channels"

    Did I misunderstood how proper setting should be?

    Any way, I wonder if I can handle Intermediate with one processor and Final transfer with other processor (maped with interrupt)

  • Hi,

    Thanks for the explanation! For the EDMA transfer completions(either intermediate or final), you have two ways to know it: polling the IPR bit or use an ISR routine. If you want to use one CPU for intermediate completion and another CPU for final completion, I don't think it will work. No matter you use poll or ISR, whenever a transfer completed, the poll become true or ISR is entered.

    Regards, Eric
  • Hi,

    Thank you for answer! So I start to thinking for solution on the other way. Pleas try to answer widely with details to may question (I'm interested in channel combining and self triggering)

    1.)If I use two channels - chained together: I know that I can use chain for example: Start Ch2 when Ch1 conmplete. Can I setup some how Ch1 that set IPR bit on intermediate and complete transfer and also on complete transfer start(chain) Ch2? If Ch2 also has complete transfer enabled I can satisfied my case. So I can use Ch2 for "dummy" transfer and triger ISR on ARM. I see that TCC param in OPT in Ch1 PaRAM must be set to Ch2. So I lose poll IPR for Ch1? Is there any option?

    2.)Is maybe option with combining with QDMA? I don't actually understand what "trigger word's" are.

    3.)I use this EDMA transfers for precise clock aligned sample data transfer. I have event's on GPI (PRU) which can be used for check if miss sample happen. For chacking that also need information how many data was transferred. How this can be chaked? Look in PaRAM for acnt, bcnt,ccnt? Is posssible to trigger - make signal/event/check bit when PaRAM is reloaded?  

    4.) is possible to chain (start) parallel more than one channel. So for example: Ch(x) complete transfer -> chain > Ch(y) & Ch(z). ?

    Best Regards,
    Mare

  • Dear support.

    Anything new? 

    Question5.) 

    For purpose of complex and fast sorting where 4 or more chained channels are needed (1. channel copy mem-to-mem on one order of sorting, 2.channel copy mem-to-mem other data and with other order of sorting ... and so on..). Let say that all combinations of sorting I prepare in state of init. - setup PaRAMs,  program it in EDMA space and then when I decide on my app event, link channels with PaRAM and start transfer.

    As far I see EDMA3_DRV_setPaRAM Copy EDMA3_DRV_PaRAMRegs to EDMA (which is slow operation) and then channel associate with PaRAM ID.
    so if I repeat myself:
    Is possible to manual "reserve" some paRAMId (globalRegs->PARAMENTRY[paRAMId])... program it and then manually set  edma3DrvChBoundRes[edma3Id][lCh].paRAMId to some reserved PaRAM in application (depend on derision which PaRAM used) and run translation. This could be called - "decision linking".