【问题标题】:STM32F0 DMA "input overflow"STM32F0 DMA“输入溢出”
【发布时间】: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”字节,随后接收到的字节数稳定为零。我做错了什么?

【问题讨论】:

    标签: stm32 dma usart stm32f0


    【解决方案1】:

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

    1. DMA 完成接收块 S_M_INPUT_CMD_SIZE 并禁用(非循环模式)
    2. USART1 接收一个字节
    3. USART1 从数据包中再接收一个字节并丢弃它们,因为没有人处理 UART
    4. 数据包完成,你得到空闲中断并重新初始化 DMA
    5. DMA 读取先前接收到的字节
    6. 不再有数据包 - 您将获得 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。尤其是比赛,它解决了我的另一个问题)
    猜你喜欢
    • 2017-08-26
    • 2022-11-10
    • 2022-12-06
    • 2012-05-30
    • 2013-01-17
    • 2015-03-26
    • 1970-01-01
    • 2017-12-30
    • 2015-07-26
    相关资源
    最近更新 更多