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

Cubemx hal 库 HAL_UART_Receive_IT 的死锁问题

[复制链接]
飞奔的皮卡丘 提问时间:2021-7-7 16:43 / 未解决
问题:
我在项目中最初用的是HAL_UART_Receive_IT,HAL_UART_Transmit。每次在接收到数据后会在回调函数里再次调用HAL_UART_Receive_IT。
当高频进行串口数据收发时,发现有概率不能正常接收数据。 问题发生后断电重启后,又恢复正常。


根据各种调查外加查资料,发现主要原因应是 __HAL_LOCK 的直接返回,导致HAL_UART_Receive_IT 失败后不能再开中断。

stm32f103 HAL 库的  串口中断方式接收数据的函数HAL_UART_Receive_IT、发送函数  HAL_UART_Transmit_IT、HAL_UART_Transmit 的内部实现都有   __HAL_LOCK(huart); 根据其实现,若调用时发现已经上锁,则会直接返回

HAL_BUSY。

1.有人建议说使用 HAL_UART_Transmit_IT代替HAL_UART_Transmit,但是我看内部实现都有 __HAL_LOCK(huart),这样一来只是会减小上述问题发生的概率,并未解决问题,因此并未采用。
2.我尝试在原本HAL_UART_Receive_IT的地方都追加了返回值判断,一旦返回  HAL_BUSY,就去主循环每10ms重新调用一次
HAL_UART_Receive_IT,直到返回正确。 但是经过长时间测试,又发生了问题,无法接续正常收发数据了。
3.我尝试在 HAL_UART_Receive_IT的实现里,把__HAL_LOCK(huart) 注释掉,跟2.的设备一起做长时间测试,做对比试验,目前暂未出现问题。  但网上的开发者说并不建议这样粗暴对策,我也暂不明确会有什么副作用,因此目前还在寻找更好的方法。

请问大佬们是否有什么建议? 感激不尽。




收藏 评论8 发布时间:2021-7-7 16:43

举报

8个回答
yklstudent 回答时间:2021-7-7 17:08:33
HAL库一般很少用,你还是要找找为啥一直返回HAL_BUSY的原因
废鱼 回答时间:2021-7-8 10:48:10
楼主,您好。因为数据处理不及时导致串口溢出后,发生该问题。通过重新初始化串口可以解决,可以考虑使用LL库。
butterflyspring 回答时间:2021-7-8 11:31:43
从描述上看,高频次发送数据时发生这个问题,多半是中断服务程序执行时间到了极致(仔细看中断内容,里面有些情况执行了一些东西,而且还有回调函数)。 为了保证 (huart) 参数一致,才需要LOCK保证操作的互斥性。 所以,如果有其他中断存在,那么需要保证串口为最高优先级。如果时间还不够,考虑使用LL库自己设计中断发送接收,以前没有HAL库大家也这么写。 或者考虑使用DMA方式,减少程序每个字节都处理。
飞奔的皮卡丘 回答时间:2021-7-8 11:41:01
yklstudent 发表于 2021-7-7 17:08
HAL库一般很少用,你还是要找找为啥一直返回HAL_BUSY的原因

应是HAL_UART_Transmit里Lock生效后,HAL_UART_Receive_IT拿不到锁,直接返回的HAL_BUSY
飞奔的皮卡丘 回答时间:2021-7-8 11:46:55
飞羽一条 发表于 2021-7-8 10:48
楼主,您好。因为数据处理不及时导致串口溢出后,发生该问题。通过重新初始化串口可以解决,可以考虑使用LL ...

之前在其他博客里也发现了对ORE的说明,建议在HAL_UART_ErrorCallback 里做清标志的动作。
尝试后发现问题还发生,然后才对HAL_UART_Receive_IT 下手的... 不过也还是没有完全弄清楚。
LL库还没有用过,听说是新出的,如果直接上LL估计有不少东西要重写吧...
飞奔的皮卡丘 回答时间:2021-7-8 12:00:43
butterflyspring 发表于 2021-7-8 11:31
从描述上看,高频次发送数据时发生这个问题,多半是中断服务程序执行时间到了极致(仔细看中断内容,里面有 ...

感谢分析讲解。  之前看了下uart 收发函数里LOCK的内容,他们之间有关系的可能就是huart->ErrorCode = HAL_UART_ERROR_NONE;  这个东西。  后面在中断处理时候会做为判断条件。
至于耗时问题,因为现在发送时用的是HAL_UART_Transmit,如果执行得慢,会阻塞LOCK,这个问题就比较容易发生了。 有考虑过把HAL_UART_Transmit 变更为HAL_UART_Transmit_IT,这样阻塞时间就会短得多。只会LOCK几个赋值
    /* Process Locked */
    __HAL_LOCK(huart);

    huart->pTxBuffPtr = pData;
    huart->TxXferSize = Size;
    huart->TxXferCount = Size;

    huart->ErrorCode = HAL_UART_ERROR_NONE;
    huart->gState = HAL_UART_STATE_BUSY_TX;

    /* Process Unlocked */
    __HAL_UNLOCK(huart);


但是毕竟理论上还是存在发生问题的可能性的,所以就没有改 HAL_UART_Transmit_IT,直接去动HAL_UART_Receive_IT 了= =  但是感觉太粗暴,不怎么合理,问题倒是还没有再现出来。。。
(以前跑几十次测试就能测出来,现在跑了五千多次了...)

至于中断的使用,目前除了UART,都是CubeMX配置外设后自动配好的,级别默认都是0,就没有去改:
Non maskable interrupttrue00
Hard fault interrupttrue00
Memory management faulttrue00
Prefetch fault, memory access faulttrue00
Undefined instruction or illegal statetrue00
System service call via SWI instructiontrue00
Debug monitortrue00
Pendable request for system servicetrue00
Time base: System tick timertrue00



请问DMA 方式可以避免当前这种问题的么?  还没有用过,需要学习一下。 如果可以,这貌似是比较合理的办法。
LL库的话到这个阶段貌似不太合适,因为其他代码也都是基于HAL库写的,这样可能要大改了。
watershade 回答时间:2021-7-9 10:39:03
我前段时间也遇到过串口接收不及时的问题。比方说我预计会接收到8个字节数,但是实际上我接受到了12个字节数据。就会出现ORE中断。需要我在HAL_UART_ErrorCallback 里面做个处理。你猜怎么着,这样还是解决不了问题。尽管没有出现你说的死锁问题。我的做法是开启使用DMA方式接收,但是开启idle中断。如果内存足够,可以试图让DMA接收的数据长度比预计的数据长度大很多。这样就可以接收任意数据长度的数据。我最终是靠这种方法实现的。


如果你有逻辑/总线分析仪甚至示波器,可以试着看一下出现问题的原因。不过你这个似乎是随机发生的,追查的难度还是很大的。
废鱼 回答时间:2021-7-13 13:59:27
楼主,我最早使用HAL库遇到类似的问题,我是直接修改的库,直接用环形队列,把他的中断处理函数给修改掉了。或者是中断开启后,不再关闭中断,继续读取数据,如果缓冲区满后,就把新的数据丢掉。

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