UART 发送 DMA。传输完成后没有 UART_IRQ_Handler 调用(它在调试模式下工作)

Posted

技术标签:

【中文标题】UART 发送 DMA。传输完成后没有 UART_IRQ_Handler 调用(它在调试模式下工作)【英文标题】:UART Transmit DMA. no UART_IRQ_Handler call after transmit complete (it works in debug mode) 【发布时间】:2022-01-05 13:34:13 【问题描述】:

所以我试图通过 UART 使用 DMA 发送一些数据(所以使用 UART_Transmit_DMA() 函数)。 查看源代码,它为 dma 传输完成设置回调并调用HAL_DMA_Start_IT()。当传输完成时,DMA_IRQ_Handler 被调用并调用 HAL_DMA_IRQHandler() 它调用启用 TransferComplete 中断的回调。

此操作应启动UART_IRQ_Handler(),但这不会发生!即使 NVIC 设置正确。

我发现启动的唯一方法是调用__HAL_UART_ENABLE_IT(&huart, UART_IT_TC) before UART_Transmit_DMA()。但这还不够,使其工作的唯一方法是在__HAL_UART_CLEAR_FLAG(huart, UART_FLAG_TC)(stm32f4xx_hal_uart.c 内部)放置一个断点,这样首先执行中断例程(DMA 和 UART_IRQ_Handler)然后__HAL_UART_CLEAR_FLAG(huart, UART_FLAG_TC) 最后被执行。

这是正常的还是我做错了什么?

编辑: 好的,我发现了另一个想法,我现在更好地理解了这个问题。 从__HAL_UART_ENABLE_IT(&huart, UART_IT_TC)在我的情况下无用(我不需要启用寄存器中的ITC位)这一事实开始,总是存在同样的问题。

DMA 回调启用 ITC,但同时 TC 状态标志已被清除,因此不会触发中断。如果我在清除 TC 状态标志之前放置断点,则 ITC 由回调设置并且中断触发成功!

清除UART_Transmit_DMA()里面的这个标志是什么意思?

/* Enable the UART transmit DMA stream */
tmp = (uint32_t *)&pData;
HAL_DMA_Start_IT(huart->hdmatx, *(uint32_t *)tmp, (uint32_t)&huart->Instance->DR, Size);

/* Clear the TC flag in the SR register by writing 0 to it */
__HAL_UART_CLEAR_FLAG(huart, UART_FLAG_TC); //<<<!!!--- why this?

/* Process Unlocked */
__HAL_UNLOCK(huart);

【问题讨论】:

【参考方案1】:

让我们看一下HAL_UART_Transmit_DMA更完整的部分(还有一些代码,但只是关于变量初始化)

HAL_DMA_Start_IT(huart->hdmatx, *(uint32_t *)tmp, (uint32_t)&huart->Instance->DR, Size);

/* Clear the TC flag in the SR register by writing 0 to it */
__HAL_UART_CLEAR_FLAG(huart, UART_FLAG_TC);

/* Process Unlocked */
__HAL_UNLOCK(huart);

/* Enable the DMA transfer for transmit request by setting the DMAT bit
   in the UART CR3 register */
SET_BIT(huart->Instance->CR3, USART_CR3_DMAT);

HAL_DMA_Start_IT 仅配置 DMA 传输,此功能不涉及 UART。此时 DMA 已准备好处理来自 UART 的请求,但由于 UART_CR3 寄存器中的 DMAT 位尚未设置,因此没有发出任何请求,也没有数据传输。

__HAL_UART_CLEAR_FLAG(husart, USART_FLAG_TC); 只清除状态寄存器中的 TC 标志,它不妨碍进一步的中断生成(记住,此时 UART 没有发送任何内容),中断在 UART_CR1 寄存器中启用,并在所有数据都被触发时触发发送到线路。清除的原因很简单而且非常笼统——在启用中断之前,它的状态(标志,产生中断)应该被清除,否则它会立即触发。我不知道为什么他们在启用 TC 中断之前在此处清除而不是在回调中清除,但这看起来像是开发人员的决定。

SET_BIT(huart-&gt;Instance-&gt;CR3, USART_CR3_DMAT); 此行启用来自 UART 的 DMA 请求,并且只有在此调用之后才会开始传输。稍后可以生成 TC 中断。

在您的情况下,DMAT 可能位已在调用 HAL_UART_Transmit_DMA 之前设置。请提供与问题相关的所有代码 - 初始化和开始传输。没有它,只能进行猜测。

【讨论】:

以上是关于UART 发送 DMA。传输完成后没有 UART_IRQ_Handler 调用(它在调试模式下工作)的主要内容,如果未能解决你的问题,请参考以下文章

STM32F4 UART1 DMA发送和接收不定长度数据

基于RT-Thread的CAN电机驱动板设计 uart串口DMA的实现

STM32 ADC_DMA_UART 数据传输

Cortex-A9 UART

Cortex-A9 UART

RT1052 LPSPI1 dma传输和UART2 DMA传输实现不定长数据接收