STM32 TTL串口通讯异常问题排查记录
1.问题描述
因之前使用的一款USR型号设备已停产,只能更换另一款USR型号设备;而在USR型号设备更换后进行兼容性验证时,当整机上电后再通过USR设备的复位脚对其进行复位后,会出现STM32芯片不应答USR设备发送的串口数据现象;若整机上电后不对USR设备进行复位,则两者之间一直可进行正常通讯交互。但之前的USR型号因种种原因,整机上电后必须再对其进行一次复位才可正常工作,所以为了能向前兼容,此处的复位逻辑不可更改,便得排查当整机上电后再通过USR设备的复位脚对其进行复位后,两者之间无法正常通讯交互的问题。
2.背景阐述
2.1开发环境
芯片型号:STM32F767IGT6,如图1所示。

图1 主芯片型号
开发环境:STM32CubeMX、STM32CubeIDE,版本如图2、图3所示。

图2 STM32CubeMX版本信息

图3 STM32CubeIDE版本信息
2.2数据接收
这里想分享一个对串口数据接收处理的看法。
因为串口通讯是开发过程中常用的通讯方式,所以硬件平台之间的可移值性是值得着重考虑的点。而此项目中串口数据接收处理与网上的一个观点不谋而合,此处借用很久之前在微信一篇公众号文章下看到并保存的一个评论(暂时已无法找到具体的出处,还望写此评论的本人见谅未注明有效出处,同时本人看到后可随时联系进行修改或注明)。串口数据通常按流数据类型处理,一般都会要求有一定的数据格式(定长或带协议),没有格式的数据不存在收不收全的说法。因此建议对于带格式的数据,尽量不以数据帧为单位接收,而应采用“解析器”来处理,这样可以屏蔽掉底层数据获取方式,即底层不管采用中断、还是查询,只负责取数据,只要来数据,就把数据喂给解析器即可,解析器完成一个完整的数据解析后可通过回调,通知上层并提供完整数据。这样做的好处是接收不用管数据是否收完,解析器自然会将所有接收的数据接合,且不会丢帧(因为是流处理)。而解析器是与硬件无关的,纯协议相关的,所以具有绝对的可移值性。
此项目中串口数据接收使用了接收DMA功能,通过定时轮询接收DMA缓冲区是否有数据,若有数据则取出数据,同时设置了每次最多取一定长度的数据,再将数据给解析器进行处理。
3.问题分析
因当前的程序版本实际已在多款设备中使用,并均可一直正常与之前型号的USR设备进行串口通讯交互,所以初步怀疑是对该型号USR设备的复位脚进行复位后,实际USR设备未复位成功,从而导致实际未发送数据给STM32主芯片。通过示波器来验证这一想法时,却在USR设备的TXD脚位上有采集到且是正确的数据波形,那么实际现象表明问题是出在STM32主芯片上了,数据实际发送到STM32主芯片了,但程序没有对数据进行接收处理。
这就奇怪了,如果STM32主芯片程序有问题的话,那为什么之前从来没有这样的现象出现过了?此时就只能先上JLinker仿真看下了,谁知在仿真模式下,这一问题竟又不复现了,一直都可以正常进行通讯交互了。花了一晚上的时间来进行各种可能性排查,始终没有定位到问题原因,虽然脑中一直想着如何定位问题但也不得不先去休息了。然后在休息的时间段突然想明白了,已经确认了数据接收处理逻辑是没有问题了,而用JLinker进行仿真的作用除了验证程序的实际运行流程是否符合设计外,还可以直接查看各种寄存器的值,既然仿真无法复现问题,那也可以直接实际运行,然后通过相应的外设将需要查看的寄存器内容打印出来不就行了。这样问题就能复现了,然后也可以实时查看问题出现时的现场状态了,满足这两个条件,那么什么问题就都好查了。
最终发现,只要问题出现,串口寄存器USARTx_ISR中的FE位就会被置1,FE具体描述如图4所示,

图4 串口寄存器ISR-位1 FE
同时由于串口寄存器USARTx_CR3中的DDRE位配置为1,DDRE具体描述如图5所示,

图5 串口寄存器CR3-位13 DDRE
所以导致虽然串口接收数据寄存器USARTx_RDR一直有收到数据,但接收DMA已禁止工作即不会搬运数据到接收缓冲区。至于为什么STM32主芯片会检测到FE帧错误,用示波器往前级查,才发现当前型号的USR设备在上电或复位后会主动往外发送错误格式的数据(至于整机上电时即USR设备和STM32主芯片同时启动时没有问题,应该是时序问题,USR设备上电后主动往外发送错误格式的数据时STM32主芯片的串口外设功能还未启动),而之前型号的USR设备不存在这种现象。
同时后续也找到了在仿真模式下,这一问题又不复现了的原因。是因为串口寄存器USARTx_CR3中的DDRE置为1是在引导程序中配置的,而 使用STM32CubeIDE进行仿真时,仿真起始运行地址就是当前工程配置的起始地址即在此处是应用程序的起始地址 ,故USARTx_CR3中的DDRE位的当前值为0,所以即使接收出错,接收DMA仍正常工作,继续搬运数据到接收缓冲区。若如图所示 使用Keil uVision5进行仿真时,仿真起始运行地址是当前STM32主芯片的起始地址即在此处是引导程序的起始地址 ,所以USARTx_CR3中的DDRE位的当前值为1,实际测试验证在使用Keil uVision5进行仿真时,这一问题确实也能够复现。

图6 Keil uVision版本信息
4.解决方案
这个问题虽说是USR设备引起的,但同时也反应出了STM32主芯片在串口通讯接收处理这块程序的一个隐患——没有通讯出错的安全恢复机制。最后如图7、8所示,通过使能串口错误中断,触发中断后再对相应的错误标志位进行清零操作。当然针对这一问题,取消在引导程序中配置串口寄存器USARTx_CR3中的DDRE为1的操作,也是可以解决的。

图7 串口寄存器CR3-位0 EIE

图8 串口寄存器ICR-消除错误标志
5.验证结果
将增加了解决方案处理的程序烧录旧版硬件和新版硬件后,STM32主芯片与USR设备均可一直正常进行串口通讯交互。
6.问题总结
经过此次问题排查过程,给我最大的感受是:
1.之前没有问题,而现在突然有问题了,那么至少问题的表层原因是在变化的那部分,如这次便是USR型号不同,对上电或复位后的自身初始化处理不同;
2.找到问题方的本质,才能一针见血地定位到问题原因,如这次STM32主芯片程序未对相应的串口数据进行接收解析处理,而控制STM32主芯片处理串口接收数据的本质便是串口相关的寄存器标志位。