/stm32f4-FreeRTOS-uart-interrupt-queue

STM32F4 Asynchronous Interrupt (both Receive/Transmit) + Free RTOS queue application

Primary LanguageC

STM32F4 Asynchronous Interrupt (both Receive/Transmit) + Free RTOS queue application

#stm32f4, #hal, #uart, #stm32cube, #stm32cubeide, #rtos, #freertos

If you encounter the problem of using UART with HAL of stm32 microcontrollers, you should check out this small application. I have tested it on Macos, so there might be some issue if you are using different OS. Please let me know if it so.

Basically, you need to do 3 steps to make UART interrupt works.

  1. Configure it correctly. Here are 2 functions needed to do it. Stm32CubeIDE will generate it automatically, but check back once again is not redundant.
static void MX_NVIC_Init(void)
{
  /* USART2_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(USART2_IRQn, 5, 0);
  HAL_NVIC_EnableIRQ(USART2_IRQn);

}

static void MX_USART2_UART_Init(void)
{

  /* USER CODE BEGIN USART2_Init 0 */
  /* USER CODE END USART2_Init 0 */

  /* USER CODE BEGIN USART2_Init 1 */

  /* USER CODE END USART2_Init 1 */
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 115200;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART2_Init 2 */



  /* USER CODE END USART2_Init 2 */

}

static void MX_GPIO_Init(void)
{
  /**USART2 GPIO Configuration
  PA2     ------> USART2_TX
  PA3     ------> USART2_RX
  */
	GPIO_InitStruct_UART2.Pin = GPIO_PIN_2 | GPIO_PIN_3;
	GPIO_InitStruct_UART2.Mode = GPIO_MODE_AF_PP;
	GPIO_InitStruct_UART2.Pull = GPIO_PULLUP;
	GPIO_InitStruct_UART2.Speed = GPIO_SPEED_LOW;
	GPIO_InitStruct_UART2.Alternate = GPIO_AF7_USART2;
	HAL_GPIO_Init(GPIOA, &GPIO_InitStruct_UART2);
}
  1. Write an interrupt handle in your main function. If you don't do it, UART interrupt wont work. Make sure the pattern you use in this function match with the one in the callback func.
// This is needed to wake up UART interrupt
  // It's format has to be consistent with one in HAL_UART_RxCpltCallback
  HAL_UART_Receive_IT(&huart2, &byte, 1);
  1. Callback & Handler. Here, the autogenerated code said that you can put some code here to handle the interrupt. But it takes me too much time to figure out it does not work (like using the SPL). May be I need to learn more.
    Please slap me in the face with knowledge if you know why and how. Thank you.
void USART2_IRQHandler(void)
{
  /* USER CODE BEGIN USART2_IRQn 0 */

  /* USER CODE END USART2_IRQn 0 */
  HAL_UART_IRQHandler(&huart2);
  /* USER CODE BEGIN USART2_IRQn 1 */

  /* USER CODE END USART2_IRQn 1 */
}

/* USER CODE BEGIN 1 */
/* This callback is called by the HAL_UART_IRQHandler when the given number of bytes are received */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  if (huart->Instance == USART2)
  {
	  BaseType_t xHigherPriorityTaskWoken = pdFALSE;

 /* Transmit one byte with 100 ms timeout */
	/* Receive one byte in interrupt mode */
	HAL_UART_Receive_IT(&huart2, &byte, 1);

	cmd_buffer[cmd_len++] = byte & 0xFF;

    /* Check for "Enter" cmd - finish input */
	if (byte == '\r'){
		// Response to confirm message received
		char msg[50] = "\rYour command is: \"";
		HAL_UART_Transmit(&huart2, &msg, sizeof(msg), 100);

		// There is a '\n' at cmd_buffer[0]
		if (cmd_buffer[0] == '\n'){
			HAL_UART_Transmit(&huart2, &cmd_buffer[1], cmd_len-2, 100);
		}
		else{
			HAL_UART_Transmit(&huart2, &cmd_buffer, cmd_len-1, 100);
		}
		char msg1[50] = "\".\r\n";
		HAL_UART_Transmit(&huart2, &msg1, sizeof(msg1), 100);

	    cmd_len = 0;
	    // user finished entering data
	    // Notify cmd handing task
	    xTaskNotifyFromISR( menuDisplayTaskHandle, 0, eNoAction, &xHigherPriorityTaskWoken);

	    xTaskNotifyFromISR(cmdHandlingTaskHandle, 0, eNoAction, &xHigherPriorityTaskWoken);
  }
	// yield
	if (xHigherPriorityTaskWoken){
		taskYIELD();
	}
  }
}