搜索
查看: 19513|回复: 12

[已解决] 关于HAL UART 发送接收死锁问题

[复制链接]

该用户从未签到

8

主题

89

帖子

0

蝴蝶豆

中级会员

最后登录
2019-4-30
发表于 2017-4-10 11:02:36 | 显示全部楼层 |阅读模式
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.


    现象:
    串口发送(没用中断发送),---->有接收,又触发发送,导致死锁
回复

使用道具 举报

该用户从未签到

3

主题

20

帖子

3

蝴蝶豆

中级会员

最后登录
2020-5-30
发表于 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加锁语句也能正常工作。
回复 支持 2 反对 0

使用道具 举报

该用户从未签到

47

主题

1683

帖子

7

蝴蝶豆

论坛元老

最后登录
2022-4-9
发表于 2017-4-10 12:12:37 | 显示全部楼层
你这不是CUBE导致的“死锁”,而是RTOS线程之间没有同步好导致的。
不能靠应用级别的标识来判断线程之间的同步和运行,而是要靠RTOS自身的信号量、事件等等来判断和同步线程。
你可以不用RTOS测试下,先保证应用可用,再调RTOS吧。
回复 支持 反对

使用道具 举报

该用户从未签到

8

主题

89

帖子

0

蝴蝶豆

中级会员

最后登录
2019-4-30
 楼主| 发表于 2017-4-10 12:23:35 | 显示全部楼层
moyanming2013 发表于 2017-4-10 12:12
你这不是CUBE导致的“死锁”,而是RTOS线程之间没有同步好导致的。
不能靠应用级别的标识来判断线程之间的 ...

感谢回复,!~~~~
当前UART中断确实不是RTOS的,但是相对于来说比RTOS的中断级别要优先吧?
从当前的现在来看就是进入串口中断后,还是触发了串口发送,这个可能是RTOS引起的,因为这个中断接收串口里面没有LOCK,导致可以串口继续发送
回复 支持 反对

使用道具 举报

该用户从未签到

133

主题

4688

帖子

239

蝴蝶豆

版主

最后登录
2021-4-10
发表于 2017-4-10 13:16:27 | 显示全部楼层
这里可能是串口溢出导致的,当发生这样的问题时,判断huart->State ,重新执行串口初始化能解决。
回复 支持 反对

使用道具 举报

该用户从未签到

8

主题

89

帖子

0

蝴蝶豆

中级会员

最后登录
2019-4-30
 楼主| 发表于 2017-4-10 13:38:42 | 显示全部楼层
安 发表于 2017-4-10 13:16
这里可能是串口溢出导致的,当发生这样的问题时,判断huart->State ,重新执行串口初始化能解决。 ...

谢谢版主!~~
应该不是溢出,因为每次我只接收一个字节!~~
重新初始化确实可以!~~
回复 支持 反对

使用道具 举报

该用户从未签到

8

主题

89

帖子

0

蝴蝶豆

中级会员

最后登录
2019-4-30
 楼主| 发表于 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);
                }
        }
}
回复 支持 反对

使用道具 举报

该用户从未签到

133

主题

4688

帖子

239

蝴蝶豆

版主

最后登录
2021-4-10
发表于 2017-4-10 14:49:39 | 显示全部楼层
楼主应该加上溢出的处理,当发生忙状态时,串口寄存器的值是多少,就知道是哪些错误导致的了。
回复 支持 反对

使用道具 举报

该用户从未签到

47

主题

1683

帖子

7

蝴蝶豆

论坛元老

最后登录
2022-4-9
发表于 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()类型的开启中断函数。
回复 支持 反对

使用道具 举报

该用户从未签到

8

主题

89

帖子

0

蝴蝶豆

中级会员

最后登录
2019-4-30
 楼主| 发表于 2017-4-10 20:21:59 | 显示全部楼层
moyanming2013 发表于 2017-4-10 15:28
你的程序逻辑有严重的潜在问题!
HAL_UART_RxCpltCallback()函数是在中断里被调用的,而你又在该函数里面 ...

这个发送是调试串口,只是为了测试使用。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /3 下一条

Archiver|手机版|小黑屋|论坛-意法半导体STM32/STM8技术社区

GMT+8, 2024-5-4 02:16 , Processed in 0.183324 second(s), 43 queries .

Powered by Discuz! X3.4

Copyright © 2001-2024, Tencent Cloud.

快速回复 返回顶部 返回列表