嵌入式系统异常复位定位思想 2007-05-11 22:06:05 大中小 凡是靠软件支撑的嵌入式系统都会发生复位现象,如果没有发生过复位,那么很有可能会发生另外一种更糟糕的情况,系统吊死,陷入了死循环,你根本就不知道它到底运行到了哪里。也有可能是你的能力所限,异常中断没有写好,虽然处理器发生了异常,但你没有去处理。所以从这来看,发生了复位还不算最坏,至少系统能恢复,只要不是经常发生,没准你的客户始终都发现不了,还会夸你的产品很好。 现在的处理器已经做的很好,只要你对它的工作原理稍微有点了解,那么你就可以写出适当的代码,当发生异常的时候,根据现场保留的故障诊断信息,来定位出错的根源。至于为什么会复位,本质来说是你的软件自己让它复位的(最常用的是看门狗),常见的DEMO程序,异常中指分之,只是些个死循环,在实际的产品中是万万不能这样操作的。 对于各种处理器,异常一般会有3种: 1)预取指中止,也就是说取得指令地址不正确,因为处理器都会有一些保留地址,这些地址CPU是不能访问的,万一进行访问,就说明程序执行出错了。 2)数据中指,也就是说访问的数据地址不正确,原因同上。 3)指令错误,顾名思义,指令译码出错。 在如上的三种情况,软件都必须要处理,简单的话,开看门狗,对系统进行复位,负责任的话,可以保留现场信息,留着后面的程序员来定位原因。 当然还有高档的CPU,这种异常是一种特殊的处理,比如地址重映射等,这里不关注,需要特殊处理。 对于一个稍微复杂点的嵌入式软件,它会专门作一个故障诊断的功能,当系统发生警告或者错误的时候进行特殊处理,比如内存不足,当错误积累到一定程度,系统自动复位,这种是一种纠错处理,处理器并未发生异常。 以ARM7为例,我们知道在用户模式下我们常用的R0-R15以及CPSR共17个寄存器,其中R15是用作PC指针,R14用作函数返回指针,R13用作堆栈指针。那么发生异常后我们怎么做才能给以后提供足够的定位信息呢? 1)根据异常模式下的R14找出USER模式下的PC指针,因为这个时候已经发生了处理器模式切换。 2)切换到特权模式访问用户模式的SP指针,通过SP指针,保存堆栈数据到RAM(注意这片RAM开机不要被初始化,可以通过编译配置完成)。 3)复位系统,开机检测到异常开机,把诊断信息记录到文件系统。 4)用工具读出文件到PC,对比编译的符号文件,一般是MAP文件,或者使用其他工具,进行分析,不出意外,很快就能找出复位的原因。 有些处理器会有指令执行过程中总线记录的环形RAM,每当指令执行,总线访问的地址,以及访问方式会实时记录下来,当有异常发生的时候,这片RAM区域会自动锁死,只能访问,不能改写,同样可以记录下来,保存到文件系统,供以后分析。 其实这里还没有说为什么处理器会产生异常,从我来看,绝大多数的异常内存越界引起的,比如 U32 buf[1]; for(i = 0; i < 10; i++) { buf = 0xFFFFFFFF; } 上述代码在语法上是没有任何问题的,但执行的过程中就会发生异常。因为局部变量(buf[])都是从堆栈中申请的,下面的那个循环就会把堆栈中其他地址的内容都改写成0xFFFFFFFF,如果当地址访问的话就发生了错误。 还有最常见的堆栈溢出,也就是堆栈空间开小了,申请的局部变量跑到堆栈以外了,改写了其他地方的RAM,引起处理器异常。 以上只是简单说一下原理,具体仍需要对处理器稍微有些了解,不是朝夕就能立刻生效的,ARM的话可以参考《ARM体系机构与编程》,其实这本书就是ARM公司的英文文档的精简翻译,看看英文原版也未尝不可。
|