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 chain-linked issue

Part Number: PROCESSOR-SDK-AM437X

Tool/software: TI-RTOS

Hi,

What I see when I debug my code is that sometimes (seems to be random) EDMA transfer is doubled.

What I do is "EDMA multi-dimensional shift register" triggered with CPU. I use "self-chain" for partial transfer (for huge data size is advice to split transfer into several smaller chunks) and "self-prepare / link mode" to reload PaRAM without CPU intervention.

Can you please check my setup:

	ch_chain_link1 = EDMA3_DRV_LINK_CHANNEL;
	ch_chain_link2 = EDMA3_DRV_LINK_CHANNEL;

	for(ch_chain = 31; ch_chain < 64; ch_chain++){
		tcc_chain = ch_chain;
	    edmaResult = EDMA3_DRV_requestChannel(hEdma, &ch_chain, &tcc_chain,(EDMA3_RM_EventQueue)2,NULL, NULL);
	    if(edmaResult == EDMA3_DRV_SOK){
	    	break;
	    }
	}
    if(edmaResult != EDMA3_DRV_SOK){
    	ERROR_H;
    }

    edmaResult = EDMA3_DRV_requestChannel(hEdma, &ch_chain_link1, NULL,(EDMA3_RM_EventQueue)2,NULL, NULL);
    if(edmaResult != EDMA3_DRV_SOK){
    	ERROR_H;
    }
    edmaResult = EDMA3_DRV_requestChannel(hEdma, &ch_chain_link2, NULL,(EDMA3_RM_EventQueue)2,NULL, NULL);
    if(edmaResult != EDMA3_DRV_SOK){
    	ERROR_H;
    }

	/* Transfer complete chaining enable. */
	chain.tcchEn = EDMA3_DRV_TCCHEN_DIS;
	/* Intermediate transfer complete chaining enable. */
	chain.itcchEn = EDMA3_DRV_ITCCHEN_EN;
	/* Transfer complete interrupt is enabled. */
	chain.tcintEn = EDMA3_DRV_TCINTEN_EN;
	/* Intermediate transfer complete interrupt is disabled. */
	chain.itcintEn = EDMA3_DRV_ITCINTEN_DIS;

	memset(&opt, 0, sizeof(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 |= ((tcc_chain << (0x0000000Cu)) & (0x0003F000u));
    /* Final transfer completion interrupt */
    opt.reg_bit.itcinten = 0;
    opt.reg_bit.tcinten= 1;
    opt.reg_bit.syncdim = 1;

    PaRAM.opt = opt.reg;
    PaRAM.srcAddr = (uint32_t)&context->FIRdata.FIR_shiftReg[0][FIR_LEN-2];
    PaRAM.destAddr = (uint32_t)&context->FIRdata.FIR_shiftReg[0][FIR_LEN-1];
    PaRAM.aCnt = sizeof(context->FIRdata.FIR_shiftReg[0][0]);
    PaRAM.bCnt = FIR_LEN-1;
    PaRAM.cCnt = NUMBER_OF_FIR_CH;
    PaRAM.bCntReload = FIR_LEN-1;
    PaRAM.srcBIdx = (int16_t)( (int32_t)&context->FIRdata.FIR_shiftReg[0][FIR_LEN-3] - (int32_t)&context->FIRdata.FIR_shiftReg[0][FIR_LEN-2]);
    PaRAM.srcCIdx = (int16_t)((int32_t)&context->FIRdata.FIR_shiftReg[1][0] - (int32_t)&context->FIRdata.FIR_shiftReg[0][0]);
    PaRAM.destBIdx = (int16_t)((int32_t)&context->FIRdata.FIR_shiftReg[0][FIR_LEN-2] - (int32_t)&context->FIRdata.FIR_shiftReg[0][FIR_LEN-1]);
    PaRAM.destCIdx = (int16_t)((int32_t)&context->FIRdata.FIR_shiftReg[1][0] - (int32_t)&context->FIRdata.FIR_shiftReg[0][0]);
    PaRAM.linkAddr = 0xFFFF;

    edmaResult |= EDMA3_DRV_setPaRAM (context->hEdma, ch_chain, &PaRAM);
    edmaResult |= EDMA3_DRV_chainChannel(context->hEdma, ch_chain, ch_chain, (EDMA3_DRV_ChainOptions *)&chain);

    edmaResult |= EDMA3_DRV_registerTccCb(context->hEdma,
										  ch_chain,
										  FIRshift_DmaIRQ, context);
    edmaResult |= EDMA3_DRV_getPaRAM(context->hEdma, ch_chain, &PaRAM);
    edmaResult |= EDMA3_DRV_setPaRAM (context->hEdma, ch_chain_link1, &PaRAM);
    edmaResult |= EDMA3_DRV_setPaRAM (context->hEdma, ch_chain_link2, &PaRAM);
    edmaResult |= EDMA3_DRV_linkChannel (context->hEdma, ch_chain, ch_chain_link1);
    edmaResult |= EDMA3_DRV_linkChannel (context->hEdma, ch_chain_link1, ch_chain_link2);
    edmaResult |= EDMA3_DRV_linkChannel (context->hEdma, ch_chain_link2, ch_chain_link1);
    if(edmaResult != EDMA3_DRV_SOK){
    	ERROR_H;
    }

This is how I triger:

	if(EDMA3_DRV_SOK != EDMA3_DRV_enableTransfer(context->hEdma,context->CH, EDMA3_DRV_TRIG_MODE_MANUAL)){
		ERROR_H;
	}

This is isr callback function:

static void FIRshift_DmaIRQ(uint32_t tcc,EDMA3_RM_TccStatus status,void *appData){
	FIR_shiftContext *context = (FIR_shiftContext *)appData;
	int x;
	if(EDMA3_RM_XFER_COMPLETE == status){
		Custom_cache_invalidate((uint32_t)context->FIRdata.FIR_shiftReg, sizeof(context->FIRdata.FIR_shiftReg));
	//	for(x = 0; x < NUMBER_OF_FIR_CH; x++){
	//		context->FIRdata.FIR_shiftReg[x][0] = context->FIRdata.inputBuff.inputFIR[x];
	//		Custom_cache_writeBack((uint32_t)&context->FIRdata.FIR_shiftReg[x][0], sizeof(context->FIRdata.FIR_shiftReg[x][0]));
	//	}
		context->FIRdata.FIR_shiftReg[0][0].int_shiftReg = context->FIRdata.inputBuff.filds.index;
		Custom_cache_writeBack((uint32_t)&context->FIRdata.FIR_shiftReg[0][0], sizeof(context->FIRdata.FIR_shiftReg[0][0].int_shiftReg));
		context->FIRdata.FIR_shiftReg[1][0].int_shiftReg = context->FIRdata.inputBuff.filds.UTC;
		Custom_cache_writeBack((uint32_t)&context->FIRdata.FIR_shiftReg[1][0], sizeof(context->FIRdata.FIR_shiftReg[0][0].int_shiftReg));
		context->FIRdata.FIR_shiftReg[2][0].float_shiftReg = context->FIRdata.inputBuff.filds.freq;
		Custom_cache_writeBack((uint32_t)&context->FIRdata.FIR_shiftReg[2][0], sizeof(context->FIRdata.FIR_shiftReg[0][0].int_shiftReg));
		for(x = 0; x < FIR_PHASOR_LEN; x++){
			context->FIRdata.FIR_shiftReg[3+x*2][0].float_shiftReg = context->FIRdata.inputBuff.filds.phasor[x].Re_;//re
			Custom_cache_writeBack((uint32_t)&context->FIRdata.FIR_shiftReg[x*2][0], sizeof(context->FIRdata.FIR_shiftReg[0][0].float_shiftReg));
			context->FIRdata.FIR_shiftReg[4+x*2][0].float_shiftReg = context->FIRdata.inputBuff.filds.phasor[x].Im_;//im
			Custom_cache_writeBack((uint32_t)&context->FIRdata.FIR_shiftReg[1+x*2][0], sizeof(context->FIRdata.FIR_shiftReg[0][0].float_shiftReg));
		}
		//postEvent
		if(context->DownSamplingCounters.lastREGISTER != context->FIRdata.inputBuff.filds.index){
			context->DownSamplingCounters.lastREGISTER = context->FIRdata.inputBuff.filds.index;
			Event_post(context->FIRactionEvent, EVENT_FIR_SHIFT_END);
		}
		else{
			__asm__("BKPT");
		}
	}
	else{
		__asm__("BKPT");
	}

}

After some random time, I get duplicated index.. also I can see duplicated value in output data....

Is this issue/behavioural known? Or more likely I do something stupid (but can't see for a week of investigating)..


Best regards , Mare

  • Hi,

    For EDMA chaining,

    The channel chaining capability for the EDMA3 allows the completion of an EDMA3
    channel transfer to trigger another EDMA3 channel transfer. The purpose is to allow
    you the ability to chain several events through one event occurrence.
    Chaining is different from linking (Section 2.3.7). The EDMA3 link feature reloads the
    current channel parameter set with the linked parameter set. The EDMA3 chaining
    feature does not modify or update any channel parameter set; it provides a
    synchronization event to the chained channel (see Section 2.4.1.3 for chain-triggered
    transfer requests).
    Chaining is achieved at either final transfer completion or intermediate transfer
    completion, or both, of the current channel. Consider a channel m (DMA/QDMA)
    required to chain to channel n. Channel number n needs to be programmed into the
    TCC bit of channel m channel options parameter (OPT) set.

    There is a chain example from EDMA LLD: edma3_lld_2_12_05_XX\examples\edma3_driver\src\dma_chain_test.c you can refer to.

    Regards, Eric
  • Hi Eric,

    I didn't expect a copy/paste text from the reference manual.

    Now I experimenting with code, and I disable linking of channel. Now I get from time to time "EDMA3_RM_E_CC_DMA_EVT_MISS". It seems that some time start transfer get doubled...

    I trigger some channels with A9 and some channels with pru (direct writing on registers).... could be this issue? 

  • Hi,

    "I trigger some channels with A9 and some channels with pru ", =====> If you chain several channels together, you only need to trigger the first channel.

    Regards, Eric