cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 UART Idle Interrupt configuration

BKell.2
Associate

Hello,

I want to use a UART Idle Interrupt Routine to handle an unknown number of incoming bytes.

I set this up for 2 UARTs right now and it works like a Charm for one of them. The working UART operates at 115200 Baud. The second Uart should work with 9600Baud.

The Problem with my second UART lies on the HW Side. Here I have a LIN Driver which gives me an unwanted echo on my Rx Side.

0693W00000D1F1IQAV.pngAs you can see the first UART Message is the Echo from the Tx of my STM32 and the second UART Message is the real reply which I want to have.

It wouldn't be a problem to filter out the first response on my IT Service Routine, but the IDLE Interrupt triggerst AFTER the second UART Message resulting in a really long byte array where it sometimes also detects the high signal as '0's. Is there any way to configure the IDLE Timing? I'm using HAL .

4 REPLIES 4
TDK
Guru

A high signal is an idle bus, it's not a string of value 0 bytes. Gotta be something else happening there to explain it, probably a big within the firmware. Going to be hard to debug without showing any code or even which chip you're using.

The idle interrupt doesn't work any differently due to bytes being echoed, but you'll need to filter those out in the proper manner.

If you feel a post has answered your question, please click "Accept as Solution".
Pavel A.
Evangelist III

Which STM32? If it has Receive timeout (RTO) feature - you want to use that instead of the idle interrupt.

BKell.2
Associate

I forgot to mention. I'm using a STM32F373CBTx.

But why does it write a bunch of '0' then?

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	/*
	 * UART Rx Complete Callback
	 * Rx Complete is called by DMA: if it rolls over and when IDLE Interrupt occurs
	 * DMA interrupt always occurs befor  the idle interrupt can be fired because idle detection needs at least one UART clock to detect the bus is idle.
	 * */
	if(__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE))
	{
		__HAL_UART_CLEAR_IDLEFLAG(huart);
 
		start = RxBfrPos;
		RxBfrPos = RX_MAX_SIZE - (uint16_t)huart->hdmarx->Instance->CNDTR;
		uint16_t len = RX_MAX_SIZE;
 
		if (RxRollover < 2)
		{
			if (RxRollover)
			{
				if (RxBfrPos <= start) len = RxBfrPos + RX_MAX_SIZE - start;
				else len = RX_MAX_SIZE + 1;
			}
			else
			{
				len = RxBfrPos- start;
			}
		}
		else
		{
			len = RX_MAX_SIZE + 2;
		}
 
		if (len && (len <= RX_MAX_SIZE))
		{
			rxFlag = 1;
			laengeNachricht = len;
		}
		else
		{
			rxFlag = 0;
		}
		RxRollover = 0;
	}
	else
	{
		//No idle Flag
		RxRollover++;
	}
}

And in the interrupt file:

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 (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE))
  {
	  HAL_UART_RxCpltCallback(&huart1);
  }
  /* USER CODE END USART1_IRQn 1 */
}

In the Init fkt:

static void MX_USART1_UART_Init(void)
{
 
  /* USER CODE BEGIN USART1_Init 0 */
 
  /* USER CODE END USART1_Init 0 */
 
  /* USER CODE BEGIN USART1_Init 1 */
 
  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */
 
  /* USER CODE END USART1_Init 2 */
 
}

In the Main():

  __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
  HAL_UART_Receive_DMA(&huart1, UART1_rxBufferDMA, RX_MAX_SIZE);

DMA is configured as circular mode.

I will try the receive timeout, in the meantime I had the idea. I could just listen for as many bytes as I'm sending in IT Mode and after the last Interrupt I can listen for the real incoming bytes in DMA Mode. This could also eliminate the faulty '0's.

Sebastiaan
Senior

Depending on the timing, some of your devices on the LIN bus might reply within or after the IDLE timeout, which makes it harder.

But I'm assuming that's not the case here, so I would just do a DMA receive, and use the IDLE interrupt to inspect your RX buffer. If rx buffer only contains the echo, you need to wait for another interrupt. If it also includes the reply, you can process that or copy it in a different buffer if that's desired.