两个 USART 中断的溢出错误

Posted

技术标签:

【中文标题】两个 USART 中断的溢出错误【英文标题】:Overrun errors with two USART interrupts 【发布时间】:2014-05-29 12:28:53 【问题描述】:

在 STM32F2 上使用两个以 115200 波特运行的 USART,一个用于与无线电模块通信,另一个用于从 PC 进行串行通信。时钟速度为 120MHz。

当同时从两个 USART 接收数据时,一个 USART 或另一个可能会发生溢出错误。做一些快速的包络计算,应该有足够的时间来处理两者,因为中断只是简单地将字节复制到循环缓冲区。

在理论和测量中,将字节推送到缓冲区的中断代码应该/确实以 2-4µS 的顺序运行,在 115200 波特下,我们有大约 70us 来处理每个字符。

为什么我们偶尔会在一个或其他 USART 上看到 ORE?

更新 - 附加信息:

    此时我们的代码中没有其他 ISR 正在触发。 我们正在运行 Keil RTX,其 systick 中断配置为每 10 毫秒触发一次。 我们目前没有禁用任何中断。 根据这本书(Cortex-M 处理器系列的设计师指南),中断延迟大约为 12 个周期(不是很致命)

鉴于上述所有 70us 至少是我们清除中断所需时间的 10 倍 - 所以我不确定它是否容易解释。我是否应该得出结论,一定是我忽略了其他一些因素?

MDK-ARM 是 4.70 版

系统中断由 RTOS 使用,因此无法计时,其他 ISR 每个字节运行需要 2-3µS。

【问题讨论】:

你没有提供足够的信息让别人说出你为什么会被超支。明显的候选人:在其他地方禁用中断?更高优先级的中断处理程序太慢?你的代码中的错误?没有足够的信息来确定是哪个。 ISR 延迟在该芯片上非常致命,UART 没有 fifo 缓冲区。你的理论计算已经偏离了两倍。添加更高优先级的中断,其 ISR 花费太多时间,或者中断在您不知道的代码中被禁用,并且溢出变得很容易解释。 感谢 cmets 我在问题中添加了更多信息,我不确定我还能提供哪些其他信息。 什么版本的 RTX(或 ARM-MDK)? Cortex-M3 的早期版本存在错误并且不完全支持中断优先级分组。如果没有代码,这个问题可能无法回答。 我不会放弃一个无法解释的问题,因为症状可能会在以后出现在其他地方。尽管如此,对于我最近的几个项目,我总是使用 DMA 创建一个循环缓冲区,用于存储从 USART 接收到的数据。实际硬件(DMA 控制器)不会错过最后期限(除非它也超载,但除非您将它用于其他用途,否则 2 个 USART 以这种速度应该是小菜一碟)。 【参考方案1】:

几个月前,我在 Cortex M4 (SAM4S) 上遇到了与您类似的问题。我有一个基于定时器中断以 100 Hz 的频率调用的函数。

与此同时,我将 UART 配置为在接收字符时中断。 UART 上的预期数据是 64 字节长的数据包,并且每个字符的中断都会导致延迟,因此我的 100 Hz 更新功能以大约 20 Hz 的速度运行。在这个特定的 120 MHz 处理器上,100 Hz 相对较慢,但在每个字符上中断都会导致大量延迟。

我决定将 UART 配置为使用 PDC(外设 DMA 控制器),我的问题立即消失了。

DMA 允许 UART 将数据存储在内存中,而不会中断处理器,直到缓冲区已满,从而节省大量开销。

在我的例子中,我告诉 PDC 将 UART 数据存储到缓冲区(字节数组)中并指定长度。当 UART 通过 PDC 填充缓冲区时,PDC 发出中断。

在 PDC ISR 中:

    给 PDC 新的空缓冲区 重启 UART PDC(这样可以在我们在 isr 中做其他事情的同时收集数据) memcpy 将完整缓冲区放入 RINGBUFFER 退出 ISR

正如上述 swineone 建议的那样,实施 DMA,您就会热爱生活。

【讨论】:

【参考方案2】:

遇到了类似的问题。简短的解决方案 - 将过采样更改为 8 位,这使得 USART 时钟更加精确。并明智地选择您的 MCU 时钟!

huart1.Init.OverSampling = UART_OVERSAMPLING_8;

此外,添加 USART 错误处理程序和机制来检查您的数据是否有效,例如 CRC16。这是 STM32F0xx 系列的示例,我假设它在整个系列中应该非常相似。

void UART_flush(void) 
  // Flush UART RX buffer if RXNE is set
  if READ_BIT(huart1.Instance->ISR, USART_ISR_RXNE) 
    SET_BIT(huart1.Instance->RQR, UART_RXDATA_FLUSH_REQUEST);
  

  // Not available on F030xx devices!
  // SET_BIT(huart1.Instance->RQR, UART_TXDATA_FLUSH_REQUEST);

  // Clear All Errors (if needed)
  if (READ_BIT(huart1.Instance->ISR, USART_ISR_ORE | USART_ISR_FE | USART_ISR_NE)) 
    SET_BIT(huart1.Instance->ICR, USART_ICR_ORECF | USART_ICR_FECF | USART_ICR_NCF);
  


// USART Error Handler
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) 
  if(huart->Instance==USART1) 
    // See if we have any errors
    if (READ_BIT(huart1.Instance->ISR, USART_ISR_ORE | USART_ISR_FE | USART_ISR_NE | USART_ISR_RXNE)) 
        // Flush errors
        UART_flush();

        // Raise Error Handler
        _Error_Handler(__FILE__, __LINE__);
    
  

DMA 也可能有所帮助。我的问题与 USART 时钟容差有关,这甚至可能导致实现 DMA 时出现溢出错误。由于是 USART 硬件问题。无论如何,希望这可以帮助那里的人!干杯!

【讨论】:

【参考方案3】:

我最近有这个问题,所以我实现了一个尚未植入的UART_ErrorCallback函数(只是_weak版本)。 是这样的:

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)

     if(huart == &huart1)
     
         HAL_UART_DeInit(&huart1);
         MX_USART1_UART_Init(); //my initialization code
      ...

这解决了溢出问题。

【讨论】:

以上是关于两个 USART 中断的溢出错误的主要内容,如果未能解决你的问题,请参考以下文章

关于STM32串口接收中断,网上有如下中断方式接收数据的程序:

arm中断问题 很急! 很简单

使用 STM32L476RG 时出现 UART 溢出错误

stm32 串口 中断的问题

USART接收中断stm32

STM32的USART中断死循环,形成死机。