STM32F0 DMA“输入溢出”

Posted

技术标签:

【中文标题】STM32F0 DMA“输入溢出”【英文标题】:STM32F0 DMA "input overflow" 【发布时间】:2017-05-28 21:12:02 【问题描述】:

STM32F0 DMA 从 UART 接收数据时遇到问题。我在非循环模式下都使用了 2 个 DMA 通道(用于 rx 和 tx),rx 通道的优先级较低。来自 UART 的数据在空闲线中断中处理,我在其中读取 DMA 接收到的字节数并处理它们。一切正常,直到包中的字节数小于或等于 DMA 缓冲区大小。否则 DMA 会奇怪地关闭,随后的空闲线中断会给我 1、0、0、... DMA 接收字节数。这是代码的一部分,我在其中检查 DMA 缓冲区是否已满,并尝试将 DMA 计数器重置为缓冲区大小:

#define S_M_INPUT_CMD_SIZE 20
static char s_m_uart_dma_in_buff[S_M_INPUT_CMD_SIZE + 1]; 

void USART1_IRQHandler(void)

   ITStatus reception_status = USART_GetITStatus(USART1, USART_IT_IDLE);
   if(reception_status != RESET)
   
      int32_t bytes_number = S_M_INPUT_CMD_SIZE - DMA_GetCurrDataCounter(DMA1_Channel3);            
      if (DMA_GetFlagStatus(DMA1_FLAG_TC3) != RESET)
      
         USART_ITConfig(UART_, USART_IT_IDLE, DISABLE);
         DMA_Cmd(DMA1_Channel3, DISABLE);
         while (DMA1_Channel3->CCR & DMA_CCR_EN);
         for (int i = 0; i < S_M_INPUT_CMD_SIZE; i++)
            s_m_uart_dma_in_buff[i] = '\0'; 
         DMA_SetCurrDataCounter(DMA1_Channel3, S_M_INPUT_CMD_SIZE); 
         DMA_Cmd(DMA1_Channel3, ENABLE); 
         DMA_ClearFlag(DMA1_FLAG_GL3);
      
      USART_ClearITPendingBit(UART_, USART_IT_IDLE);
    

在第一次“溢出”和 DMA 启用之后,出现 rx 寄存器中的“缓冲区大小 + 1”字节,随后接收到的字节数稳定为零。我做错了什么?

【问题讨论】:

【参考方案1】:

如果您尝试使用您的代码接收大小大于 S_M_INPUT_CMD_SIZE 的数据包会发生什么情况:

    DMA 完成接收块 S_M_INPUT_CMD_SIZE 并禁用(非循环模式) USART1 接收一个字节 USART1 从数据包中再接收一个字节并丢弃它们,因为没有人处理 UART 数据包完成,你得到空闲中断并重新初始化 DMA DMA 读取先前接收到的字节 不再有数据包 - 您将获得 0、0、... DMA 接收字节数

我不得不说,这种处理 DMA 传输的方式真的很奇怪。 DMA 传输通常必须在 DMA 中断处理程序中处理,而不是外围设备。

为了处理长数据包,您必须实现 DMA 中断处理程序。因此可以在 IDLE 中断之前重新初始化 DMA 接收。因此 DMA 将准备好从 UART 接收更多数据。

还有一件事。在你的代码中有一场比赛。在您阅读 bytes_number 和禁用 DMA 之间,一个或多个字节可以通过 DMA 传输。

但处理 UART 更正确的方法是在循环模式下运行 DMA 并且不要重新初始化它。因为每次禁用 DMA 时,您都会错过一些 UART 输入。

【讨论】:

感谢您的回复@alexander。也许我不明白你,但是接收到的字节数“0, 0, ...”是对新空闲中断中的后续包的反应,似乎 DMA 只是厌倦了工作。我同意这种方式很奇怪,但这是我想出的以最低 cpu 成本接收可变长度包的唯一方式。感谢比赛,我会解决的。 @Yuriy,所以在长包后你发送另一个包?你得到0 到以下数据包?你如何检查字节数?希望您不要在 ISR 中停止使用 JTAG 的程序,因为 JTAG 可能会破坏真实画面。使用全局变量记录事件。也有可能 UART 和 DMA 彼此不同步(因此您必须重置 UART 或 DMA)。也有可能 UART 设置溢出标志并停止接收直到清除它。 字节数为零的检查正在跳过 if(bytes_number > 0)。我尝试重新连接 USART 和 DMA,并尝试禁用/启用 DMA RCC。我会尝试完全重新初始化,但看起来不太好。 解决方案很简单。将 rx 通道 DMA 设置为循环模式解决了该问题。现在每个太长的包都被 DMA 传输完成标志捕获,并且所有后来的包都得到了很好的处理。再次感谢@alexander。尤其是比赛,它解决了我的另一个问题)

以上是关于STM32F0 DMA“输入溢出”的主要内容,如果未能解决你的问题,请参考以下文章

65 STM32F0系列 串口DMA循环接收实验记录

65 STM32F0系列 串口DMA循环接收实验记录

65 STM32F0系列 串口DMA循环接收实验记录

笔记之STM32F0芯片SPI_DMA的使用(HAL库)

笔记之STM32F0芯片SPI_DMA的使用(HAL库)

笔记之STM32F0芯片SPI_DMA的使用(HAL库)