Hi,
Processor: TMS320F28335 150Mhz.
ADC -> DMA->Memory (Ping/Pong).
I have been using the processor for some time, but recently found a bug in the operation of using the DMA to move data to memory from the ADC. I am using the ADC sampling at a fast rate(faster than this example shows), with two simultaneous samples(4 A2D values) repeated 4 times before filling the ADC results registers. The DMA is set to transfer 4 values into memory. This is repeated 250 times per buffer, filling first one buffer and then the other buffer.
The Ping/Pong Buffers are DMA1,DMA2 (Uint16 DMA1[4][250];) This pare placed into two memory sections.
The problem I am having is that the DMA seems to be coping the last 2 values from buffer DMA2 into buffer DMA1. and losing buffer DMA1’s last two values. In the example data(attached pdf). Note that at the end of DMA2 (553, 100) values are repeated at the start of DMA1(553,100). This same pattern can be seen over a large set of data, two values from the last part of buffer named DMA2 are replicated in DMA1. Also at the end of DMA1 in the middle section, values seem to be missing. At the start of DMA2 the value 507 without any other values next to 507. Most sets of data shows 3 to 4 values before dropping to 0 for a few samples.
My DMA and ADC configuration code is as follows:
ADC: AdcRegs.ADCTRL1.bit.CPS=1; AdcRegs.ADCTRL1.bit.ACQ_PS =1; // ADC_SHCLK; AdcRegs.ADCTRL3.bit.ADCCLKPS =1; // ADC_CKPS; // ADC will sample in Simultaneous sampling mode is selected. AdcRegs.ADCTRL3.bit.SMODE_SEL = 0x1; AdcRegs.ADCTRL1.bit.SEQ_OVRD = 0x1; // No Wrap at MaxConv AdcRegs.ADCTRL1.bit.SEQ_CASC = 0x1; // 1 Cascaded Mode AdcRegs.ADCTRL2.bit.INT_ENA_SEQ1 = 0x1; // Int on MaxConv AdcRegs.ADCTRL2.bit.RST_SEQ1 = 0x1; // Set SEQ1 to CONV00 AdcRegs.ADCTRL1.bit.CONT_RUN = 0x1; // Continuous Conv mode AdcRegs.ADCMAXCONV.all = 1; // Set up ADC to perform 4 conversions for every SOC AdcRegs.ADCCHSELSEQ1.bit.CONV00=0; // data pair one AdcRegs.ADCCHSELSEQ1.bit.CONV01=1; // data pair two AdcRegs.ADCCHSELSEQ1.bit.CONV02=0; // data pair one AdcRegs.ADCCHSELSEQ1.bit.CONV03=2; // data pair three AdcRegs.ADCCHSELSEQ2.bit.CONV04=0; // data pair one AdcRegs.ADCCHSELSEQ2.bit.CONV05=3; // data pair four AdcRegs.ADCCHSELSEQ2.bit.CONV06=0; // data pair one AdcRegs.ADCCHSELSEQ2.bit.CONV07=4; // data pair five
DMA: EALLOW; DmaRegs.DMACTRL.bit.HARDRESET = 1; // Perform a hard reset on DMA asm (" nop"); // one NOP required after HARDRESET DmaRegs.DEBUGCTRL.bit.FREE = 1; // Allow DMA to run free on emulation suspend // Set up SOURCE address: DmaRegs.CH1.SRC_BEG_ADDR_SHADOW = (Uint32)&AdcMirror.ADCRESULT0; // Point to beginning of source buffer DmaRegs.CH1.SRC_ADDR_SHADOW = (Uint32)&AdcMirror.ADCRESULT0; // Set up DESTINATION address: DmaRegs.CH1.DST_BEG_ADDR_SHADOW = (Uint32)&DMABuf1[0][0]; // Point to beginning of destination buffer DmaRegs.CH1.DST_ADDR_SHADOW = (Uint32)&DMABuf1[0][0]; // Set up BURST registers: DmaRegs.CH1.BURST_SIZE.all = NumberOfChan-1;//Number of words(X-1)x-ferred in a burst DmaRegs.CH1.SRC_BURST_STEP = 1; // Increment source addr between each word x-ferred DmaRegs.CH1.DST_BURST_STEP = NumberOfSamples; // Increment dest addr between each word x-ferred // Set up TRANSFER registers: DmaRegs.CH1.TRANSFER_SIZE = NumberOfSamples-1;//(NumberOfSamples-1); // Number of bursts per transfer, DMA interrupt will occur after completed transfer DmaRegs.CH1.SRC_TRANSFER_STEP = 1;// TRANSFER_STEP is ignored when WRAP occurs DmaRegs.CH1.DST_TRANSFER_STEP = 0;// TRANSFER_STEP is ignored when WRAP occurs // Set up WRAP registers: wrap on 4 reads of ADC DmaRegs.CH1.SRC_WRAP_SIZE = NumberOfChan-1; // Wrap source address after N bursts DmaRegs.CH1.SRC_WRAP_STEP = 0; // Step for source wrap DmaRegs.CH1.DST_WRAP_SIZE = 0; // Wrap destination address after N bursts DmaRegs.CH1.DST_WRAP_STEP = 1; // Step for destination wrap // Set up MODE Register: DmaRegs.CH1.MODE.bit.PERINTSEL = DMA_SEQ1INT; // Passed DMA channel as peripheral interrupt source DmaRegs.CH1.MODE.bit.PERINTE = PERINT_ENABLE; // Peripheral interrupt enable DmaRegs.CH1.MODE.bit.ONESHOT = ONESHOT_DISABLE; // Oneshot disable DmaRegs.CH1.MODE.bit.CONTINUOUS = CONT_ENABLE; // Continous enable DmaRegs.CH1.MODE.bit.SYNCE = SYNC_ENABLE; // Peripheral sync enable/disable DmaRegs.CH1.MODE.bit.SYNCSEL = SYNC_SRC; //Sync effects source or destination DmaRegs.CH1.MODE.bit.OVRINTE = OVEFLOW_ENABLE;//Enable/disable the overflow interrupt DmaRegs.CH1.MODE.bit.DATASIZE = SIXTEEN_BIT; // 16-bit/32-bit data size transfers DmaRegs.CH1.MODE.bit.CHINTMODE = CHINT_END; // Generate interrupt to CPU at end of transfer DmaRegs.CH1.MODE.bit.CHINTE = CHINT_ENABLE; // Channel Interrupt to CPU enable // Clear any spurious flags: DmaRegs.CH1.CONTROL.bit.PERINTCLR = 1; // Clear any spurious interrupt flags DmaRegs.CH1.CONTROL.bit.SYNCCLR = 1; // Clear any spurious sync flags DmaRegs.CH1.CONTROL.bit.ERRCLR = 1; // Clear any spurious sync error flags // Initialize PIE vector for CPU interrupt: PieCtrlRegs.PIEIER7.bit.INTx1 = 1; // Enable DMA CH1 interrupt in PIE DmaRegs.CH1.CONTROL.bit.RUN = 1; //--- Enable the DMA interrupt IER |= 0x0040; // Enable INT7 in IER to enable PIE group EDIS;
I have been working in a DSP/BIOS project for most of the code development, but moved this example back into none RTOS based project to remove all outside code. The same basic problem of data not being filled into the correct memory location exists in both sets of code.
I am thinking that I have missed something in the data sheets or I am using the ADC/DMA in a way that just was not intended to be used. As the DMA transfer works for filling most of the buffer with values that make sense, it it seems its a boundry case that when the buffer's are switching somthing is mixing up data. I have the following code that runs just after the ISR posts a flag into the main while loop.
if(DMA_INTPost == 1) { DMA_INTPost=0; //clear for next INT to set, we dont want to enter function unless we have new data. iPingPong ^= 1; // iPingPong toggles between 0 and 1 //--- Process the ADC data if(iPingPong == 1) // Ping buffer filling, process Pong bugger { ProcessBuffer=&DMABuf1[0][0]; //process DMABuf1 IERValue=IER; IER=0; EALLOW; asm (" nop"); asm (" nop"); DmaRegs.CH1.DST_BEG_ADDR_SHADOW = (Uint32)&DMABuf1[0][0]; // load DMABuf1 as we are waiting for DMABuf2 to fill DmaRegs.CH1.DST_ADDR_SHADOW = (Uint32)&DMABuf1[0][0]; EDIS; IER=IERValue; } else // Pong buffer filling, process Ping buffer { ProcessBuffer=&DMABuf2[0][0];// Disable EALLOW protected register access IERValue=IER; IER=0; EALLOW; asm (" nop"); asm (" nop"); DmaRegs.CH1.DST_BEG_ADDR_SHADOW = (Uint32)&DMABuf2[0][0]; // Point to beginning of destination buffer DmaRegs.CH1.DST_ADDR_SHADOW = (Uint32)&DMABuf2[0][0]; EDIS; IER=IERValue; } // handle dma data for(i=0;i<250;i++) MegaBuffer[0][MegaPtr++]=ProcessBuffer[i]; if(MegaPtr>MegaBufSize) { //Count+=1; MegaPtr=0; // reset to zero }
Looking to see what input I can get.
Thanks,
Caleb