关于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);
  }
}



  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
下面是使用CubeMX配置FreeRTOSDMA串口接收的示例代码: 1. 配置FreeRTOS 在CubeMX,打开Project Manager视图,选择FreeRTOS,并启用RTOS。 2. 配置USART串口 在Pinout & Configuration视图,选择需要使用的USART串口,并配置为接收模式。例如,将USART2配置为接收模式,波特率为115200。 3. 配置DMA 在Pinout & Configuration视图,选择需要使用的DMA通道,并配置为USART2的接收通道。例如,将DMA1_Stream5配置为USART2的接收通道。 4. 生成代码并添加接收代码 在CubeMX,点击"Generate Code"按钮,生成代码。然后,在main.c文件添加以下代码,以接收USART2的数据: ``` #include "main.h" #include "FreeRTOS.h" #include "task.h" #include "usart.h" /* Buffer used for reception */ uint8_t uartRxBuffer[10]; /* Task handle */ TaskHandle_t xTaskHandle; void vTaskFunction(void *pvParameters) { while (1) { /* Wait for data to be received */ xSemaphoreTake(xSemaphore, portMAX_DELAY); /* Process received data */ printf("Received data: %s\r\n", uartRxBuffer); } } /* DMA USART2 interrupt callback */ void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; /* Give semaphore to unblock the task */ xSemaphoreGiveFromISR(xSemaphore, &xHigherPriorityTaskWoken); /* Clear the interrupt flag */ __HAL_DMA_DISABLE_IT(huart->hdmarx, DMA_IT_TC); __HAL_UART_CLEAR_OREFLAG(huart); /* Switch context if necessary */ portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } int main(void) { /* Initialize FreeRTOS */ xSemaphore = xSemaphoreCreateBinary(); xTaskCreate(vTaskFunction, "Task", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, &xTaskHandle); /* Enable DMA interrupt */ __HAL_DMA_ENABLE_IT(&hdma_usart2_rx, DMA_IT_TC); /* Start USART reception */ HAL_UART_Receive_DMA(&huart2, uartRxBuffer, sizeof(uartRxBuffer)); /* Start FreeRTOS scheduler */ vTaskStartScheduler(); while (1) { } } ``` 在上述代码,我们创建了一个FreeRTOS任务,在任务等待接收到数据。当数据被接收时,DMA USART2中断会触发回调函数HAL_UART_RxCpltCallback(),它将释放一个信号量,以便任务可以继续处理接收到的数据。请注意,我们使用了xSemaphoreTake()和xSemaphoreGiveFromISR()函数来在任务和中断之间进行同步。 这就是使用CubeMX配置FreeRTOSDMA串口接收的示例代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值