Arm “我如何调试?”;“未定义指令”;IAR Embedded Workbench中LPC1788的故障?

Arm “我如何调试?”;“未定义指令”;IAR Embedded Workbench中LPC1788的故障?,arm,microcontroller,lpc,Arm,Microcontroller,Lpc,我正在为LPC1788(Cortex-M3)微控制器开发一个应用程序。此应用程序涉及发送和接收CAN消息,我发现当我将其置于重载状态并转动拇指30-60分钟时,将发生硬故障 我正在通过IAR Embedded Workbench 6.60.1.5104调试固件,当发生此硬故障时,它会在启动\u LPC177x\u 8x.s中定义的弱链接默认硬故障处理程序处中断: PUBWEAK HardFault_Handler SECTION .text:CODE:REORDE

我正在为LPC1788(Cortex-M3)微控制器开发一个应用程序。此应用程序涉及发送和接收CAN消息,我发现当我将其置于重载状态并转动拇指30-60分钟时,将发生硬故障

我正在通过IAR Embedded Workbench 6.60.1.5104调试固件,当发生此硬故障时,它会在
启动\u LPC177x\u 8x.s
中定义的弱链接默认硬故障处理程序处中断:

        PUBWEAK HardFault_Handler
        SECTION .text:CODE:REORDER(1)
HardFault_Handler
        B HardFault_Handler
不幸的是,调用堆栈只包含此处理程序的地址,而不包含调用它的代码的任何部分(错误发生的地方)

我能收集到的唯一有用的信息是从
NVIC:CFSR
寄存器中设置的
UNDEFINSTR
位。从文件中:

设置此位时,为异常而叠加的PC值将返回 指向未定义的指令。未定义的指令是 处理器无法解码的指令。潜在原因:

a) 使用Cortex-M设备不支持的指令。
b) 内存内容不正确或损坏

我读到指令执行点的程序计数器值存储在一个异常堆栈寄存器中,但我不确定如何从IAR访问这些寄存器

如果有任何帮助,我已经提供了一个屏幕截图,其中包含一些调试细节(
右键单击->查看图像
,查看更大版本):


我通过修改找到的代码找到了解决方案

那里的用户“Ramon”很有帮助地发布了代码,使我走上了用IAR编译的正确道路(我以前从未尝试过在IAR Embedded Workbench中编写原始程序集)

这是我使用的硬故障处理代码:

#包括“lpc177x_8x.h”
静态易失性无符号长堆叠_r0=0;
静态易失性无符号长堆叠_r1=0;
静态易失性无符号长堆叠_r2=0;
静态易失性无符号长堆叠_r3=0;
静态易失性无符号长堆叠_r12=0;
静态易失性无符号长堆叠_lr=0;
静态易失性无符号长堆叠_pc=0;
静态易失性无符号长堆叠_psr=0;
静态易失性无符号长_cfsr=0;
静态易失性无符号长_hfsr=0;
静态易失性无符号长dfsr=0;
静态易失性无符号长_afsr=0;
静态易失性无符号长_bfar=0;
静态易失性无符号长_mmar=0;
无效硬故障处理程序(无效)
{
__asm(“tst lr,#4”);
__asm(“ite eq\n”
mrseq r0,msp\n
“mrsne r0,psp”);
__asm(“b硬故障处理程序c”);
}
无效硬故障处理程序c(无符号长*硬故障参数){
叠加_r0=((无符号长)硬故障_参数[0]);
堆叠_r1=((无符号长)硬故障_参数[1]);
叠加_r2=((无符号长)硬断层_参数[2]);
叠加_r3=((无符号长)硬断层_参数[3]);
堆叠_r12=((无符号长)硬断层_参数[4]);
叠加_lr=((无符号长)硬断层_参数[5]);
堆叠_pc=((无符号长)硬故障_参数[6]);
叠加_psr=((无符号长)硬断层_参数[7]);
//可配置故障状态寄存器
//由mmsr、bfsr和ufsr组成
_cfsr=(*((易失性无符号长*)(0xe000ed28));
//硬故障状态寄存器
_hfsr=(*((易失性无符号长*)(0xe000ed2c));
//调试故障状态寄存器
_dfsr=(*((易失性无符号长*)(0xe000ed30));
//辅助故障状态寄存器
_afsr=(*((易失性无符号长*)(0xe000ed3c));
//读取故障地址寄存器。这些寄存器可能不包含有效值。
//检查bfarvalid/mmarvalid以查看它们是否为有效值
//内存管理故障地址寄存器
_mmar=(*((易失性无符号长*)(0xe000ed34));
//总线故障地址寄存器
_bfar=(*((易失性无符号长*)(0xe000ed38));
__asm(“bkpt#0\n”);//进入调试器
}
为了测试这一点,我创建了以下函数,以确保捕获“零除”使用错误,但使用错误将自动提升为硬错误:

void configureFaultHandling()
{
//抓住所有可能的错误。
//SCB->SHCSR |=SCB_SHCSR_MEMFAULTENA_Msk
//SCB_SHCSR_BUSFAULTENA_Msk
//| SCB_SHCSR_USGFAULTENA_Msk;
SCB->CCR |=SCB_CCR_部门0_TRP_Msk
|SCB_CCR_UNALIGN_TRP_Msk;
}
我在
main
的开头添加了以下内容:

void main()
{
配置FaultHandling();
INTA=5/0;
}
运行此操作时,程序在
void hardfault\u handler(void)
处快速停止,我可以逐步进入
hard\u fault\u handler\u c
并检查寄存器的值

我发现这些值与IAR的
视图->堆栈->堆栈1
窗格中显示的值相对应。事后看来,这是有道理的,因为文档中指出,当发生故障时,某些寄存器的值会被推送到堆栈上。然而,编写这个函数帮助我找出堆栈中的哪些值对应于哪些寄存器

为了参考我自己和其他可能有类似问题的人,我发现“堆栈1”(即索引6)中的第7个值对应于异常发生时的程序计数器值。这就是我看到的样子(
右键单击->查看图像
放大):

这样做可以让您找到硬故障的来源,而无需覆盖默认的硬故障处理程序,只要调试器在发生硬故障时自动中断


希望这也有助于消除“未定义指令”故障。

我通过修改找到的代码找到了解决方案

那里的用户“Ramon”很有帮助地发布了代码,使我走上了用IAR编译的正确道路(我以前从未尝试过在IAR Embedded Workbench中编写原始程序集)

这是硬故障处理代码I u