从CortexM0中的RAM运行代码时发生HardFault

Kyl*_*ira 5 c++ memory assembly arm cortex-m

我目前正在为Arm Cortex-M0 +微控制器开发固件,并且面临一个相当有趣的问题。我不是在寻找任何答案,而是想与其他开发人员分享问题,以便我(希望)对我所面临的问题有所了解。我将在下面描述它:

我有一个程序可以从外部闪存芯片动态加载(正确编译和链接)代码,然后直接在MCU RAM中执行。有趣的是,当逐步(通过调试器)运行时,我可以完美地执行RAM加载的代码,但是在自由运行时,它总是会崩溃(正式为HardFault)。我试图禁用所有中断,我仔细检查了指令,内存地址,字节对齐方式以及所有内容,但是我仍然无法查明异常的原因。

你们中有人对可能发生的事情有任何暗示吗?我非常想知道更多有关您的经历!谢谢,

更新1(30/05)

在这种情况下,自由运行意味着在分支到RAM之前不设置断点。每当我进入分支并在RAM中执行指令时,它将正确运行并返回。无论断点不在哪里(因此MCU都会通过分支进行缩放),都会观察到HardFault。请注意,即使在调试器启动但未设置断点的情况下启动,它也会崩溃。

更新2(30/05)

我正在使用Cypress S6E1C3系列Arm Cortex M0 + FM0 +微控制器

更新3(30/05)

深入研究并使用代码后,我可以使其正常工作!但是,它给我带来的问题多于答案。阅读有关BLX指令(BLX)的ARM官方文档后,我发现分支地址的LSBit 确定了CPU指令模式(1导致它以Thumb模式运行)。通过显式设置该位,即使在自由运行模式下我也可以使代码始终运行。事实是,RAM中的代码尚未在Thumb模式下进行编译,并且没有明显的原因说明为什么使用调试器逐步运行代码会导致指令模式发生变化...有什么想法吗?

K.

Kyl*_*ira 1

问题出在分支地址中(正如 @PeterCordes 正确指出的那样)。到 RAM 的分支由以下代码执行(针对此受众稍作调整):

// Prepare address and Function Pointer
uint32_t codeBufferAddress = reinterpret_cast<uint32_t>(&buffer) + offset;
void(*methodFromRAM)(void*) = reinterpret_cast<void(*)(void*)>(codeBufferAddress | 0x01);

// Branch to RAM
// thisPointer holds an object byte-stream...
(*methodFromRAM)(reinterpret_cast<void*>(thisPointer));
Run Code Online (Sandbox Code Playgroud)

请注意,第 3 行与( )codeBufferAddress进行或运算,这确保分支将在Thumb Mode下进行。当我发布这个问题时,所持有的值是,它显然没有设置 LSBit ,因此会强制 MCU 在ARM 模式下运行。0x01codeBufferAddress | 0x01codeBufferAddress0x20003E40

我认为编译器将无法推断和调整分支模式,因为地址是动态生成的 (尽管我认为它可能更聪明一点并强制所有分支在Thumb 模式下运行,因为我的 MCU 只能解码 Thumb )。

无论如何,当在逐步模式下运行时,我无法观察到目标地址的任何变化,目前我只能猜测它强制 MCU 在Thumb 模式下运行......但这只是一个猜测。有任何想法吗?

K.