嵌入式软件调试(Debug)方法
- 1 问题定位和分析方法
- 1.1 二分定位法
- 1.2 数据流方法
- 1.3 隔离法
- 1.4 汇编法
- 1.5 ABA法
- 1.6 版本回溯确认法
- 1.7 调试IO法
- 2 调试注意事项
- 3 典型问题类型
1 问题定位和分析方法
1.1 二分定位法
方法阐述:
在任务中或者可能出现问题的模块中,屏蔽一半的任务或者代码,在执行确认问题是否消失。
简单示例:
问题:明确知道在任务A中出现了复位问题,且只有一个位置存在问题,如何快速定位在哪个函数中出现复位?
#当然我们知道,通过调试器单步是最简单的,暂时不使用这种方式
二分法排查步骤:
1)、屏蔽func1()、func2()、func3(),如果出现问题消失,则确认问题在此三个函数中,反之则在另外三个函数中;
2)、假设步骤一中问题消失,则可继续屏蔽func1()、func2(),观察问题是否存在,判断依据同上;
3)、重复上述步骤,则可找到出问题的函数,细分甚至可以明确定位代码语句。
#上述是在假设问题只存在一个位置,如可能存在多个位置,则需要更多排查步骤(需要明确知道某一块代码不会出现问题,不能依据一半存在问题就排除另一半正常)
Task(A)
{
func1();
func2();
func3();
func4();
func5();
func6();
}
适用的场景:
1)、容易复现的问题
2)、不好分析,没有头绪的问题
3)、不方便在线调试的问题,无法设置断点单步调试的问题
4)、大部分问题(只是可能存在更简单的方式)
1.2 数据流方法
方法阐述:
依据设计的数据流,从数据产生的源头开始,依据数据的流向,依次确认数据在每个节点的处理正确性。或者方向也可。正确性含义——1)、进入某节点的数据或者流出某节点的数据是否与预期的一致;2)、定位出数据链路上具体哪个节点处理存在问题;
简单示例:
1)、图一为简单的模拟开关状态采集原理图
2)、图二为软件在模拟开关开关状态处理的常见步骤/模块(体现了其数据流)
问题:假设开关逻辑处理模块未得到正确的开关状态,应该如何准确的定位问题位置?
数据流分析方法(此处以采集端至上层软件的分析方向,也可反向):
1)、确认板端硬件电压正确性(通过万用表、示波器等均可,主要包括两个值:a)、参考电压;b)、开关不同挡位下的电压)
2)、通过调试器观测电压采集模块确认采集后的电压正常与否(若不正常,则取确认MCAL配置)
3)、确认滤波后的电压是否正常(若不正常则排查ADC滤波及换算模块)
4)、以上均无问题,则排查开关状态处理模块(如状态定义的阈值、死区设置等)
适用的场景:
1)、数据链路清晰
2)、接口之间接口较为简单
3)、节点的输入、输出数据易于获取:在线调试、打印log、通信发送等
1.3 隔离法
方法阐述:
定义:单独针对某个模块(函数、子系统等)进行调试
方法:a)、模型仿真(如在Simulink中对功能进行仿真),给模块输入,监控模块的输出;b
)、将模块/函数单独放在单元测试软件中对其进行测试;c)、在线调试,将模块输入替换成可修改的变量,模块输出替换成易观测的变量
工具:劳特巴赫、Tessy、Simulinkdeng
#下图为进行在线调试时,修改的示例:将原有的输入去除(见左侧虚线),将输出增加或者替换成可监控的变量或者其他可观测类型输出
适用场景:
1)、模块之间无耦合性、接口清晰的模块
2)、问题已经可定位至具体的模块
3)、纯粹逻辑问题
4)、针对问题模块进行调试
5)、仿真与在线仿真结合可以排查编译相关问题(如数据类型处理方式等)
1.4 汇编法
方法阐述:
1)、对某段代码进行反汇编,在汇编的层次上进行单步执行
2)、查看每一步对应的寄存器值是否正常(通用寄存器、PC、SP等)
3)、查看跳转是否正常
简单示例:
某一块RAM地址写入超出实际范围,最后修改了CSA存储区域,导致OS执行完之后无法完成CSA切换,导致OS进入Trap(未保存下来相应记录)
排查方式:单步发现在某一部之后进入OS Trap,根据跳转地址、CSA指针地址等判断出来内存问题
适用场景:
1)、定位到具体语句却无法查出问题根源
2)、程序莫名奇妙跑飞问题
3)、BT跳转追踪
4)、其他怪异的问题
1.5 ABA法
方法阐述:
使用A组件存在问题,将A组件替换成B组件故障消失,再将B组件替换回A组件,故障复现
简单示例:
问题描述:某功能与MCU、SOC以及芯片A相关,在该控制器上功能不能正常使用,其余注入相同软件的控制器正常,因此你无法判断是电路问题还是芯片A本身问题?
排查方式:
1)、将芯片A替换成在其他控制器上能正常工作的芯片B,看控制器是否能正常工作
2)、将芯片A在其他正常控制器上进行验证,可以验证芯片A的状态,同时印证步骤一的结论
#ABA方法不一定与描述的一致,记住其思想“替换硬件已验证硬件状态”即可
适用场景:
1)、软件硬件问题界定(无法分辨软件还是硬件导致,可将相关芯片进行替换验证)
2)、外围设备问题(如烧写器、CANoe等),通过更换肯定是好的设备验证设备问题
1.6 版本回溯确认法
方法阐述:
1)、将整个软件或部分模块回滚至确认功能好使的版本,确认相应的故障状态是否消失
2)、将问题版本软件与正常版本软件进行对比分析,针对修改项进行分析
#这是常用的方式,此处就不做示例说明
适用场景:
1)、因软件修改而出现的问题
2)、用于快速分析解决问题
3)、须有完善的版本管理系统
1.7 调试IO法
方法阐述:
翻转IO/IO跳变,通过外部观测设备(如示波器)确认代码执行情况
简单示例:
问题描述:第二个功能必须在第一个功能结束后4s后才能触发(严格时序问题)
测试方法:功能触发时将某一个IO口拉高,关闭时将电平拉低,如图绿色和蓝色分别表示一功能触发与结束(高电平时触发,低电平时关闭),通过示波器就能捕捉相关功能之间的时间间隔
#IO法对于时间测试、时序测试等十分适用,但注意用于测试时若占用某功能接口,在测试完成后须删除测试代码,复原相关功能
适用场景:
1)、分支执行情况分析
2)、时间间隔分析
2 调试注意事项
1)、首先确认硬件状态
2)、调试时尽量关闭看门狗:
a)、调试看门狗时除外
b)、防止复位时不易发现
c)、有时可看到程序死在什么地方
3)、底层问题尽量结合手册
3 典型问题类型
寄存器设置问题、异常处理不完善、数组越界、时序错误、硬件问题、运算溢出、配置错误、栈溢出、运算溢出等