插拔232通信线导致串口接收停止(使用DMA)

问题背景

本次问题属于异常情况的处理问题,问题现象是当用户插拔传感器的232端子(类似于耳机口)时会导致重新插回端子后板子无法继续正常收到数据,需要重启我们的软件才能解决该问题,此次问题是改用DMA方式接收之后出现的问题。

问题分析

由于本次问题也属于典型的通信问题,因此,我们使用数据流分析方法对该问题进行分析如下:
1.传感器应答数据异常;
2.是否有响应接收;
3.是否正常启动DMA;
4.重新初始化串口;

通过XCOM进行抓包,不断插拔232口,没插拔几次问题就出现了,然后重新插回232之后,通过抓取的报文发现传感器是有回复的,并且内容也是正确的。

由于问题比较容易复现,所以我们先分析出现问题后再次插回232时的情况,通过调试发现程序能够正常进入空闲中断,并且就抓取报文来看,总线数据是没有问题的。
虽然程序有进入空闲中断,但是我们获取的DMA数据长度始终为最大值,也就是没有接收到数据。
于是我们先进入调试,然后再次进入调试,同时观察出现问题时抓取的报文,出现问题时总线的确有数据,只是内容有问题。
并且,一旦出现该现象之后,即使总线通信恢复正常,接收也无法恢复,DMA始终无法恢复正常接收,那就是说DMA不再能够响应总线的数据接收了。

但是即使存在总线异常,我们也会在最长1s之后重启DMA(Stop+Start Recv),但是就结果来看DMA好像并没有正常重启,于是我们通过调试确认是否正常重启。
出现问题之后,我们进入调试发现Stop接口返回HAL_OK,但是单步调试发现程序并没有进入重启逻辑,也就是Rx启动失败。

也就是说执行重启时DMA Rx实际上已经停止了,导致这里无法执行停止逻辑,然而此时huart->RxState的状态依旧为HAL_UART_STATE_BUSY_RX,然而我们重新启动DMA Rx的HAL_UART_Receive_DMA接口又需要huart->RxState的状态必须为HAL_UART_STATE_READY,而该状态又必须要执行UART_EndRxTransfer函数将该状态置为HAL_UART_STATE_READY,但是前面已经提到:由于DMAR寄存器已经被清除,所有无法执行到停止逻辑,也就无法将Rx状态置为HAL_UART_STATE_READY,这也就导致了我们DMA Rx重启失败,也就导致了本次的问题。
那么又是哪里将Rx的DMAR寄存器清除了呢?于是我们全局搜索清除接口:
CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR),再结合我们在线调试发现是在串口中断处理函数(HAL库的接口HAL_UART_IRQHandler)中,出现问题时会进入异常处理逻辑,也就是执行完之后DMA便无法重启,并且也是在这个里面清除的DMAR。

在这个函数里面会调用HAL_DMA_Abort_IT函数将hdma->State置为异常状态HAL_DMA_STATE_ABORT,这又导致DMA无法重新启动(因为用于DMA重新启动的HAL_DMA_Start_IT里面需要hdma->State为HAL_DMA_STATE_READY)。

问题总结

综上分析,HAL的中断异常处理中会清除DMAR导致DMA停止接口不能执行停止逻辑,以及内部调用的终止接口将状态置为异常状态,以及没有将Rx状态清除,导致重启也无法执行。
在HAL库中没有那个接口能够逃过这个状态锁,因此,我们仅能执行重新初始化,将整个串口初始化,才能将这些锁置位。

经过重新初始化的尝试,DMA总线重启成功,数据接收也恢复正常。

HAL库中串口中断处理函数中的异常已处理逻辑

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值