cancel
Showing results for 
Search instead for 
Did you mean: 

Problem with DMA and USART receiving problem

VolterPhase
Associate II

Hello,

I have an STM32F107 microcontroller that uses DMA and USART to receive 250 bytes every 10 ms. The RTOS tick is 1 kHz, so osDelay(1) results in a delay of about 1 ms.

The sender transmits 200 bytes every 5 ms, and during this phase, it is not critical if a 200-byte packet is missed.

On the receiver side, I check DMA_GetCurrDataCounter to determine if 200 bytes have been received. Once 200 bytes are confirmed, I disable the DMA and start processing, which takes less than 1 ms. After processing, I re-enable the DMA and wait to receive the next packet.

 

 

__NO_RETURN static void app_main (void *argument){	
int DMA_Buffer_Current;
USART3Config();
DMA_Configuration();

While(1)
{

				DMA_Time_Alive=DMA_Time_Alive+1;
				if(DMA_Time_Alive>=10)
				{
					DMA_Enable(false);
					DMA_Time_Alive=0;
					DMA_Enable(true);
				}


	DMA_Buffer_Current=500-DMA_GetCurrDataCounter(DMA1_Channel3);
If(DMA_Buffer_Current>=200)
{
DMA_Time_Alive=0;
DMA_Enable(false);
//Do Processing
DMA_Enable(true);

}

osDelay(4);

      }

}

 

 

My DMA buffer[500] array has a size of 500, which is more than twice the size of the input packet.

 

 

void DMA_Configuration(void){
//	DMA_InitTypeDef DMA_InitStructure;	
	NVIC_InitTypeDef NVIC_InitStructure;
	

	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
	NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel3_IRQn;;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 7;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);		
	
	DMA_ClearITPendingBit(DMA1_IT_TC3| DMA1_IT_TE3);
	DMA_Cmd(DMA1_Channel3, DISABLE);

	DMA_SetCurrDataCounter(DMA1_Channel3,sizeof(Buffer));

	DMA_DeInit(DMA1_Channel3);
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART3->DR;
        DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Buffer;
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
	DMA_InitStructure.DMA_BufferSize =sizeof(Buffer);
	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_Mode_Circular ;
	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
	
	DMA_Init(DMA1_Channel3, &DMA_InitStructure);
	
	DMA_ITConfig(DMA1_Channel3, DMA_IT_TC, ENABLE);
	DMA_ITConfig(DMA1_Channel3,DMA_IT_TE, ENABLE);
	
	USART_DMACmd(USART3, USART_DMAReq_Rx, ENABLE);
		
}

 

 

I've defined DMA_Time_Alive to confirm that DMA is operational and receiving packets every 10 ms.

Given the baud rate of 921600, each packet is fully transmitted in less than 3.5 ms.

 

 

 

				DMA_Time_Alive=DMA_Time_Alive+1;
				if(DMA_Time_Alive>=10)
				{
					DMA_Enable(false);
					DMA_Time_Alive=0;
					DMA_Enable(true);
				}

 

 

As far as I understand, if there's an error in the DMA or USART, the DMA stops functioning. Therefore, even if errors occur, DMA_Time_Alive will reinitialize DMA every 40 ms. Furthermore, I handle all errors within the USART interrupts and DMA. Given that the DMA size is larger than each packet size, and considering that I disable and enable DMA upon receiving each packet size, I prefer to clear flags and disable the DMA when it's full.

 

 

void DMA1_Channel3_IRQHandler(void){ // USART3_RX
				DMA_ClearITPendingBit(DMA1_IT_TC3| DMA1_IT_TE3);
				DMA_Cmd(DMA1_Channel3, DISABLE);	
				USART_DMACmd(USART3, USART_DMAReq_Rx, DISABLE);
}	
		
