STM32 HAL库 串口收发崩溃原因 ( __HAL_LOCK)

一般工况是类似MODBUS主从通讯,上位机发下位机收,如果通信负载不大,极少出现发送数据时候出现接收中断,不过这种BUG经不起通讯测试。如:
测试用例:
测试冗余数据发送,使用自动测试脚本,在通信帧的校验码后字节添加1-8字节随机数,每种字节长度测试10000次。

以上测试初串口就会崩溃,只能发不能收,调试结果是,串口接收中断不再响应。
源码中使用HAL_UART_Receive_IT 中断接收数据,HAL_UART_Transmit非中断方式发送,两个函数内部均有这样的宏函数:

#define __HAL_LOCK(__HANDLE__)\ do{\ if((__HANDLE__)->Lock == HAL_LOCKED)\ {\ return HAL_BUSY; \ }\ else\ {\ (__HANDLE__)->Lock = HAL_LOCKED; \ }\ }while (0U)#define __HAL_UNLOCK(__HANDLE__)\ do{\ (__HANDLE__)->Lock = HAL_UNLOCKED; \ }while (0U)

原因在于进入接收中断后__HAL_LOCK(huart)发现UART资源已经被锁,随即返回HAL_BUSY,不再执行HAL_UART_Receive_IT中的打开接收中断代码,所以uart再无法接收数据。锁住该UART的是发送函数中的__HAL_LOCK(huart)。
此BUG多次在论坛提及,只是ST官方一直没有处理,着实坑过不少人……参见:
https://community.st.com/s/question/0D50X00009XkeOGSAZ/questions-surrounding-hallock
他们的临时处理方式是将库函数中发送功能代码拷贝到自己的函数中,去掉上锁解锁操作。

解决方式:
注释掉__HAL_LOCK、__HAL_UNLOCK即可。

话说为什么要加锁呢?看起来只是为了保护一些串口操作变量,不过乍一看唯一有冲突的是这个:
【huart->ErrorCode = HAL_UART_ERROR_NONE; 】
因为发送与接收操作变量是分开的,只有ErrorCode有可能被异常地修改,所以注释掉这种保护并不会影响正常使用。
【STM32 HAL库 串口收发崩溃原因 ( __HAL_LOCK)】同样的问题,可以参考这个:https://www.jianshu.com/p/6995fb60364f

最后,CAN, USB, UART等出现类似问题也不足为奇了。

    推荐阅读