你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

关于HAL UART 发送接收死锁问题

[复制链接]
benlarden 提问时间:2017-4-10 11:02 /
STM32F105S使用中断接收,触发UART_Receive_IT()中的   ......

   if(--huart->RxXferCount == 0)
    {
      __HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);

      /* Check if a transmit process is ongoing or not */
      if(huart->State == HAL_UART_STATE_BUSY_TX_RX)
      {
        huart->State = HAL_UART_STATE_BUSY_TX;
      }
      else
      {
        /* Disable the UART Parity Error Interrupt */
        __HAL_UART_DISABLE_IT(huart, UART_IT_PE);

        /* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */
        __HAL_UART_DISABLE_IT(huart, UART_IT_ERR);

       huart->State = HAL_UART_STATE_READY;
      }
      HAL_UART_RxCpltCallback(huart);


      ......

     进入HAL_UART_RxCpltCallback(huart);后,判断huart->State 尽然不是上面的2个中的一个,然后返回HAL_BUSY状态,导致死锁


    请问哪位遇到过这种情况吗?请指点下,系统使用了FREERTOS.


    现象:
    串口发送(没用中断发送),---->有接收,又触发发送,导致死锁
收藏 4 评论12 发布时间:2017-4-10 11:02

举报

12个回答
giveup 回答时间:2018-6-24 11:00:56
尽管是老帖子了,有些想法,希望对其他人有帮助。
最近调试stm32f407vet6+freeRTOS+uart3/uart6的小程序。uart3/uart6都使用HAL_UART_Transmit_IT函数发送,uart3使用HAL_UART_Receive_IT接收,uart6只发送。上位机每40ms查询uart3,uart3反馈结果。
当然,在调试中肯定遇到了上面说的uart3不能接收的问题。设置了错误中断处理,仍然出现uart3随机性失去响应。调试中发现问题不是上面的原因,而是出现在hal库中HAL_UART_Receive_IT/HAL_UART_Transmit_IT函数处理上,具体讲, __HAL_LOCK(huart)处理不当。

上述两个函数存在于Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_uart.c中,大约786~863行。HAL库版本是:STM32Cube_FW_F4_V1.21.0。
发送函数和接收函数中,都出现了 __HAL_LOCK(huart)操作。这实现了对端口的全局加锁。然而,此处却是欠考虑:huart是全双工的,如果APP调用HAL_UART_Transmit_IT在tx操作中执行了 __HAL_LOCK(huart)操作,还没有执行 __HAL_UNLOCK(huart)时发生了rx接收中断,在HAL_UART_RxCpltCallback调用中重新设定HAL_UART_Receive_IT就会出现HAL_BUSY错误。而实际上,这种状态下,硬件都是正常,完全能工作的。观察两个函数中 __HAL_LOCK(huart)和 __HAL_UNLOCK(huart)之间保护的全局变量,只有一个 huart->ErrorCode = HAL_UART_ERROR_NONE是存在冲突的。然而,在错误处理回调函数中,这个错误码一般都检测不到。换句话说,这个加锁操作锁的范围比较大,造成了 Tx和Rx操作的冲突。
当然,如果在启动Rx设定时发生Tx中断,也会因相同原因发生Tx启动失败。
总结一句话,出现HAL_BUSY错误的原因之一是两个函数中加锁操作造成的。
解决的办法:检查HAL_UART_RxCpltCallback调用中重新设定HAL_UART_Receive_IT的返回值,若出现HAL_BUSY错误,进一步检查huart->RxState是否忙,决定是否重新调用启动接收。
当然,不推荐的做法是简单注释掉HAL库中HAL_UART_Receive_IT加锁语句也能正常工作。
moyanming2013 回答时间:2017-4-10 12:12:37
你这不是CUBE导致的“死锁”,而是RTOS线程之间没有同步好导致的。
不能靠应用级别的标识来判断线程之间的同步和运行,而是要靠RTOS自身的信号量、事件等等来判断和同步线程。
你可以不用RTOS测试下,先保证应用可用,再调RTOS吧。
benlarden 回答时间:2017-4-10 12:23:35
moyanming2013 发表于 2017-4-10 12:12
你这不是CUBE导致的“死锁”,而是RTOS线程之间没有同步好导致的。
不能靠应用级别的标识来判断线程之间的 ...

