当处理器被锁定时,这确实是很扎手的问题,被锁定就等同与死机,我们唯一能做的是避免锁定状态。因为锁定只出现于NMI和硬fault的服务例程中,所以在设计它们时,一定要分外地小心,就好像亲手给自己的爱人做大手术那样一丝不苟。比如,我们应该尽量避免不必要的椎栈访问,这是有原因的。对于NMI来说,在进入NMI时常常是在危急关头,如掉电,短路等硬件故障。此时,有可能存储系统已经失能了,而对于硬fault来说,有可能是因为SP指针飞了,以致前面的椎栈操作触发了本次硬fault ,再操作椎栈还不当场被秒杀?如下面代码所警示:
hard_fault_hander
PUSH{R4-R7,LR} ;除非确保椎栈是安全可用的(谁能确保?),否则
┇ 不要这样做
值此危难关头,必须沉着冷静,在设计硬fault,总线fault以及存储管理fault的服务例程时,值得先花点功夫去查一查SP值,看它是否在可接受的范围,然后再做后续工作。对于NMI服务例程来说,它做的通常是应急工作,设计系统时就应该让这种应急工作极简单(比如,只以改变一个I/O脚的电平,最多也就是修改若干寄存器的值,就可以开启相关的应急硬件),因此常常可以只使用R0-R3以及R12就完全名胜,无需椎栈操作。
简化硬fault和NMI的服务例程确实是个好主意:它们只做必需的,然后挂起PendSV让诸如错误报告等其他工作在PENDsv中处理。当然,软件中断兴许也能凑合着用。
除此之外,我们还必须杜绝在硬NMI/fault 例程中使用SVC指令,这也是斩立决的,因为SVC的优先级总是没有NMI和硬fault的高,而且它又不允许挂起,这看起来很容易做到,但是当程序变得复杂,并且如果NMI/硬fault服务例程序中调用了其他目标文件中的函数,就不能保证这些函数中没有使用过SVC。因此在开发软件时,必须认真地仔细地计划如何实现SVC。或者获取调用函数的说明文档。确保不会出事。 |