智能汽车安全新媒体
作者 | 王御
最近返回来一个故障件,需要分析故障原因,这次解决问题的过程比较有意思,记录一下。
01
问题定位及看门狗的影响
首先上电测试,发现工作电流与正常电流差异比较大,控制器也没有CAN报文输出。一般这个时候我会通过调试器接口把整个Flash全部dump为一个s19文件,再把这个s19文件通过调试器刷到另一个正常的件上,如果另一个正常,那就是硬件问题;如果问题依旧,那就是软件问题。这次还是这么操作。
在dump的过程中,如果由于故障这个控制器(A控制器)不断重启,是attach不上的。一般通过在上电时发送10 02指令强制跳转到BT,然后可以dump出完整的flash。
把这个flash通过调试器下载到另一个控制器(B控制器)中,需要注意,必须先通过CAN将特殊的不带看门狗的程序刷写到控制器中,才可以使用调试器下载,否则会导致控制器异常,只能通过Cyclone的小红盒才能救回来。
下载以后测试,果不其然,故障复现,基本确定是软件的问题。照理说现在应该attach以后通过单步调试查找问题,但是控制器不断重启,attach不上。即使attach上,断点停住后会导致电源芯片没喂狗导致异常,所以单步调试前必须去掉电源芯片看门狗。
先说一下分工,这个控制器是由硬件、基础软件、应用软件及集成三个团队共同开发的,基础软件交付给我们应用组是静态库文件。基础软件在初始化的时候对电源芯片进行配置,开启或者关闭看门狗,电源芯片对MCU进行复位。
正常要关看门狗,就要和基础软件的同事提需求,他给代码并重新编成库给我们,我们再重新集成。但是这个故障件这么操作可能会导致失去故障现场,因此需要一种不影响软件和硬件的方式来实现。
02
关闭看门狗方案
与硬件同事沟通,了解电源芯片MCZ33903进入的条件为:DBG PIN电压在8-10V,退出条件为:DBG PIN电压在8-10V以外 or SPI 设置MODE 寄存器。说明如下图:
2.1 硬件方案
硬件的同事介绍,DBG电压还受MCU控制,上电默认进入DEBUG模式,但是基础软件初始化后就退出了DEBUG模式。硬件同事提供了几个解决办法:
通过焊接一个零欧电阻,屏蔽MCU对DBG的控制;同时将MCZ33903的片选针脚弄断,以此断开MCU合MCZ33903的SPI通信
断开某个零欧电阻,断开MCZ33903重启MCU的通路,使得电源芯片无法重启MCU
以上两种方式都需要物理改造,而且有副作用,暂时先不采用,实在不行再说。
2.2 软件方案
与基础软件的同事沟通,设置看门狗的代码如下:
s_uasSendBuffer[0]=LEAVE_DEBUG_MODE; // 0xDD00
Spi_SyncTransmit(s_ucSequenceNumber); // 发送退出DBG模式SPI指令:Leave_DBG_MODE(0xDD00)
// 略过
Rte_Call_GPO_GPIO130(0); // 配置DBG控制IO口为低,禁用DBG:SET GPIO130=0;
第二个办法是直接修改dump出的s19,直接把这两个语句改了。思路是从C代码找汇编码,然后找机器码,然后确定修改后的机器码,然后在s19中完成替换,再修改s19的行校验,然后再刷写到控制器中进行单步调试。
03
实施过程
先找汇编码和机器码,打开调试器的Assem窗口,搜索函数名MCZ33903,找到关键代码如下:
0x4d09a: 701b0500 e_li r0,0xdd00
0x4d09e: b00f se_sth r0,0(r31)
0x4d0a0: 307e2570 e_lbz r3,0x2570(r30)
0x4d0a4: 78025da5 Spi_SyncTransmit(0x72e48)
// 略过
0x4d0b2: 4803 se_li r3,0
0x4d0b4: 79ffe2e7 e_bl IoHwAb_OutputGPIO130(0x4b39a)
看到这一堆东西,我整个人是有点懵的,上一次用汇编还是十几年前的微机原理和51单片机,语法和这个差挺多的。没事,慢慢来,第一步是弄明白机器码和汇编码的对应关系。在网上下载了《Programmer’s reference manual》,根据这个手册,对关键的两行代码做分析。
3.1 SPI设置代码分析过程
701b0500 e_li r0,0xdd00
先看汇编码的含义
701b0500: 0111-0000-0001-1011-0000-0101-0000-0000
按照e_li指令重新划分,为:
701b0500: 0111-00|00-000|1-1011|-0|000-0|101-0000-0000
得到相应位置为:
RD=0
LI20(4:8)=11011
LI20(0:3)=0000
LI20(9:19)=101-0000-0000
LI20=LI20(0:3)LI20(4:8)LI20(9:19)=0000-1101-1101-0000-0000=0xDD00
这下对上了,把0xDD00替换为一个查询指令0x2100(RD_CAN:确认CAN寄存器)
LI20=0X2100=0000-0010-0001-0000-0000
LI20(9:19)=001-0000-0000
LI20(0:3)=0000
LI20(4:8)=00100
更新后的指令为:
0111-00|00-000|0-0100|-0|000-0|001-0000-0000
换算为十六进制为:
70040100 e_li r0,0x2100
4803 se_li r3,0
先看汇编码的含义
4803:0100-1|000-0000-|0011
UI7=0,修改为UI7=1,则代码为
0100-1!000-0001-!0011:4813 se_li r3,1。
3.2 s19替换
到这一步为止,已经知道替换的机器码了。701b0500->70040100,4803->4813,开始搞s19.
用VScode打开s19,寻找并替换,同时计算最后的校验byte,修改后如下:
用hexview打开这个文件,并和dump出来的s19做比较,确认修改正确。
3.3 下载测试
使用调试器将修改后的s19下载到控制器中,需要注意,必须先通过CAN将特殊的不带看门狗的程序刷写到控制器中,才可以使用调试器下载,否则会导致控制器异常。
下载成功!attach,成功!在初始位置下断点,在周期任务下断点,reset,初始位置停住了,run,周期位置停不住!好,问题定位,继续查找,发现是NVM相关的问题,好了,接下来就可以将问题移交给基础软件的同事解决了。完结撒花!
最后补充一个操作上的失误,别人告诉我控制器里面的版本号是2007,在Attach的时候选择了2007版本的elf,导致单步的时候代码对不上了,在调试器窗口看到0x4d09a位置不是701b0500了,然后又从dump出的s19找版本号的字符串,发现是2009,在Attach的时候选择了2009版本的elf,这才一切正常,所以一定要注意维护好elf的版本,一旦丢失,排查问题的时候就抓瞎了。
来源:@知乎王御
https://zhuanlan.zhihu.com/p/508465914
- THE END -
精品活动推荐
因文章部分文字及图片涉及到引用,如有侵权,请及时联系17316577586,我们将删除内容以保证您的权益。