感谢回复,!~~~~
当前UART中断确实不是RTOS的,但是相对于来说比RTOS的中断级别要优先吧?
从当前的现在来看就是进入串口中断后,还是触发了串口发送,这个可能是RTOS引起的,因为这个中断接收串口里面没有LOCK,导致可以串口继续发送
废鱼 回答时间:2017-4-10 13:16:27
这里可能是串口溢出导致的,当发生这样的问题时,判断huart->State ,重新执行串口初始化能解决。
benlarden 回答时间:2017-4-10 13:38:42
安 发表于 2017-4-10 13:16
这里可能是串口溢出导致的,当发生这样的问题时,判断huart->State ,重新执行串口初始化能解决。 ...

谢谢版主!~~
应该不是溢出,因为每次我只接收一个字节!~~
重新初始化确实可以!~~
benlarden 回答时间:2017-4-10 13:46:33
本帖最后由 benlarden 于 2017-4-10 14:02 编辑

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  /* NOTE: This function should not be modified, when the callback is needed,
           the HAL_UART_RxCpltCallback can be implemented in the user file
   */
        
        if(huart->Instance == USART3){
                ......//recv process

                cRxBuffPtr[0] = 0;
                if(HAL_UART_Receive_IT(huart,cRxBuffPtr[0],1) != HAL_OK){
                        HAL_UART_Transmit(&huart5, (uint8_t *)"uart3 err\r\n", 11, 0xff);
                }
        }
}
废鱼 回答时间:2017-4-10 14:49:39
楼主应该加上溢出的处理,当发生忙状态时,串口寄存器的值是多少,就知道是哪些错误导致的了。
moyanming2013 回答时间:2017-4-10 15:28:21
benlarden 发表于 2017-4-10 13:46
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  /* NOTE: This function should not be mod ...

你的程序逻辑有严重的潜在问题!
HAL_UART_RxCpltCallback()函数是在中断里被调用的,而你又在该函数里面调用了发送函数:
HAL_UART_Transmit()。
你看代码,HAL_UART_Transmit()会判断uart的状态,此时返回了HAL_BUSY。
另外即使不是由上述原因产生的,也没有这么用的。收发尽量一直(要么中断,要么阻塞式)。
再者,HAL_UART_RxCpltCallback()里面只能用HAL_UART_Receive_IT()类型的开启中断函数。
benlarden 回答时间:2017-4-10 20:21:59
moyanming2013 发表于 2017-4-10 15:28
你的程序逻辑有严重的潜在问题!
HAL_UART_RxCpltCallback()函数是在中断里被调用的,而你又在该函数里面 ...

这个发送是调试串口,只是为了测试使用。
rgw5267 回答时间:2018-8-9 17:33:48
moyanming2013 发表于 2017-4-10 15:28
你的程序逻辑有严重的潜在问题!
HAL_UART_RxCpltCallback()函数是在中断里被调用的,而你又在该函数里面 ...

HAL_UART_RxCpltCallback里面也不能用HAL_UART_Receive_IT, 会把ErrorCode覆盖掉, HAL_UART_Receive_IT只是开启中断函数, 可以在对应的IRQHandler最后执行.
lockyer 回答时间:2019-5-3 01:38:47
本帖最后由 wuxiaoluo 于 2019-5-3 10:03 编辑

遇到问题一摸一样,只是用了CUBEMX简单生成代码,中断接收,什么也没做,然后主循环发送固定字符,pc发送数据一百几十个就无法接收了。不会再中断接收了。如果循环判断再次中断接收是否成功,那么会导致发送也锁死了。
guohuimao 回答时间:2019-5-25 19:38:11
  使用HAL库来开发UART全双工通信的方案,这是在给自己挖墓呀.....两个方案死在串口上面了,不知查过多少网页,给ST的技术人员写过多少邮件打过多少电话了.....

所属标签

相似问题

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版