关于stm32 HAL库在freertos下串口+DMA发送完成中断处理的问题

平台环境:stm32f407+freertos
硬件接口:USART1+DMA
出现的问题:因为是在RTOS系统下,因此串口1的发送思路:调用HAL_UART_Transmit_DMA函数前需要获得对应的信号量,DMA发送完成中断触发后在中断中释放对应的信号量。然而,在stm32f4xx_it.c文件中找到串口1链接的DMA2_Stream7的中断,该中断只做了一件事,调用HAL_DMA_IRQHandler中断处理函数。如果直接在DMA2_Steam7_IRQHandler释放信号量,那么如果DMA触发半传输完成中断的时候也会释放一次信号量(即1次传输释放2次)从设计的角度来说不能接收。
/**
* @brief This function handles DMA2 stream7 global interrupt.
*/
void DMA2_Stream7_IRQHandler(void)
{
  /* USER CODE BEGIN DMA2_Stream7_IRQn 0 */

  /* USER CODE END DMA2_Stream7_IRQn 0 */
  HAL_DMA_IRQHandler(&hdma_usart1_tx);
	
  /* USER CODE BEGIN DMA2_Stream7_IRQn 1 */
  /* USER CODE END DMA2_Stream7_IRQn 1 */
}
因此,在HAL_DMA_IRQHandler在HAL_DMA_IRQHandler中断处理函数中找到下述代码,代码中判断如果是DMA发送完成中断,则调用回调函数。这里,我准备注册一个自定义的回调函数来释放所需的信号量。
if ((tmpisr & (DMA_FLAG_TCIF0_4 << hdma->StreamIndex)) != RESET)
{  ...;
  if(hdma->XferCpltCallback != NULL)
  {
    /* Transfer complete callback */
    hdma->XferCpltCallback(hdma);
  }
}
DMA库函数通过调用下述函数进行注册:
HAL_StatusTypeDef HAL_DMA_RegisterCallback(DMA_HandleTypeDef *hdma, HAL_DMA_CallbackIDTypeDef CallbackID, void (* pCallback)(DMA_HandleTypeDef *_hdma))
于是,写了如下注册函数用以实现回调:
void Uart_DMA_Tx_CPLT_Callback(DMA_HandleTypeDef *hdma)
{
 static portBASE_TYPE xHigherPriorityTaskWoken;
 MY_PRINTF(HAL_GetTick(),"Uart1_DMA_Tx_CPLT_Callback",0,0);
 xSemaphoreGiveFromISR(sem_uart1_tx,&xHigherPriorityTaskWoken);
}
然而,调试结果始终没有打印出相关信息,直到研究了HAL_UART_Transmit_DMA(&huart1,buf,size)这个函数才发现问题所在。截取该函数中下面这句话,意味着每次调用HAL_UART_Transmit_DMA函数都会重新注册一次DMA发送中断完成的回调函数。
/* Set the UART DMA transfer complete callback */
huart->hdmatx->XferCpltCallback = UART_DMATransmitCplt;
在下述函数中加入对应代码,实现了DMA中断传输完成释放信号量:
static void UART_DMATransmitCplt(DMA_HandleTypeDef *hdma)
{
  static portBASE_TYPE xHigherPriorityTaskWoken;
  UART_HandleTypeDef* huart = ( UART_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent;
  /* DMA Normal mode*/
  if((hdma->Instance->CR & DMA_SxCR_CIRC) == 0U)
  {
    huart->TxXferCount = 0U;
    /* Disable the DMA transfer for transmit request by setting the DMAT bit
       in the UART CR3 register */
    CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAT);
    /* Enable the UART Transmit Complete Interrupt */
    SET_BIT(huart->Instance->CR1, USART_CR1_TCIE);
  
    if ( hdma == &hdma_usart1_tx )
    {
       xSemaphoreGiveFromISR(sem_uart1_tx,&xHigherPriorityTaskWoken);    
    }
  }
  /* DMA Circular mode */
  else
  {
    HAL_UART_TxCpltCallback(huart);
  }
}




你可能感兴趣的:(stm32)