cancel
Showing results for 
Search instead for 
Did you mean: 

DMA fails to complete (STM32F303x)

gbigden
Associate III
Posted on November 12, 2015 at 10:26

This is a rather complex problem. I have an interrupt routine running under the systick handler with a period of 10mS. Within this I do 4096 reads of ADC3 via DMA2_Channel5, which works fine. Single shot mode

The problem comes when I have data coming in from USART2 via DMA1_Channel6. Occasionally DMA2 fails to complete the transfer, that is, it's counter decrements but does not get to zero.

AFAIK I have set up the interrupts with systick having the highest priority, followed by DMA2 and then DMA1

Any ideas as to what might be happening?

#triage-nurse #stm32
10 REPLIES 10
gbigden
Associate III
Posted on November 12, 2015 at 16:21

If I add a 500uS delay at the end of my DMA setup the problem disappears - any ideas why?

_____________________________

void DMA2_ADC3_Config(void)

{

  DMA_InitTypeDef   DMA_InitStructure;

  int numSamples;

 

  numSamples = sizeof( Receive.rawData ) / sizeof( Receive.rawData[0]);

     

    // Enable DMA2 clock

  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);

  DMA_DeInit(DMA2_Channel5);

  

  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &ADC3->DR;

  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Receive.rawData;       

  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;

  DMA_InitStructure.DMA_BufferSize = numSamples; 

  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;       //Set for 16 bit

  

  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;                   

  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

  DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;

  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

  

  DMA_Init(DMA2_Channel5, &DMA_InitStructure);

  delayMicrosecondsT3(500);

}

_____________

dhiry2k1
Associate II
Posted on November 12, 2015 at 18:56

Try binding ADC using DMA interrupts ... I had this problem using USART. If you notice , one or 2 bytes will always gets stuck in buffer.

gbigden
Associate III
Posted on November 13, 2015 at 12:49

Hi - Not sure how to do that. I have set up the DMA to deliver 4096 samples as fast as the ADC can deliver them. I have now reduced the delay to 50uS and it still works perfectly. I would like to know why.

gbigden
Associate III
Posted on November 18, 2015 at 12:35

Can I please get some help on this. Having to put in a delay is causing serious problems elsewhere

gbigden
Associate III
Posted on November 18, 2015 at 16:23

Full code - which works, unless I remove the delay

void DMA2_Channel5_Config(void)

{

  DMA_InitTypeDef   DMA_InitStructure;

  int numSamples;

 

  numSamples = sizeof( Receive.rawData ) / sizeof( Receive.rawData[0]);

     

    // Enable DMA2 clock

  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);

  DMA_DeInit(DMA2_Channel5);

  

  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &ADC3->DR;

  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Receive.rawData;       

  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;

  DMA_InitStructure.DMA_BufferSize = numSamples; 

  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;       //Set for 16 bit

  

  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;                   

  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

  DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;

  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

  

  DMA_Init(DMA2_Channel5, &DMA_InitStructure);

  DMA_Cmd( DMA2_Channel5, ENABLE );

  delayMicrosecondsT3(50);                      //NOTE!!!!!!!!!!!!!!!!!!!!!!!!!!! No idea why this is needed, but without it the ADC/DMA sometimes never completes and the data collection hangs up

}

  //******************************************************************************

  // Set up ADC3 to do DMA conversions of sound reflections to memory

  // Note - Only some DMA and channels mapped to ADC numbers

  // DMA1_Ch1 -> ADC1

  // DMA2_Ch1 -> ADC2

  // DMA2_Ch2 -> ADC4

  // DMA2_Ch3 -> ADC2

  // DMA2_Ch4 -> ADC4

  // DMA2_Ch5 -> ADC3

  //******************************************************************************

  

void ADC3_Go( void )

