cancel
Showing results for 
Search instead for 
Did you mean: 

Using a STM32F4 MCU: Which is the right way to manage the TX and RX ?

nvincis88
Associate

 Hi all,

I'm using a STM32F4 MCU

I'm having much problem handling ISR and/or DMA with UART TX/RX

Could anyone tell me which is the right way to manage the TX and RX ?

In case of ISR i can only TX correctly , but when i try to RX ... i can receive only 4 byte, the other data generate a OVERRUN Error that i can't handle.

In case of DMA the RX won't works and the TX works only with the debugger ( Step by Step ) .

Without debugger the string is overwritten.

For Example these two string that i have to print:

1) CAN Filter Configured!

2) CAN Controller Started!

produces this output:

CAN Filter Confitarted!

If is necessary i can paste the code that i'm using.

Thanks a lot

3 REPLIES 3

So, sounds like you're reusing the same buffer, and not managing the completion properly. The IT and DMA USART commands do not block, you must manage completion in the callbacks. Here you'd probably want to have your own buffering, and understand if you have a prior DMA/IT operation already pending. If you have something already pending you should queue the data, and light off the new transfer when you get a completion on the active one.

The HAL is perhaps overly cumbersome in this regard, but you're not compelled to use it.

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

USART = Low Layer is a good fit.

It depends on how to process the incoming data and how fast you want to process incoming messages.

If you can manage 2 msec delay to process incoming RX data, use DMA in circular buffer and check from the main loop every 2msec if something has been fully received.

If you want to do the 8 bit MCU way, get RX as interrupt byte by byte and fill a buffer, decode when the message is fully received (header, length byte, termination char, etc..). Set a flag in the interrupt to tell the main loop to process then clear the flag.

While the flag is set, use backup buffer or discard incoming bytes. your choice.

For TX, just directly write bytes in polling, if you are using a kind of "printf" you'll be cooking char by char while a char is being pushed out, not so much waste of time here.

nvincis88
Associate

I did the following operations:

0) On Init:

g_OperationStatus = HAL_UART_Receive_IT(p_Uart, UART1_RxBuffer, RXBUFFERSIZE);
 
Where :
 
/* Size of Reception buffer */
#define RXBUFFERSIZE                      1u	 
 
/* Buffer used for reception */
uint8_t UART1_RxBuffer[RXBUFFERSIZE];

1) IRQHandler

void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */
 
  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */
	
#if ( USE_UART_ISR == 1u )
	
  /* USER CODE BEGIN USART2_IRQn 0 */
 
#if 0
  case USART_IT_TXE: 	//to indicate the status of the transmit buffer register
	  break;
  case USART_IT_RXNE:  //to indicate the status of the receive buffer register
	  break;
  case USART_IT_TC: 	//to indicate the status of the transmit operation
	  break;
  case USART_IT_IDLE:  //to indicate the status of the Idle Line
	  break;
  case USART_IT_CTS:   //to indicate the status of the nCTS input
	  break;
  case USART_IT_LBD:   //to indicate the status of the LIN break detection
	  break;
  case USART_IT_NE: 	//to indicate if a noise error occur
	  break;
  case USART_IT_FE: 	//to indicate if a frame error occur
	  break;
  case USART_IT_PE: 	//to indicate if a parity error occur
	  break;
  case USART_IT_ORE: 	//to indicate if an Overrun error occur
	  break;
#endif
	
#if 0 //Never read data in the interrupt
 
  /* UART in mode Receiver -------------------------------------------------*/
  if(((*READ_REG(USED_UART_PORT_PTR.Instance->SR)  & USART_SR_RXNE) 	 != RESET) && 
     ((*READ_REG(USED_UART_PORT_PTR.Instance->CR1) & USART_CR1_RXNEIE) != RESET))
  {
	  	MX_UART_ReceiveData(USED_UART_PORT_PTR);
		
	//	HAL_UART_Receive_IT(USED_UART_PORT_PTR, RxBuffer, 1);
		
  }
 
#else
 
#endif
 
#endif
  /* USER CODE END USART1_IRQn 1 */
}

2) TX / RX / Error Callbacks

//
// Initialize the command buffer being processed to all null characters
//
void UART_ClearTxBuffer()
{
		memset(UART1_TxBuffer, 0x0, TXBUFFERSIZE);
	
#if 0
		TxBufferLock = 0u;
#else
	//	USED_UART_PORT_PTR->gState = HAL_UART_STATE_READY;
#endif
 
#if ( USE_UART_ISR == 1u )
		__HAL_UART_ENABLE_IT(USED_UART_PORT_PTR, UART_IT_RXNE);	//Enable Interrupt of UART RX
#endif
 
 
}
 
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
	UART_ClearTxBuffer();
}
 
 
/*
*  RX SEND END CALLBACK
*/
 
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart->Instance == USART1)
	{
		//USART1
		//MX_UART_ReceiveData(USED_UART_PORT_PTR);
 
		if(UART1_RxBuffer != NULL)
		{
 
		      __HAL_UART_CLEAR_FLAG(huart, UART_FLAG_RXNE);
 
			  UART_printf("UART Data Received Bytes\r\n");
		}
 
	}
	else
	{
 
	}
}
 
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
	if(huart->Instance == USED_UART_PORT)
	{
		if (huart->ErrorCode == HAL_UART_ERROR_ORE) // overrun
		{
 
			/* Process Locked */
			__HAL_LOCK(huart);
 
			huart->ErrorCode = HAL_UART_ERROR_NONE;
			huart->RxState = HAL_UART_STATE_BUSY_RX;
 
			/* Process Unlocked */
			__HAL_UNLOCK(huart);
 
#if ( USE_UART_ISR == 1u )
 
			/* Enable the UART Parity Error Interrupt */
			__HAL_UART_ENABLE_IT(huart, UART_IT_PE);
 
			/* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
			__HAL_UART_ENABLE_IT(huart, UART_IT_ERR);
 
			/* Enable the UART Data Register not empty Interrupt */
			__HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);
 
			// MX_UART_ReceiveData(USED_UART_PORT_PTR);
 
#endif
 
		}
	}
}