1. 背景:
在调试过程中发现,S32K3xx当进行8次软件复位(functional reset)后MCU会死在复位里面,无法正常工作。
驱动库为:SW32K3_RTD_4.4_2.0.0
注意,下述分析比较硬核,要认真的慢慢看才能看明白,笔者自己过了一段时间看第二遍都有点蒙哈哈哈哈
2. 分析:
2.1 EB配置
EB中关于reset的复位如下:
上图配置项解释:
Mcu Reset Type 配置当我们调用Mcu_PerformReset();接口时是执行Functional Reset还是Destructive Reset
Mcu Functional Reset Escalation Threshold (0 -> 15) 配置Functional Reset的阈值,0表示关闭此功能,若配置为n,则n次Functional Reset后会自动执行一次Destructive Reset
Mcu Destructive Reset Escalation Threshold (0 -> 15) 配置Destructive Reset的阈值,0表示关闭此功能,若配置为n,则n次Functional Reset后会保持在Reset状态(表象为MCU跑挂了),直到下一次power-on reset到来重启
2.2 寄存器分析
为了弄清楚8次复位后就死机的原因,我们需要在代码中读取如下寄存器的值:
具体的寄存机介绍请参考文末的寄存器描述或者手册,要看懂后文的描述以及复位的真正原因,读者需先搞懂下述寄存器的作用。
DES_regester = *(uint32 *)0x4028C000;
FES_regester = *(uint32 *)0x4028C008;
FRET_regester = *(uint32 *)0x4028C018;
DRET_regester = *(uint32 *)0x4028C01c;
FREC_counter = *(uint32 *)0x4028C014;
2.3 power-on后实测各寄存器的值如下:
DES = 1 FES = 0 FRET = f DRET = f //在main函数最开始读取的寄存器值
DES = 0 FES = 0 FRET = 0 DRET = 0 //调用Mcu_GetResetReason(void)后读取的寄存器值
注意是否调用Mcu_GetResetReason(void)接口会对寄存器值产生影响。(笔者不太明白NXP驱动中Mcu_GetResetReason(void)函数为什么要去清除DES和FES寄存器)
可以看到,上电后DES的第0位F_POR被置位1,即产生了power-on event ,同时FRET和DRET被硬件置位0XF。
调用Mcu_GetResetReason(void)后清除掉了DES的value,同时在上电代码执行过程中,Mcu_Init()调用Power_Ip_MC_RGM_ResetInit()函数,将EB中配置的FRET和DRET值写给了寄存器,如下图所示,于是FRET和DRET的值被写为0.
2.3.1 死机问题解决方案:
在驱动函数Power_Ip_MC_RGM_ResetInit()中添加如下判断条件即可。如果要搞清楚原因,可继续看后续分析。
2.4 power-on起来后,我们通过调用软复位接口执行functional reset,寄存器值如下:
DES = 0 FES = 20000000 FRET = 0 DRET = f //在main函数最开始读取的寄存器值
DES = 0 FES = 0 FRET = 0 DRET = f //调用Mcu_GetResetReason(void)后读取的寄存器值
FREC = 0
FES显示发生了’Functional’ reset event,可以看到此时DRET寄存器被置位为0xF,这与手册中描述不符。(手册中只有power-on才会置位DRET,且置位为0)。
在这种情况下,实测发现不断的调用软件functional reset接口复位MCU,FREC寄存器的值始终为0,且FRET寄存器为0,即disable了阈值功能, 因此在这种情况下不会出错。
2.5 power-on起来后,我们通过外部看门口拉引脚的方式reset MCU,寄存器值如下:
DES = 0 FES = 1 FRET = f DRET = f //在main函数最开始读取的寄存器值
DES = 0 FES = 0 FRET = f DRET = f //调用Mcu_GetResetReason(void)后读取的寄存器值
可以看到FES寄存器被置位1,即发生了functional reset,同时FRET和DRET被硬件置位0XF(这与手册中描述不符,FES = 0X1可以看出发发生了external reset事件,且不会置位DRET寄存器)。在经过Mcu_Init()函数时,如图2所示,由于DES寄存器等于0,于是不会去写FRET和DRET为EB中配置的值,这两个寄存器同时被置位0xF,即FRET和DRET的阈值功能被激活。Mcu_GetResetReason()会将FES寄存器的值清零。
2.6 power-on起来,通过外部看门口拉引脚的方式reset MCU后,通过软件进行functional reset,寄存器值如下:
DES = 0 FES = 20000000 FRET = f DRET = f //在main函数最开始读取的寄存器值
DES = 0 FES = 0 FRET = f DRET = f //调用Mcu_GetResetReason(void)后读取的寄存器值
FREC = 8
第8次软复位后系统就死在reset里面了。这就极度异常了,首先从设计上说不应该出现这种情况(对用户而言在EB中是关闭了FRET和DRET功能的)。其次,FRET和DRET中的值为0xf,即15,理论上说15次functional reset产生一次destructive reset,15次destructive才产生一次死在reset中的事件。但是FREC = 8的时候系统就死掉了。与NXP的FAE沟通,他们这部分的确存在一些问题,应该在后续的驱动和软件更新中会解决这些问题,笔者当前的解决方案就是2.3.1节中描述的,简单粗暴,如果您看懂了上述分析,其他相关问题也都可以通过修改驱动来规避。
3. 相关寄存器:
查看数据手册可以看出EB中的Mcu Functional Reset Escalation Threshold对应FRET寄存器,Mcu Destructive Reset Escalation Threshold 对应DRET寄存器。
FRET寄存器:
由上图可知,当我们写FRET寄存器时,会清除 functional reset counter的值(清为0)。当发生power-on reset和Destructive reset时会重置FRET寄存器,手册中FRET的默认值为0,但实测发现为15(0XF)。如下图所示:
DRET寄存器
如上图,在DRET中写入任何值会重置destructive reset counter寄存器为0,当发生power-on reset时会置位DRET寄存器。同样,手册中DRET的reset value为0,但实测发现为0XF(15)
DES寄存器:
- power-on后F_POR会被置为1。
- 往bit中写1清零寄存器。因此可以看到驱动中这样的清零方式: