关于飞思卡尔单片机MC9S12XET256A出现看门狗COP不复位且系统出现死机现象,所有功能或管脚无输出并卡死等问题的总结,希望给遇到同样问题的朋友提供参考。
由于对飞思卡尔的看门狗COP不是很了解,导致工作过程遇到了一些麻烦,后来经过很长时间的搞鼓,并通过NXP官网技术支持的帮助,解决了问题,现总结如下:
?与其他单片机不同的是看门狗计数溢出后:9S12是先复位系统(寄存器和所有外设
都恢复到默认状态),然后PC指向看门狗中断向量所保存的看门狗中断服务程序地址)。 注意!看门狗中断是不可屏蔽中断,且它并不是一个中断服务函数,只是一个路径。系统复位以后,执行的第一动作就是将系统指针PC首先跳到该路径上,因此必须在代码里声明该路径的地址向量,声明的地方在一个后缀名为.prm的文件里。
默认只有VECTOR 0 _Startup,但9s12有三种复位的情况,分别指向三个地址,0号是系统上电,非法地址等复位;1号是时钟异常复位;2号就是我们需要的看门狗复位;我们让系统复位后,都把PC指向启动首地址。注意!如果不定义,系统指针就一直指向对应中断标号的地址上,且不会再跳转移动,整个系统像跑飞或卡死的现象。 这个问题外国朋友Radek说得通俗易懂,如下:
Hi XJC,
I am glad that it works now.
The problem is that the COP do not cause any watchdog interrupt and CopInterrupt() isn’t an interrupt routine (ISR).
When COP is not triggered properly, it will reset MCU. If COP is detected as reset source, vector at address 0xFFFA will be fetched. This vector points to your CopInterrupt() routine.
Similar is valid also for CM reset (vector at 0xFFFC).
POR/External/Illegal Address resets will fetch reset vector at address 0xFFFE.
So, the CopInterrupt() routine is executed as first code after MCU reset (while the stack is not initialized yet) and RTI instruction at end of routine doesn’t have sense (there isn’t any context which might be restored). The CopInterrupt() (CMInterrupt()) routine must end by jump into some code. For example: asm jmp _Startup;
If you do not want different behavior/code for POR/CM/COP resets, you may define _Startup() routine for all three vectors inside prm file. For example: VECTOR 0 _Startup //Power On, External, Illegal Address resets VECTOR 1 _Startup //Clock Monitor reset VECTOR 2 _Startup //COP Watchdog reset
In that case you don’t need to define CopInterrupt()/CMInterrupt() routines.
I hope it helps you.
Have a great day, Radek
?正常情况下,很多人容易配置成如下图所示的示例,那么就会出现两种情况:当在中断
里面放while(1);语句,可以正常产生看门复位;当放一个很长的for循环(超过看门狗溢出的时间),则马上出现卡死现象,不复位情况。(注意!图片的代码 while(1)和for是写在Main函数里,其实在Main里是不会出现这种情况的,一定是要放在中断里才会出现所说的情况)
对于这个现象,外国朋友Radek是这么解释的:
Hi XJC,
It hard to say what exactly happened in this extreme situation. Theoretically, it might be debugged on assembler level.
It is like a jump from the window. Sometimes you may fall on your legs, sometimes on your head. It might depend left or right leg used for the jump start. And always it depends on floor level from which you jumped.
Since, the CopInterrupt() is not ended properly by asm JMP command, the RTI will restore some data from the stack. I suppose that the difference will be just in stack content or stack pointer during MCU reset.
The Situation 2 is a just happy coincidence where RTI instruction will fill program counter by some valid data.
I suppose that i and j variables are probably not static and they exist on the stack. This may cause different stack pointer value and the program counter is filed by invalid data after the watchdog reset.
Anyway, it is code runaway in both situations with happy end only in one case. I hope it helps you. Have a great day, Radek
总结:大概意思就是无解,让我们按套路出牌,不然出现的情况也是无可预知的。
?还有一种情况,如果是有做低功耗处理的,那么在进入WAIT或STOP前,要么关闭看门
狗,要么要想一个办法在低功耗的时候又可以喂狗,又要符合你的功耗要求。否则也会出现如题所说的一些情况。这个解决方法还是按外国朋友Edward说的来解决。配置CLKSEL寄存,使进入wait后看门狗无效,如果是STOP那就自己查DataSheet看是哪个寄存器吧。 It looks like you keep COP enabled in WAIT mode and COP times out while you are in WAIT mode. Of course each reset resets all I/O settings. I think also that you didn't define COP reset vector, at least your map file shows defined only vector 66 @ 0xFF7A. No wonder than that MCU on COP reset can land in state you wrote: \wake\
COP can be disabled in WAIT mode. Look at COPWAI bit in CLKSEL. Please keep in mind that COPWAI bit is write once bit in normal (non debug) mode, so first write to CLKSEL (any CLKSEL bit) must initialize COPWAI to desired level.
Edward
注意!CLKSEL 任何位只能被写一次,后面代码再写的就无效了;抑或是先配置时间时写了该位,再写这个位要关闭看门狗,那就是无效操作了。