问题描述
我们通过485和第三方设备进行通信时,是通过接收中断完成数据的接收,但是在实际测试过程中发现设备的应答内容会出现偶发的缺少一个字节。
后续经过问题的分析将串口的接收机制改为使用DMA方式接收数据,但是由于该设备会涉及到两个扫描指令,两个指令的应答内容是不同的,但是在实际测试中发现本属于第二个指令的应答内容会出现在第一个指令应答的位置。
问题分析
字节丢失分析
初次遇到此问题时怀疑是设备应答出现了异常,但是通过并联一个485监听发现出现字节丢失问题时报文内容时正常的。
那也就是说整个数据链路到H750都是正确的,问题也就是出在了750内部了,我们再结合数据接收的方式:通过接收中断逐个字节获取设备应答的数据。
于是将串口的溢出中断使能,在问题发生时的确伴随着溢出标志的置位,看来是中断不能及时处理数据。
对整个工程进行分析发现:
1.串口的中断优先级开到最大也会出现问题;
2.中断中的处理函数执行时间也已经最短;
3.系统中存在几处执行了总中断的关闭,屏蔽之后问题不再出现;
综上所述,我们可以得出本次的问题主要是由于外部关闭了总中断导致接收中断不能及时处理。
根据系统的定义,此处的总中断关闭接口是必须要执行,因此,我们仅能通过DMA的方式对数据进行接收。
数据不刷新
改用DMA接收方式之后,程序总算稳定运行了一段时间,也不再出现丢字节的问题了,但是运行了4小时左右之后,再次出现了异常应答,经过分析发现通道1所谓的异常应答是属于通道2的应答。
通过断点调试,出现问题时数据长度的确属于通道1的应答内容长度,但是内容却是通道2的应答(两个通道的应答长度是不同的)。
通过DMA数据传输长度正常,但是内容却貌似没有刷新,这是什么操作,此时结合以往的调试经验,立刻联想到了cache,于是先手动将D-cache关闭。
长运一段时间问题不再复现,但是系统对于性能还是有需求的,所以还是不能关闭cache,于是就在取DMA传输的RAM地址之前调用内核的SCB接口强制该段地址同步RAM的数据。
经过以上修改后,总算完美地解决了此次的问题。
问题总结
本次的问题主要原因如下:
1.外部频繁关闭总中断,导致串口接收中断无法及时收到数据,进而导致出现丢失字节的问题;
2.DMA方式会将串口接收的数据自动放到指定的RAM地址中,但是系统开启了D-cache,所以程序中访问的数据并不是实际的RAM中的数值,所以这种非一致性导致软件读取到的内容不是最新的;文章来源:https://www.uudwc.com/A/4rnVY/
本次遇到的是接收的问题,同样的分析思路,我们在执行数据发送时是否也会有发送的字节间隔并不是连续的(被关闭总中断影响),那么对方在接收时是否也会出现错误断帧的问题?此次偶发的无应答会不会就是这个原因(虽然抓包看都有发)?文章来源地址https://www.uudwc.com/A/4rnVY/