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->Instance->CR3, USART_CR3_DMAT);
此行启用来自 UART 的 DMA 请求,并且只有在此调用之后才会开始传输。稍后可以生成 TC 中断。
在您的情况下,DMAT
可能位已在调用 HAL_UART_Transmit_DMA
之前设置。请提供与问题相关的所有代码 - 初始化和开始传输。没有它,只能进行猜测。
【讨论】:
以上是关于UART 发送 DMA。传输完成后没有 UART_IRQ_Handler 调用(它在调试模式下工作)的主要内容,如果未能解决你的问题,请参考以下文章