{

  ADC_InitTypeDef ADC_InitStructure;

  int ADC_Sample_Time;

  RCC_ADCCLKConfig(RCC_ADC34PLLCLK_Div1);      

  RCC_AHBPeriphClockCmd( RCC_AHBPeriph_ADC34, ENABLE );

  ADC_StructInit( &ADC_InitStructure );

  ADC_InitStructure.ADC_ContinuousConvMode = ADC_ContinuousConvMode_Enable;

  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; 

  ADC_InitStructure.ADC_ExternalTrigConvEvent = ADC_ExternalTrigConvEvent_0;         

  ADC_InitStructure.ADC_ExternalTrigEventEdge = ADC_ExternalTrigEventEdge_None;

  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

  ADC_InitStructure.ADC_OverrunMode = ADC_OverrunMode_Disable;   

  ADC_InitStructure.ADC_AutoInjMode = ADC_AutoInjec_Disable; 

  ADC_InitStructure.ADC_NbrOfRegChannel = 1;

  ADC_Init(ADC3, &ADC_InitStructure); 

  ADC_Sample_Time = MachineState.ADC_Sample_Time;                       //Actual conversion time is 12.5 clock cycles + ADC_Sample_Time (usually 1.5 cycles) = 14 cycles

  ADC_RegularChannelConfig(ADC3, ADC_Channel_1, 1, ADC_Sample_Time);    

   

  DMA2_Channel5_Config(); 

  ADC_Cmd( ADC3, ENABLE );      //Enable ADC3 

  ADC_DMACmd( ADC3, ENABLE );   //Enable ADC3 DMA 

      

  while( !ADC_GetFlagStatus( ADC3, ADC_FLAG_RDY ) );    // wait for ADRDY 

  ADC_StartConversion( ADC3 );  // Start ADC3 Software Conversion 

 

}

dthedens
Associate II
Posted on November 18, 2015 at 16:37

Do you call the function DMA2_ADC3_Config() repetitively?

I would enable the clock once and only once in main()

Maybe you are trying to be safe by DMA_DeInit() but I doubt it is that useful.

Using DMA with UART input is tricky.  If there are errors, the DMA might not finish.

there is a useful app note about using a timer to monitor activity on the UART pin which can provide a recovery mechanism when errors occur.  Forgot the AN number

Anyway, AN4031 is a good read.

gbigden
Associate III
Posted on November 18, 2015 at 16:42

I use DMA1 with the USART and DMA2 is reserved for ADC3

Posted on November 18, 2015 at 17:20

Full code...

Um, no.

I'm not sure of the value of tearing down everything to restart the DMA, and if that is necessary, but the delay is indicative of a race condition, where you want to ensure this path loses. You'll need to look carefully at the order and sequence of things. Consider moving the clocks outside this level, and just what it takes to Init the DMA a second time around.

You need to condense your failure condition into a complete/concise example, if I can't see a way to replicate/identify your issue in five minutes or less, I'm not going to even start looking. I think you need to figure out who's going to help you, and how much context and framework that's going to take.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
gbigden
Associate III
Posted on November 19, 2015 at 16:03

I have followed your suggestions and moved various initializations outside the loop. Still the same problem, which seems to stem from this code, in that when I do not use it there is no problem. This is set up during initialization and is not touched again.

void DMA_ConfigurationUSART2(void)

{

  DMA_InitTypeDef  DMA_InitStructure;

  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); 

  

 

  // USART2_RX DMA1 Channel 6 

 

  DMA_DeInit(DMA1_Channel6); 

  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                            // Receive

  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&PacketIn.buffer;

  DMA_InitStructure.DMA_BufferSize = sizeof( PacketIn.buffer );

  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART2->RDR;

  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

//  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

  DMA_InitStructure.DMA_Priority = DMA_Priority_Low;

 

  DMA_Init(DMA1_Channel6, &DMA_InitStructure);

 

  // Enable the USART Rx DMA request 

  USART_DMACmd(USART2, USART_DMAReq_Rx, ENABLE);

 

  // Enable DMA Stream Transfer Complete interrupt 

  DMA_ITConfig(DMA1_Channel6, DMA_IT_TC, ENABLE);

 

  // Enable the DMA RX Stream 

  DMA_Cmd(DMA1_Channel6, ENABLE);

}

 

 

void DMA1_Channel6_IRQHandler(void) //RX

{

  //Test on DMA Stream Transfer Complete interrupt 

  if (DMA_GetITStatus(DMA1_IT_TC6))

  {

      // Clear DMA Stream Transfer Complete interrupt pending bit 

    DMA_ClearITPendingBit(DMA1_IT_TC6);

    

    if (PacketIn.rxFull == true) 

      return;        //Because we have not yet handled the other requests

    else

      PacketIn.rxFull = true;

  }

}