【问题标题】:UART receive interrupt stops triggering after several hours of successful receiveUART 接收中断在成功接收数小时后停止触发
【发布时间】:2015-09-18 08:30:16
【问题描述】:

我正在使用与 xbee 连接的 STM32f4 发现板来接收来自远程温度传感器的温度数据。使用的代码是 CMIS UART 示例代码。我将接收数据包数据,一次 1 个字节。换句话说,只要接收到每个字节,就会调用 UART 接收中断。一旦我得到完整的数据包,我将复制温度数据。我的 UART 回调函数可以正常工作。但是几个小时后,UART接收中断停止工作,UART无法接收任何东西。但是 UART 传输仍然有效。我正在使用波特率为 115200 的 UART1。我已将 UART 中断优先级设置为 0,并且没有其他中断共享此优先级。所有其他中断优先级均低于 UART。谁能告诉我为什么UART中断停止触发?

#define PACKET_DELIMETER 0x7E

uint8_t g_frame_ok=0; //flag to indicate complete packet received
uint8_t g_index_of_aoBuf=0; //Index of receive buffer
uint8_t g_aoBuf_of_xbee[100]={0};//Receive Buffer
uint8_t r_byte=0; //Receiving byte 

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *allUartHandle)
{
 __HAL_UART_FLUSH_DRREGISTER(allUartHandle); 

 if(HAL_UART_Receive_IT(allUartHandle, (uint8_t *)&r_byte, 1) == HAL_OK) //Interrupt occurs when each byte arrives
 {
    if(r_byte==PACKET_DELIMETER)
    {
        //start receiving packet
    }
    if( g_index_of_aoBuf>=g_aoBuf_of_xbee[2]+4)
    {
        g_frame_ok=1;
        BSP_LED_On(LED4);
    }           
   }
 }

【问题讨论】:

  • 如果我理解正确,您的代码是从 CMSIS UART 示例派生的?你能附上这个例子的链接吗?我从来没有使用过这些 API,但看起来你真的做错了……
  • 我已经从这个链接下载了示例代码。 st.com/web/en/catalog/tools/PF259243。示例代码接收中断回调函数与我的代码不同。在示例代码中,将针对特定数量的缓冲区大小调用接收中断。但是在我的代码中,每个字节都会调用接收中断。你能告诉我我在这里做错了什么吗?
  • 如果 UART 外设与 stm32f0 系列上的相同/相似,您确实需要检查溢出和帧错误并适当地“清除”条件。否则,一个位错误可能会锁定外围设备,直到您重新启动。 ST 的免费软件和示例几乎从不为强大的生产代码提供足够的错误处理。
  • 你找到这个问题的解决方案了吗?就我而言,它仅在 10 - 15 分钟后停止!

标签: c embedded stm32f4discovery cmsis


【解决方案1】:

我从未使用过您提到的 API,所以我可能是错的,但以下是我在查看后注意到的一些事情:

HAL_UART_RxCpltCallback 不是 UART 中断。它是来自 HAL 子系统的回调,当您发出的接收请求完成时将调用该回调。这意味着它只会在您发出接收请求后的一段时间内被调用。你无权访问 UART 中断,如果你使用 HAL 层,你不应该尝试弄乱它。

关于这个,HAL_UART_Receive_IT 实际上是一个会发出接收请求的函数。它总是会立即返回,并且永远不会收到任何东西。这意味着调用后接收缓冲区中的数据无效。一旦你发出请求,HAL_UART_RxCpltCallback 将在接收完成后随时调用。只有此时缓冲区中的数据才有效。要检索数据,您可以使用来自HAL_UART_Receive_IT 的相同变量,但也可以通过回调参数中的(UART_HandleTypeDef*)->pRxBuffPtr 获得数据缓冲区。

我认为在回调中再次调用HAL_UART_Receive_IT 是可以的,但最好还是在最后调用。

另外,__HAL_UART_FLUSH_DRREGISTER 是用来做什么的?对我来说,它看起来弊大于利。

【讨论】:

    【解决方案2】:

    在回调函数和程序其余部分之间共享的变量必须声明为 volatile,以防止编译器错误地优化代码。

    您还必须确保对此类变量的写入和读取是原子的,或者使用信号量保护它们。否则你可能会遇到竞争条件错误。

    这两个经典错误中的任何一个或两者都可能导致您描述的问题:两者都倾向于导致难以重现的间歇性、意外行为。

    此外,如果您的 CPU 允许,请设置一个断点,该断点在对中断启用寄存器的写访问时触发并检查跟踪。

    【讨论】:

    • 在CMSIS中,互斥量和信号量在ISR中不能完全使用,并且当你在uart中使用dma之类的中断时,你需要在中断服务程序中读取数据,比如HAL_UART_RxCpltCallback函数。在这种情况下最好的解决方案是什么?
    • @masoud 请将其作为一个新问题发布,而不是对旧帖子的评论。
    • 好的@Lundin 我在这里发布了我的问题:link
    猜你喜欢
    • 2019-02-21
    • 1970-01-01
    • 1970-01-01
    • 2017-09-26
    • 2013-03-05
    • 2021-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多