STM32F103 STM32CUBE HAL库 串口DMA接收无法执行回调
- [一、STM32CubeMX 串口DMA配置](#一、STM32CubeMX 串口DMA配置)
- 二、串口程序生成代码
- 三、代码新增
-
- [3.1 自定义DMA回调函数](#3.1 自定义DMA回调函数)
- 四、DMA发送问题点
- 总结
一、STM32CubeMX 串口DMA配置
配置串口2波特率19200,启用DMA发送正常模式。配置DMA中断。
二、串口程序生成代码
串口初始化程序
c
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 = 19200;
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 */
}
DMA中断处理程序入口
c
/**
* @brief This function handles DMA1 channel6 global interrupt.
*/
void DMA1_Channel6_IRQHandler(void)
{
/* USER CODE BEGIN DMA1_Channel6_IRQn 0 */
/* USER CODE END DMA1_Channel6_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_usart2_rx);
/* USER CODE BEGIN DMA1_Channel6_IRQn 1 */
/* USER CODE END DMA1_Channel6_IRQn 1 */
}
/**
* @brief This function handles DMA1 channel7 global interrupt.
*/
void DMA1_Channel7_IRQHandler(void)
{
/* USER CODE BEGIN DMA1_Channel7_IRQn 0 */
/* USER CODE END DMA1_Channel7_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_usart2_tx);
/* USER CODE BEGIN DMA1_Channel7_IRQn 1 */
/* USER CODE END DMA1_Channel7_IRQn 1 */
}
三、代码新增
3.1 自定义DMA回调函数
弱函数重定义
c
/**
* @brief Tx Transfer completed callbacks.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @retval None
*/
__weak void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(huart);
/* NOTE: This function should not be modified, when the callback is needed,
the HAL_UART_TxCpltCallback could be implemented in the user file
*/
}
重定义回调函数
c
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1)
{
...
}
}
四、DMA发送问题点
在实际测试中,发现第一次发送后进入中断后无法再次发送,且未执行回调函数。
调试发现。
当发送使用HAL_UART_Transmit_DMA发送数据时,状态呗置位了,再次发送不发进入if判断。
解决办法1
调用发送接口后将状态 huart->gState 复位。但是发送数据太长时,数据可能还未传输完成,可能会导致状态不一致。如果HAL_UART_Transmit_DMA调用的频率过快,可能出现冲突,数据错乱。
解决办法2
发送后在发送中断回调函数中复位状态。
新问题,回调函数无法执行,DMA正常模式下,未调用会点函数:
此时需要更改UART_DMATransmitCplt函数或者更改成循环模式。
c
static void UART_DMATransmitCplt(DMA_HandleTypeDef *hdma)
{
UART_HandleTypeDef *huart = (UART_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
/* DMA Normal mode*/
if ((hdma->Instance->CCR & DMA_CCR_CIRC) == 0U)
{
huart->TxXferCount = 0x00U;
/* Disable the DMA transfer for transmit request by setting the DMAT bit
in the UART CR3 register */
ATOMIC_CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAT);
/* Enable the UART Transmit Complete Interrupt */
ATOMIC_SET_BIT(huart->Instance->CR1, USART_CR1_TCIE);
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/*Call registered Tx complete callback*/
huart->TxCpltCallback(huart);
#else
/*Call legacy weak Tx complete callback*/
HAL_UART_TxCpltCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
}
/* DMA Circular mode */
else
{
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/*Call registered Tx complete callback*/
huart->TxCpltCallback(huart);
#else
/*Call legacy weak Tx complete callback*/
HAL_UART_TxCpltCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
}
}
参考STM32F4
总结
STM32CUBE给开发提供了很多便利,但是HAL库还是有不少坑在里面,需要我们理解库函数的机制,遇到BUG后去调试优化。