void USART3_IRQHandler(void){						
  if (USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)
	{
			USART_ReceiveData(USART3); 
		  //USART_ITConfig(USART3, USART_IT_RXNE, DISABLE);
	}
		
	if (USART_GetITStatus(USART3, USART_IT_TXE) != RESET)
  {
		  	USART_ITConfig(USART3, USART_IT_TXE, DISABLE);
	}	
	
	if (USART_GetFlagStatus(USART3, USART_FLAG_FE) != RESET) 
	{		
			USART_ReceiveData(USART3);  
			USART_ClearFlag(USART3, USART_FLAG_FE); 
	}
 	
	if(USART_GetFlagStatus(USART3, USART_FLAG_PE) != RESET)         
	{        
		USART_ReceiveData(USART3);  
		USART_ClearFlag(USART3, USART_FLAG_PE); 		
	}		
	
   if(USART_GetFlagStatus(USART3,USART_FLAG_ORE) != RESET)                                             	 
  {                                                                                                    
			USART_ReceiveData(USART3);
			USART_ClearFlag(USART3,USART_FLAG_ORE);		
  } 

   if(USART_GetFlagStatus(USART3,USART_FLAG_NE) != RESET )                                             	 
   {                                                                                                    
			USART_ReceiveData(USART3);
			USART_ClearFlag(USART3,USART_FLAG_NE);		
   }    	
}

 

 

here is my USART config:

 

 

 

void USART3Config(void){
		NVIC_InitTypeDef NVIC_InitStructure;
		USART_InitTypeDef USARTConfigVar;
		GPIO_InitTypeDef GPIOStructure;
	
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO,ENABLE);//Map
				
		GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);
		GPIO_PinRemapConfig(GPIO_PartialRemap_USART3,ENABLE);		
			
		GPIOStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING ;
		GPIOStructure.GPIO_Pin=GPIO_Pin_11;
		GPIOStructure.GPIO_Speed=GPIO_Speed_50MHz;
		GPIO_Init(GPIOC,&GPIOStructure);

		GPIOStructure.GPIO_Mode=GPIO_Mode_AF_PP;
		GPIOStructure.GPIO_Pin=GPIO_Pin_10;
		GPIOStructure.GPIO_Speed=GPIO_Speed_50MHz;
		GPIO_Init(GPIOC,&GPIOStructure);	

		USARTConfigVar.USART_BaudRate=921600;
		USARTConfigVar.USART_Mode=USART_Mode_Rx | USART_Mode_Tx;
		 
		NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
		NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
		NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
		NVIC_InitStructure.NVIC_IRQChannelSubPriority = 10;
		NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
		NVIC_Init(&NVIC_InitStructure);	
		 

			//USART_DeInit(USART3);
			USARTConfigVar.USART_StopBits=USART_StopBits_1;
			USARTConfigVar.USART_WordLength=USART_WordLength_8b;
			USARTConfigVar.USART_Parity=USART_Parity_No ;
			USARTConfigVar.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
			
		  USART_Init(USART3,&USARTConfigVar);
			USART_ITConfig(USART3, USART_IT_ERR, ENABLE);  
			USART_ITConfig(USART3, USART_IT_PE, ENABLE);	
			USART_Cmd(USART3,ENABLE);		 	
}

 

 

 But after about 30 minutes and working well, the DMA stops working and nothing is received even after 40ms that DMA_Time_Alive is present to reinitialize the DMA.

I need to know what my problem is.

2 REPLIES 2

>>I need to know what my problem is

Isn't that why we have debuggers?

So using old SPL, this does seem to be a very convoluted approach.

At the point it stops working what error/status does the DMA and UART report?

What errors get cleared, and how? I see you enumerate some in the IRQ Handler, but how does it get there unless an interrupt is generated? The recovery mechanics surely have to occur in the primary loop, and not by simply disabling/enabling.

The UART is going to be driving it's interrupt, and the DMA requests.

Be sure to clear auto/local variable, the compiler doesn't implicitly clear them, they contain random stack junk.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Hi Tesla DeLorean,

 

I appreciate your response. Yes, you are correct. As I mentioned before, I am using the Real-Time Operating System (RTOS) from Arm Company. The issue I'm facing is that I am unable to debug the code in debug mode due to a problem with the Keil software. As I posted here:

https://community.arm.com/support-forums/f/keil-forum/56072/e300-identifier-not-found---read-os_info-osrtxinfo-not-found

After updating my network middleware, I have lost my ability to use the debugger. (If you have encountered the same problem, I would be grateful if you could let me know how you resolved it). I am considering the line USART3->CR3 |= USART_CR3_EIE, and wondering if any errors that occur might not trigger an interrupt event due to the DMA (Direct Memory Access). Apart from the debugger issue, is there any technical mistake in my code?

Because as you can see, in the main loop, I check the receiving packet each 40ms, and I de-initialize and initialize the DMA completely if there is no packet is received.