cancel
Showing results for 
Search instead for 
Did you mean: 

UART IDLE LINE interrupt

federico.massimi
Associate III

hi, I need some advice, I'm trying to implement the IDLE_LINE interrupt for a UART with DMA. I simply need to receive a variable length buffer. I searched the internet and put together various code snippets, I came to this:

in main.c:

__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); 			// enable idle line interrupt
__HAL_DMA_ENABLE_IT(&hdma_usart1_rx, DMA_IT_TC); 		// enable DMA Tx cplt interrupt
HAL_Status = HAL_UART_Receive_DMA(&huart1, usartRxBuffer, RX_BUFFER_SIZE);

in stm_32f4xx_it.c

void USART1_IRQHandler(void){
  /* USER CODE BEGIN USART1_IRQn 0 */
	if (huart1.Instance->SR & UART_FLAG_IDLE) {     /* if Idle flag is set */
		volatile uint32_t tmp;                  	/* volatile to prevent optimizations */
		tmp = huart1.Instance->SR;                  /* Read status register and data reg to clear RX flag*/
		tmp = huart1.Instance->DR;
		(void) tmp;									/* only to not have the compiler warning (variable not used) */
 
		hdma_usart1_rx.Instance->CR &= ~DMA_SxCR_EN; /* Disabling DMA will force transfer complete interrupt if enabled */
	} else {  // else (not IDLE interrupt) use the normal HAL IRQHandler function
  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */
	}
  /* USER CODE END USART1_IRQn 1 */
}
 
void DMA2_Stream2_IRQHandler(void) {
  /* USER CODE BEGIN DMA2_Stream2_IRQn 0 */
	typedef struct {
		__IO uint32_t ISR; /*!< DMA interrupt status register */
		__IO uint32_t Reserved0;
		__IO uint32_t IFCR; /*!< DMA interrupt flag clear register */
	} DMA_Base_Registers;
 
	DMA_Base_Registers *regs = (DMA_Base_Registers *) hdma_usart1_rx.StreamBaseAddress;
 
	if (__HAL_DMA_GET_IT_SOURCE(&hdma_usart1_rx, DMA_IT_TC) != RESET) { // if the source is TC
		SWV_LOG("DATA: %s[%d]\r\n", (char *) huart1.pRxBuffPtr, RX_BUFFER_SIZE - __HAL_DMA_GET_COUNTER(huart1.hdmarx));
		//process_buffer( huart1.pRxBuffPtr, RX_BUFFER_SIZE - __HAL_DMA_GET_COUNTER(huart1.hdmarx));
		memset(huart1.pRxBuffPtr, 0x00, RX_BUFFER_SIZE); // clear buffer
		
		/* Prepare DMA for next transfer */
		/* Important! DMA stream won't start if all flags are not cleared first */
	  regs->IFCR = 0x3FU << hdma_usart1_rx.StreamIndex; 			// clear all interrupts
	  hdma_usart1_rx.Instance->M0AR = (uint32_t)huart1.pRxBuffPtr;  /* Set memory address for DMA again */
	  hdma_usart1_rx.Instance->NDTR = RX_BUFFER_SIZE;    			/* Set number of bytes to receive */
	  hdma_usart1_rx.Instance->CR |= DMA_SxCR_EN;            		/* Start DMA transfer */
	} else { // else (not TC interrupt source) use normal HAL IRQHandler function
  /* USER CODE END DMA2_Stream2_IRQn 0 */
  HAL_DMA_IRQHandler(&hdma_usart1_rx);
  /* USER CODE BEGIN DMA2_Stream2_IRQn 1 */
	}
  /* USER CODE END DMA2_Stream2_IRQn 1 */
}

My MCU is a STM32F401RE

Can you tell me if it's a correct way? are there better ways? could it be unreliable or not consistent in some situations?

Thanks in advance

4 REPLIES 4

I don't think anybody will be willing to read and assess your program.

https://github.com/MaJerle/STM32_USART_DMA

The author is ST FAE.

JW

The program that I sent is that of ST FAE as there is, but integrated with the HAL driver.

I don't want to take credit or steal anyone's work, I just want to know if the ST FAE program can be integrated with HAL drivers in the way I posted, that's all.

Maybe he @Tilen MAJERLE​  can have a look?

JW

Tilen MAJERLE
ST Employee

@federico.massimi​,

tutorial I have made and post on Github is open for anyone. You can leverage from there to understand how it works and reuse part of the code.

It is licensed under MIT.

Tilen