|
对我来说,使用ARM Cortex-M内核最令人沮丧的事情之一是遇到HardFaults硬件异常。这周我已经花去了好几个小时来调试和跟踪ARM Cortex-M0+器件上的硬故障的实例。
背景是,我将一个项目(NXP Kinetis KW40Z160)移植到Eclipse和ARM的GNU工具链中。 将该应用程序使用调试器下载到器件后,看上去运行良好。
但是,如果我使用调试器重新启动,或者是使用SYSRESETREQ复位微控制器(参见“如何使用软件复位ARM Cortex-M”),则它就会发生HardFaults硬件异常。
有趣的是,它在启动时在ANSI库中的_init()函数中崩溃:
在_init()中寄存器入栈会导致硬件异常:
有趣的是,同样的代码以及相同的寄存器/堆栈/等在第一次时工作正常。但在应用程序运行后不能正常工作。 通常的猜想 第一个猜想是检查通常的怀疑点: ■ 检查硬件异常处理程序的输出? 未显示任何可用的内容。 ■ 堆栈指针不对齐? 不会,第一次时使用相同的值工作正常。 ■ ARM / Thumb模式? 不,都处在Thumb模式。 ■ 堆栈可读/可写? 是的,没有使用特殊保护或其他类型的东西。 ■ 中断优先级? 不,发生时禁用中断。 ■ 调试器的问题? 不,尝试Segger和P&E,两者相同,它发生时与有没有使用调试器无关。
好吧,现在我是没有任何的办法了:-(。剩下的是无尽的尝试问同事还会有哪些原因会返回一个类似上面的问题,所以没有进展。 网上求助 下一步:搜索互联网。 许多其他人也遇到了硬件异常的问题。 至少我发现了一个关于不精确的硬件异常的有趣的文章。 很不错的文章,并且我深入的学习了一下。 不幸的是,它只适用于Cortex-M3 / M4,不适用于M0+。 不管如何,我已经添加了一个选项到硬件处理程序,使得可以在其他项目中更好地处理这个问题:
我还是没有线索。最终我尝试做一个“二进制”搜索:禁用部分应用程序,以查明是否有一些导致该问题的东西。 虽然耗时,但这是我唯一的选择。 所以我打开/关闭应用程序的部分,来找出应用程序的什么部分导致的问题。 Gotcha! 事实上,经过几个小时的搜索,我将该问题缩小到闪存编程:应用程序通过重新编程一个1 KB的闪存页面在内部存储数据,为此它会擦除闪存中的1K块。 在链接器文件中,它按照如下进行分配: - .nvm :
- {
- . = ALIGN(8);
- NV_STORAGE_START_ADDRESS = .;
- . += 1024;
- NV_STORAGE_END_ADDRESS = .;
- } > m_text
复制代码
擦除似乎工作正常。 但是在块擦除后,单片机重新启动后将会崩溃。
仔细查看链接器文件,我终于发现了问题:它应该对齐到1k闪存块大小: - .nvm :
- {
- . = ALIGN(1024); /* must be 1k aligned! */
- NV_STORAGE_START_ADDRESS = .;
- . += 1024;
- NV_STORAGE_END_ADDRESS = .;
- } > m_text
复制代码
随着这个更改,问题消失了。 总结 处理ARM上的硬件异常并不容易。 本文的硬件异常是由擦除未对齐的闪存存储器块造成的。 在我看来,处理器的内部不知何故被这样搞砸了。 我们面临的挑战是,它崩溃的方式与问题的原因并不是很紧密。 这种问题不容易找到和解决。 在这种情况下通常最好并且有效的方法是尝试缩小问题:有一个“工作正常”代码,以及一个“失败”的版本。 尝试删除所有变量(电路板、调试器、电源、主机),然后减少问题尽可能地缩小问题。 在任何情况下,我希望这篇文章可以帮助其他人在这种情况下;-)。
参考链接: ■ 使用软件复位ARM:https://mcuoneclipse.com/2015/07 ... ex-m-with-software/ ■ 一种检测不精确硬件硬件异常的方法:https://community.nxp.com/docs/DOC-103810
原英文链接:Debugging ARM Cortex-M0+ HardFaults |