DMA is faster than the task

andreahmed wrote on Friday, May 25, 2018:

Hi,
I’m using K66 NXP and I’m doing ADC DMA transfer, in the ADS Task I’m reading which DMA has been finished then I process the data on that. What I have noticed that the ADC DMA transfer is fasther than the Task, hence the variable that shows which DMA is finished, is never updated correctly. What’s the solution for that problem ?


while(1)
	{
		if(g_edmaTransferDone[ADC0_CHANNEL10_EDMA0] == true)
		{
			g_edmaTransferDone[ADC0_CHANNEL10_EDMA0] = false;
			bufferSelect = (adcBufferSwitch[ADC0_CHANNEL10_EDMA0] == 0U) ? I1_LOWER_READY : I1_UPPER_READY;
			adcBufferSwitch[ADC0_CHANNEL10_EDMA0] = 1U - adcBufferSwitch[ADC0_CHANNEL10_EDMA0];
		}
		else if(g_edmaTransferDone[ADC0_CHANNEL11_EDMA1] == true)
		{
			g_edmaTransferDone[ADC0_CHANNEL11_EDMA1] = false;
			bufferSelect = (adcBufferSwitch[ADC0_CHANNEL11_EDMA1] == 0U) ? Q1_LOWER_READY : Q1_UPPER_READY;
			adcBufferSwitch[ADC0_CHANNEL11_EDMA1] = 1U - adcBufferSwitch[ADC0_CHANNEL11_EDMA1];
		}
		else if(g_edmaTransferDone[ADC1_CHANNEL10_EDMA2] == true)
		{
			g_edmaTransferDone[ADC1_CHANNEL10_EDMA2] = false;
			bufferSelect = (adcBufferSwitch[ADC1_CHANNEL10_EDMA2] == 0U) ? I2_LOWER_READY : I2_UPPER_READY;
			adcBufferSwitch[ADC1_CHANNEL10_EDMA2] = 1U - adcBufferSwitch[ADC1_CHANNEL10_EDMA2];
		}
		else if(g_edmaTransferDone[ADC1_CHANNEL11_EDMA3] == true)
		{
			g_edmaTransferDone[ADC1_CHANNEL11_EDMA3] = false;
			bufferSelect = (adcBufferSwitch[ADC1_CHANNEL11_EDMA3] == 0U) ? Q2_LOWER_READY : Q2_UPPER_READY;
			adcBufferSwitch[ADC1_CHANNEL11_EDMA3] = 1U - adcBufferSwitch[ADC1_CHANNEL11_EDMA3];
		}

		/* send the buffer complete events via message queue */
		if(bufferSelect != BUFFERS_NOT_READY)
		{
			if(xQueueSend(g_adcQueue, &bufferSelect,  ( TickType_t ) 10) != pdPASS)
			{
				throwError(ERROR_MESSAGE_QUEUE_FULL);
				PRINTF("%s\r\n", getErrorMessage(ERROR_MESSAGE_QUEUE_FULL));
			}
			bufferSelect = BUFFERS_NOT_READY;
		}
 	}

rtel wrote on Friday, May 25, 2018:

I’m not sure I understand your question correctly. I would expect a DMA
to be fast, and don’t know what is updating the variable. If the DMA
end interrupt is setting a variable and expecting the task to read it
then it just sounds like a classic race/thread safety condition - the
interrupt is updating the variable faster and at the same time that the
task is reading it. The DMA is presumably writing the data somewhere,
so why is it also updating a variable? Ideally you want to serialise
access by writing to some kind of FIFO so the task reads from one end as
the interrupt writes to the other - effectively buffering data that can
be read out serialy rather than having two threads (an interrupt and a
task in this case) accessing a single variable at the same time. Maybe
a stream buffer can help - but with a DMA it should not be necessary.

andreahmed wrote on Friday, May 25, 2018:

Thanks for your valuable input.
Actually I put the variables that are set by the DMA as volatile. But that didn’t help.