Hi
I am using the edma to send samples to the mcasp where a codec is connected. This is on the LCDK eval board. Previously I was doing it via mcasp interrupts and everything worked fine except for the inefficiency.
Now I am using the edma to do this using ping pong buffers. Each buffer is 2048 shorts. Three params are used for the ping-pong control. The main param is updated with either ping or pong alternately. An interrupt routine is used to signal a semaphore in a task that is waiting for the expiration of each buffer.. The cpu task upon being signaled will fill the buffer that is not being used by the edma. This follows the basic ping pong buffering idea using edma interrupts.
I hooked the audio output from the codec to an oscilloscope and noticed spikes in the waveform. The spikes happen exactly at the boundary where the switch over happens. The buffers are filled with a sine wave by the task and I expect to see a near perfect sine wave on the scope.
Next I filled the ping-pong buffers during initialization of the edma and allow the edma to free run without going into the edma interrupt routine. The spikes completely vanished.
It seems as if the spikes are introduced by the edma entering the edma isr and a 0 is sent out to the mcasp during this time of change over. This brings up several questions regarding the timing of events of the edma during an update of the param.
1 Does the Param copying from one of the holder params happen before entering the isr or during the isr or after returning from the isr?
2 Logically I would expect the param copying to happen before entering the isr after the last sample of the ping or pong buffer has been sent out to the mcasp.
This would allow enough time for the isr to be serviced and exited. before the expiration of the buffer being read out to the mcasp. Is this the case?
3 Does the edma wait for return from the isr to send out the next sample for an event request from the mcasp? This could cause an under run on the mcasp but I haven't seen evidence of this.
When the edma is free running without the transfer completion isr enabled everything works fine which points to that the param copying is happening in time before the next event. Entering the isr seems to throw a spanner in the works. I have double checked that the IPR is cleared properly of all outstanding interrupt events. However it is difficult to verify via the debug system. There is a chance that the IPR is not fully cleared and is being re-entered.
This is highly important issue for us as this is a critical piece of the system that has to work correctly and we cannot tolerate any spurious outputs on the audio channel and that the edma should behave properly and predictably.
Your help to sort this out is much appreciated. I have also attached the edma test code file.
Thank you and regards
Manjula
/* * edma_test.c * * Created on: May 13, 2014 * Author: Manjula Ellepola */ #include <xdc/std.h> //mandatory - have to include first, for BIOS types #include <ti/sysbios/BIOS.h> //mandatory - if you call APIs like BIOS_start() #include <xdc/cfg/global.h> //header file for statically defined objects/handles #include "hw_psc_C6748.h" #include "soc_C6748.h" //#include "interrupt.h" //#include "uartStdio.h" #include "lcdkC6748.h" #include "hw_types.h" #include "edma.h" #include "psc.h" #include "interrupt.h" #include "math.h" #define PI 3.1415926535897932384626433832795 #define CHTYPE_DMA /* MAX ACOUNT */ #define MAX_ACOUNT (512u) /* MAX BCOUNT */ #define MAX_BCOUNT (1u) /* MAX CCOUNT */ #define MAX_CCOUNT (1u) #define MAX_BUFFER_SIZE (MAX_ACOUNT * MAX_BCOUNT * MAX_CCOUNT) volatile short _rxBuff[MAX_BUFFER_SIZE]; volatile short _dstBuff[32]; volatile short tx_buf0[4096]; //volatile short tx_buf1[1024]; volatile short dma_sin_buf[64] = { 0, 0, 3121, 0, 6122, 0, 8889, 0, 11313, 0, 13303, 0, 14782, 0, 15692, 0, 16000, 0, 15692, 0, 14782, 0, 13303, 0, 11313, 0, 8889, 0, 6122, 0, 3121, 0,0, 0, -3122,0, -6123,0, -8890,0,-11314,0, -13304,0, -14783,0, -15693,0, -16000,0, -15693,0,-14783,0, -13304,0, -11314, 0, -8890,0, -6123,0, -3122, 0}; volatile short *rxBuff; volatile short *dstBuff; volatile short* dmaTxBuffPtr; EDMA3CCPaRAMEntry paramSet; unsigned int McASP_DMA_rx; unsigned int McASP_DMA_tx; /* DATA PARAMETERS PROVIDED BY APPLICATION */ #ifdef CHTYPE_DMA unsigned int chType = EDMA3_CHANNEL_TYPE_DMA; unsigned int chNum = 1; unsigned int tccNum = 0; unsigned int edmaTC = 0; unsigned int syncType = EDMA3_SYNC_A; unsigned int trigMode = EDMA3_TRIG_MODE_EVENT; //EDMA3_TRIG_MODE_MANUAL; unsigned int evtQ = 0;/* Event Queue used */ #else unsigned int chType = EDMA3_CHANNEL_TYPE_QDMA; unsigned int chNum = 0; unsigned int tccNum = 0; unsigned int edmaTC = 0; unsigned int syncType = EDMA3_SYNC_A; unsigned int trigMode = EDMA3_TRIG_MODE_QDMA; unsigned int paRAMId = 32u; unsigned int evtQ = 0;/* Event Queue used */ unsigned int opt = 0; #endif void init_edma_McAspTx(void) { volatile unsigned int index = 0; volatile unsigned int count = 0; volatile unsigned int isIPR; unsigned char data = 0u; unsigned int retVal = 0u; unsigned int Istestpassed = 0u; unsigned int numenabled = 0u; unsigned int acnt = MAX_ACOUNT; unsigned int bcnt = MAX_BCOUNT; unsigned int ccnt = MAX_CCOUNT; unsigned int irqRaised = 0; int i; float phi, phi2, dphi, sin_val, sin_val1, dphi2 = 0; phi = 0; phi2 =0; //dphi = 360.0 * 100.0/48000.0; dphi = 2*PI*6.7/512.0; //*128/2048; // dphi2 = 2*PI*23.0/512.0; /* Enabling the PSC for EDMA3CC_0.*/ PSCModuleControl(SOC_PSC_0_REGS, 0, 0, PSC_MDCTL_NEXT_ENABLE); /* Enabling the PSC for EDMA3TC_0.*/ PSCModuleControl(SOC_PSC_0_REGS, 1, 0, PSC_MDCTL_NEXT_ENABLE); EDMA3Init(SOC_EDMA30CC_0_REGS, evtQ); //srcBuff = (char *)_srcBuff; //dstBuff = (char *)_dstBuff; // rxBuff = (short *)_rxBuff; dmaTxBuffPtr = tx_buf0; //dma_sin_buf; for(i=0; i< 2048; i++) { sin_val = (short)( 8000.0*sin(phi)); sin_val1 = 0.0; //(short)( 8000.0*sin(phi2)); tx_buf0[i*2] = sin_val; tx_buf0[i*2+1] = sin_val1; // tx_buf1[i*2] = sin_val1; // tx_buf1[i*2+1] = sin_val; phi = phi + dphi; if (phi > 2*PI) phi -= 2*PI; phi2 = phi2 + dphi2; if (phi2 > 2*PI) phi2 -= 2*PI; } /* Request DMA channel and TCC */ retVal = EDMA3RequestChannel(SOC_EDMA30CC_0_REGS, chType, chNum, tccNum, evtQ); //McASP_DMA_rx = 0x01D002B8; //0x01D02000; 0x01D002B8; McASP_DMA_tx = 0x01D00234; if (TRUE == retVal) { /* Fill the PaRAM Set with transfer specific information */ // paramSet.srcAddr = dstBuff; //(volatile int)(rxBuff); //McASP_DMA_rx; //(unsigned int)(srcBuff); paramSet.srcAddr = (unsigned int) dmaTxBuffPtr; paramSet.destAddr = McASP_DMA_tx; paramSet.aCnt = 2u; paramSet.bCnt = 2048u; //64u; paramSet.cCnt = (unsigned short)1; /* Setting up the SRC/DES Index */ paramSet.srcBIdx = 2u; paramSet.destBIdx = 0; paramSet.srcCIdx = 1u; //2u; paramSet.destCIdx = 0; paramSet.linkAddr = (unsigned short)0x43C0u; // point to par-ram 30 paramSet.bCntReload = 2048u; //64u; paramSet.opt = 0u; /* Src & Dest are in INCR modes */ paramSet.opt &= 0xFFFFFFFCu; /* Program the TCC */ paramSet.opt |= ((tccNum << EDMA3CC_OPT_TCC_SHIFT) & EDMA3CC_OPT_TCC); /* Enable Intermediate & Final transfer completion interrupt */ // paramSet.opt |= (1 << EDMA3CC_OPT_ITCINTEN_SHIFT); paramSet.opt |= (1 << EDMA3CC_OPT_TCINTEN_SHIFT); // if (syncType == EDMA3_SYNC_A) // { paramSet.opt &= 0xFFFFFFFBu; //paramSet.opt = 0000|0000|0101|0000|0000|0000|0000 paramSet.opt = 0x00100000; /* Now, write the PaRAM Set. */ EDMA3SetPaRAM(SOC_EDMA30CC_0_REGS, chNum, ¶mSet); } paramSet.srcAddr = (unsigned int)(tx_buf0+2048); // (unsigned int) dmaTxBuffPtr; paramSet.linkAddr = (unsigned short)0x43E0u; EDMA3SetPaRAM(SOC_EDMA30CC_0_REGS, 30, ¶mSet); paramSet.srcAddr = (unsigned int)tx_buf0; // (unsigned int) dmaTxBuffPtr; paramSet.linkAddr = (unsigned short)0x43C0u; EDMA3SetPaRAM(SOC_EDMA30CC_0_REGS, 31, ¶mSet); // clear int enable reg in edma HWREG(SOC_EDMA30CC_0_REGS+EDMA3CC_IECR) = 0xFFFFFFFF; // clear IPR in edma // HWREG(SOC_EDMA30CC_0_REGS+EDMA3CC_ICR) = 0xFFFFFFFF; HWREG(0x01C01070) = 0xFFFFFFFF; // EDMA3ClrIntr(SOC_EDMA30CC_0_REGS, chNum); // EDMA3EnableEvtIntr(SOC_EDMA30CC_0_REGS, 0); // enable edma evt-1 interrupt which is mapped to McASP tx retVal = EDMA3EnableTransfer(SOC_EDMA30CC_0_REGS, chNum, EDMA3_TRIG_MODE_EVENT); } void init_edma_McAspRx(void) { volatile unsigned int index = 0; volatile unsigned int count = 0; volatile unsigned int isIPR; EDMA3CCPaRAMEntry paramSet; unsigned char data = 0u; unsigned int retVal = 0u; unsigned int Istestpassed = 0u; unsigned int numenabled = 0u; unsigned int acnt = MAX_ACOUNT; unsigned int bcnt = MAX_BCOUNT; unsigned int ccnt = MAX_CCOUNT; unsigned int irqRaised = 0; int i; /* Enabling the PSC for EDMA3CC_0.*/ PSCModuleControl(SOC_PSC_0_REGS, 0, 0, PSC_MDCTL_NEXT_ENABLE); /* Enabling the PSC for EDMA3TC_0.*/ PSCModuleControl(SOC_PSC_0_REGS, 1, 0, PSC_MDCTL_NEXT_ENABLE); EDMA3Init(SOC_EDMA30CC_0_REGS, evtQ); //srcBuff = (char *)_srcBuff; //dstBuff = (char *)_dstBuff; rxBuff = (short *)_rxBuff; dstBuff = (short *)_dstBuff; /* Initalize source and destination buffers */ for (count = 0u; count < (acnt*bcnt*ccnt); count++) { //rxBuff[count] = 0; ////(short)(512.0*sin(2*PI*count/128)); dstBuff[count] = 0; /* * No need to initialize the destination buffer as it is * being invalidated. */ } /* Request DMA channel and TCC */ retVal = EDMA3RequestChannel(SOC_EDMA30CC_0_REGS, chType, chNum, tccNum, evtQ); McASP_DMA_rx = 0x01D002B8; //0x01D02000; 0x01D002B8; if (TRUE == retVal) { /* Fill the PaRAM Set with transfer specific information */ paramSet.srcAddr = McASP_DMA_rx; //(volatile int)(rxBuff); //McASP_DMA_rx; //(unsigned int)(srcBuff); paramSet.destAddr = (unsigned int)(dstBuff); paramSet.aCnt = 2u; paramSet.bCnt = 512u; paramSet.cCnt = (unsigned short)1; /* Setting up the SRC/DES Index */ paramSet.srcBIdx = 0; paramSet.destBIdx = 2u; paramSet.srcCIdx = 0; paramSet.destCIdx = 2u; paramSet.linkAddr = (unsigned short)0xFFFFu; paramSet.bCntReload = 512u; paramSet.opt = 0u; /* Src & Dest are in INCR modes */ paramSet.opt &= 0xFFFFFFFCu; /* Program the TCC */ paramSet.opt |= ((tccNum << EDMA3CC_OPT_TCC_SHIFT) & EDMA3CC_OPT_TCC); /* Enable Intermediate & Final transfer completion interrupt */ // paramSet.opt |= (1 << EDMA3CC_OPT_ITCINTEN_SHIFT); paramSet.opt |= (1 << EDMA3CC_OPT_TCINTEN_SHIFT); // if (syncType == EDMA3_SYNC_A) // { paramSet.opt &= 0xFFFFFFFBu; /* Now, write the PaRAM Set. */ EDMA3SetPaRAM(SOC_EDMA30CC_0_REGS, chNum, ¶mSet); } isIPR = EDMA3GetIntrStatus(SOC_EDMA30CC_0_REGS); for(i=0; i<32; i++) { EDMA3ClrIntr(SOC_EDMA30CC_0_REGS, i); } isIPR = EDMA3GetIntrStatus(SOC_EDMA30CC_0_REGS); EDMA3ClrIntr(SOC_EDMA30CC_0_REGS, chNum); // EDMA3EnableEvtIntr(SOC_EDMA30CC_0_REGS, 0); // retVal = EDMA3EnableTransfer(SOC_EDMA30CC_0_REGS, chNum, EDMA3_TRIG_MODE_EVENT); } /** * edma3CCComplIsr * \brief ISR for successful transfer completion. * * \note This function first disables its own interrupt to make it non- * entrant. * * \return None. */ void edma3CCComplIsr(void) { volatile unsigned int pendingIrqs; volatile unsigned int isIPR = 0; unsigned int indexl; unsigned int Cnt = 0; indexl = 0u; #ifdef _TMS320C6X // IntEventClear(SYS_INT_EDMA3_0_CC0_INT1); #else // IntSystemStatusClear(SYS_INT_CCINT0); #endif // isIPR = EDMA3GetIntrStatus(SOC_EDMA30CC_0_REGS); // Semaphore_post (txVectorModStart); HWREG(SOC_EDMA30CC_0_REGS + EDMA3CC_S_ICR(1)) = 0xFFFFFFFF; // check for mxASP dma interrupt // indexl = isIPR & 0x1; // bit 0 of dma-IPR // if (indexl != 0) // { // switch buffers /* if(paramSet.srcAddr == (unsigned int)tx_buf1) { paramSet.srcAddr = (unsigned int)tx_buf0; EDMA3SetPaRAM(SOC_EDMA30CC_0_REGS, 31, ¶mSet); dmaTxBuffPtr = tx_buf0; } else { paramSet.srcAddr = (unsigned int)tx_buf1; EDMA3SetPaRAM(SOC_EDMA30CC_0_REGS, 31, ¶mSet); dmaTxBuffPtr = tx_buf1; } */ // trigger swi or post semaphore // Semaphore_post (txVectorModStart); // clear IPR bit // EDMA3ClrIntr(SOC_EDMA30CC_0_REGS, 0); // HWREG(SOC_EDMA30CC_0_REGS+EDMA3CC_ICR(0)) = 0xFFFFFFFF; // } // HWREG(SOC_EDMA30CC_0_REGS + EDMA3CC_S_ICR(1)) = 0xFFFFFFFF; // HWREG(SOC_EDMA30CC_0_REGS + EDMA3CC_S_ICR(0)) = 0xFFFFFFFF; // HWREG(SOC_EDMA30CC_0_REGS + EDMA3CC_S_ICR(2)) = 0xFFFFFFFF; // do other dmas that are enabled // check IPR again // isIPR = EDMA3GetIntrStatus(SOC_EDMA30CC_0_REGS); // if(isIPR != 0) // { // HWREG(SOC_EDMA30CC_0_REGS+EDMA3CC_IEVAL) = 1; // } // return; // Semaphore_post (dmaNextBufStart); } void holder(void) { volatile unsigned int pendingIrqs; volatile unsigned int isIPR = 0; unsigned int indexl; unsigned int Cnt = 0; indexl = 0u; if(isIPR) { while ((Cnt < EDMA3CC_COMPL_HANDLER_RETRY_COUNT)&& (indexl != 0u)) { indexl = 0u; pendingIrqs = EDMA3GetIntrStatus(SOC_EDMA30CC_0_REGS); while (pendingIrqs) { if(pendingIrqs & 1u == 1) { /** * If the user has not given any callback function * while requesting the TCC, its TCC specific bit * in the IPR register will NOT be cleared. */ /* Here write to ICR to clear the corresponding IPR bits */ EDMA3ClrIntr(SOC_EDMA30CC_0_REGS, indexl); } ++indexl; pendingIrqs >>= 1u; } Cnt++; } } }