实习总结——关于联调解决的因CRC校验导致协议交互失败的调试经验总结
1.场景还原:在我开发USB PD测试模块时,发现待测主板始终不回复Request消息,导致我的测试失败;此时我的任务就是快速定位这个协议交互失败的原因,无论是软件、硬件还是协同。
2.大致的调试步骤:
1.首先使用了逻辑分析仪抓取了CC线(这里是CC1)上面的物理波形,并在分析仪的软件上启用了BMC解码,确认了DUT确实发出了Request消息,并且波形解码出来的CRC值与我手动计算出来的值结果一致。
2.然后,我检查了Linux驱动层的调试日志,发现驱动收到的同一条消息的CRC值与波形完全不同。好了,此时有两种可能,一种就是在PL端和PS端进行数据通信的时候发生了问题,导致校验失败;另一种可能就是PL端出现了某些问题。
3.我排查了我的驱动读取FIFO的代码,发现一切正常,所以不是我软件的问题。那么只有一种可能,那就是FPGA的PL端出现了问题。
4.好了,我此时定位了是FPGA的硬件问题了。然后就是和硬件工程师排查一下是哪里出现了问题,Review了PL端IP核的Verilog代码,发现其CRC生成器的初始值配置错误。
3.解决方案:
1.在定位了是PL端的问题以后,先进行了自己的软件CRC 校验作为临时的方案,保证了项目的进度;
2.过了大概两天,提交了我们的硬件团队,协助他们修复了IP核,并验证了新的比特流文件,最终彻底解决了该问题。
4.总结一个这个令人自豪的调试过程以及DEBUG思路吧。
总的来说,发现问题要先利用工具来进行问题的定位,这里用到了逻辑分析仪和Linux 内核调试日志,日志会打印出关键的信息,但是这需要很大的耐心去分析波形,在分析的过程中,不仅仅是对波形的分析,还是对于USB PD协议的每一步结构进行深入透彻的了解,不能忽略每一个细节,要精确到每一个时刻,哈哈哈,有点废人说实话。此外,在日志查看的阶段,也是非常需要耐心的,每一个日志信息都有可能成为突破的关键点,所以能不能有人开发一个一键解决的软件啊,要不这样有点废牛马,哈哈哈哈。
5.下面是一些详细的,便于回顾的,同时有具有体会性的调试思路。(其实我可以写一个JSION脚本来描述,但是。。。。。。自行体会吧)
1.复现问题与收集数据
1.逻辑分析仪的使用,这里可是重中之重啊,硬件的逻辑分析仪要插好,这里我们要捕获的是PL端和DUT的通信波形,所以就是插在CC线上咯;然后就是配置一下逻辑分析仪软件的配置啦,第一个是采样率,由于USB PD协议的波特率是300kbps,所以采样率要比他高,但是高多少啊,其实俺不知道,那就3Mbps吧,上网查一下就知道了。第二个是要设置一下触发方式,这里选择下降沿触发,看了BMC通信的波形,起始位是高电平,所以要捕获下他下降的那一刻。第三个是要启用一下BMC解码的功能,不然啥都没有哦(呜呜呜,谁知道我踩了多少坑,卡了多久)。
2.启动内核调试日志,因为我的Linux驱动代码是有调试打印功能的,所以说在开始运行的时候直接开一个终端跑log就行。
如果没有开启,那就完了。好吧,我开玩笑的,你可以手动开启???我好像在说废话。。。
首先要确保Linux驱动代码中的dev_dbg()、print_hex_hump_bytes()等调试打印功能是开启的。因为实际上有好多个log,是不是感觉好麻烦,没事,看关键信息就行。
你可能需要通过dynamic_debug机制动态开启:这里不展示代码,只说怎么做。
你可以通过echo命令将一个驱动文件的输出重定向到control 里面。
例如:echo 'file pd_driver.c +p' > /sys/kernel/debug/dynamic_debug/control
好吧好吧,你赢了,我还是写了。
3.复现与捕获:
开始运行程序,触发PD协议的交互,直到交互失败。可以从dmesg命令中打开日志,查看内核日志。
2.联合分析,定位矛盾(看逻辑分析仪的波形,看日志)
1.看波形:当然是在逻辑分析仪软件上看啦,注意这个时候不要从头开始看波形,直接找仪器发送的Source_Capabilities消息和DUT(Sink)回复的Request消息。重点关注我的Request消息,但是仪器发送的消息也要看啊,万一是我发的有问题呢,不要排除任何一种可能,逻辑分析仪,逻辑一定要完美,不能有漏洞。
2.当然说了这么多废话,还是要重点看Requset消息,因为大多数是回的有问题,别问我怎么回事,我瞎说的,哈哈哈哈。
言归正传,在Request消息里,要展开这条消息的详情,查看软件解码出的每一个字段:消息头、数据对象、CRC32(有的人说CRC16,其实现在多是32,这样效果更好,数据安全性更好)。
这里要验证一下我的逻辑分析仪,为了以防万一啊,万一逻辑分析仪坏了咋办呢。啊,逻辑分析仪坏了,是不是感觉累了,哈哈哈,啥都得提防,坏人好多。
怎么验证呢,当然是把消息头、数据对象那些十六进制数据自己手算一下CRC校验值啦。什么,你说你不会,好吧,其实我也不会,但是没有计算器吗?
好,通过计算器验证了一下,发现和逻辑分析仪解码出来的一样,说明我们的逻辑分析仪还是可信的,是好人捏。
好了,既然逻辑分析仪解码正确,说明这里波形是正确的,说明DUT传过来的是正确的,消息也确实是发给我仪器了。但是我的驱动却认为CRC错误。那问题可能出现在传输过程中,或者在PL端,这里其实已经初见端倪了。嘿嘿,小黑子终于露出了犄角。
那接下来就看一下内核日志这一块是怎么说的吧。查看内核日志,找出驱动记录“CRC错误”或者“丢弃无效的消息”的那一行。日志会显示驱动实际接收到的完整消息和CRC值。对比一下逻辑分析仪的正确CRC值,发现这个日志里面的和那个正确的CRC值不一样。好,确定了我上面的猜测。
这个时候我可以百分之百确定就是在传输的过程中或者是PL端哪里出现了问题。其实后面想了一下,可能是DUT向PL端传输时出现了错误,也可能是PL端,还有可能是PL端向PS端传输的过程中出现了错误,到底是哪个啊,好难猜啊哈哈哈哈哈。其实我是想知道先排查哪一个,那就分析分析吧。
3.深入挖掘原因
1. 首先,PL端应该放最后,因为那是FPGA硬件工程师的错误,最后再说,DUT向PL端传输也应该放后,因为目前没有手段直接读到FPGA端接收到的CRC32值,先排查我软件驱动读到的值吧,而且从软件到硬件排查也是通常的一个顺序。
2. 好了,分析了好久,还是回到了我驱动读到的CRC值。驱动一般不会“写”,不会修改CRC值,那么只有可能是驱动从RX_FIFO寄存器中读取错了,检查一下代码,看看是逻辑错误,还是一次性连续读取4个uint32_t,字节序的问题(毕竟是arm架构和FPGA架构),还有缓存或者内存对齐的问题?
如果这些代码没有问题,那么就是寄存器里面的数据本身就是有问题的!!!好了,这个时候我的驱动这边问题排除了。那接下来就是PL端的问题了,或者说肯定是PL端的问题了,不不不,大概率是他的问题(差点草率了,其实还有DUT向PL的过程,但是这个概率太小了,但是我不能排除,不然会出问题)。
好了,将问题丢给硬件工程师,我的调试基本上结束了。
4.解决方案
1.我不从PL端的RX-FIFO寄存器读取CRC值,根据数据直接在驱动里计算CRC值。这样做可能看着有点别扭,但是你先别别扭,因为不能因为这个错误把进度卡了,所以先这样吧。
2.修复FPGA端的错误,定位在了IP核中的CRC模块,配置错误,CRC寄存器初始值不是0XFFFFFFFF,很细节是不是哈哈哈,一个配置错误直接卡了我好久。