我正在为LPC1788(Cortex-M3)微控制器开发应用程序。这个应用程序涉及发送和接收CAN消息,我发现当我承受重负荷并且用拇指旋转30-60分钟时,会发生严重故障。
我正在通过IAR Embedded Workbench 6.60.1.5104调试固件,当这个硬错误发生时,它会在startup_LPC177x_8x.s
中定义的弱链接默认硬件故障处理程序中断:
PUBWEAK HardFault_Handler
SECTION .text:CODE:REORDER(1)
HardFault_Handler
B HardFault_Handler
不幸的是,调用堆栈只包含此处理程序的地址,而不包含调用它的任何代码部分(发生错误的地方)。
我能够收集的唯一有用信息来自UNDEFINSTR
寄存器中设置的NVIC:CFSR
位。来自文档:
当该位置1时,为异常返回堆叠的PC值 指向未定义的指令。未定义的指令是一个 处理器无法解码的指令。可能的原因:
a)使用Cortex-M设备不支持的说明 b)内存内容不良或损坏。
我已经读过,执行指令时程序计数器的值存储在一个异常堆栈寄存器中,但我不知道如何从IAR访问这些值。
如果有任何帮助,我已经提供了一个屏幕截图,其中包含一些调试细节(right click -> view image
用于更大的版本):
答案 0 :(得分:0)
我通过调整我找到from this blog.
的代码找到了解决方案用户" Ramon"有助于发布代码,使我走上正确的轨道,获得在IAR中编译的内容(我之前从未尝试过在IAR Embedded Workbench中编写原始程序集)。
这是我使用的硬错处理代码:
#include "lpc177x_8x.h"
static volatile unsigned long stacked_r0 = 0;
static volatile unsigned long stacked_r1 = 0;
static volatile unsigned long stacked_r2 = 0;
static volatile unsigned long stacked_r3 = 0;
static volatile unsigned long stacked_r12 = 0;
static volatile unsigned long stacked_lr = 0;
static volatile unsigned long stacked_pc = 0;
static volatile unsigned long stacked_psr = 0;
static volatile unsigned long _cfsr = 0;
static volatile unsigned long _hfsr = 0;
static volatile unsigned long _dfsr = 0;
static volatile unsigned long _afsr = 0;
static volatile unsigned long _bfar = 0;
static volatile unsigned long _mmar = 0;
void hardfault_handler( void )
{
__asm("tst lr, #4");
__asm("ite eq \n"
"mrseq r0, msp \n"
"mrsne r0, psp");
__asm("b hard_fault_handler_c");
}
void hard_fault_handler_c(unsigned long *hardfault_args){
stacked_r0 = ((unsigned long)hardfault_args[0]);
stacked_r1 = ((unsigned long)hardfault_args[1]);
stacked_r2 = ((unsigned long)hardfault_args[2]);
stacked_r3 = ((unsigned long)hardfault_args[3]);
stacked_r12 = ((unsigned long)hardfault_args[4]);
stacked_lr = ((unsigned long)hardfault_args[5]);
stacked_pc = ((unsigned long)hardfault_args[6]);
stacked_psr = ((unsigned long)hardfault_args[7]);
// configurable fault status register
// consists of mmsr, bfsr and ufsr
_cfsr = (*((volatile unsigned long *)(0xe000ed28)));
// hard fault status register
_hfsr = (*((volatile unsigned long *)(0xe000ed2c)));
// debug fault status register
_dfsr = (*((volatile unsigned long *)(0xe000ed30)));
// auxiliary fault status register
_afsr = (*((volatile unsigned long *)(0xe000ed3c)));
// read the fault address registers. these may not contain valid values.
// check bfarvalid/mmarvalid to see if they are valid values
// memmanage fault address register
_mmar = (*((volatile unsigned long *)(0xe000ed34)));
// bus fault address register
_bfar = (*((volatile unsigned long *)(0xe000ed38)));
__asm("bkpt #0\n"); // break into the debugger
}
为了测试这一点,我创建了以下函数以确保"除以零"将捕获使用错误,但这些使用错误将自动升级为硬故障:
void configureFaultHandling()
{
// Catch all possible faults.
// SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk
// | SCB_SHCSR_BUSFAULTENA_Msk
// | SCB_SHCSR_USGFAULTENA_Msk;
SCB->CCR |= SCB_CCR_DIV_0_TRP_Msk
| SCB_CCR_UNALIGN_TRP_Msk;
}
我在main
的开头添加了以下内容:
void main()
{
configureFaultHandling();
int a = 5 / 0;
}
运行此程序,程序很快就在void hardfault_handler( void )
制动,我可以逐步进入hard_fault_handler_c
并检查寄存器的值。
我发现这些值对应于IAR View -> Stack -> Stack 1
窗格中显示的值。事后看来这是有道理的,因为文档声明在发生故障时某些寄存器的值会被压入堆栈。但是,编写这个函数有助于我弄清楚堆栈中哪些值与哪些寄存器相对应。
为了参考我自己和可能有类似问题的其他人,我在"堆栈1"中找到了第7个值。 (即索引6)对应于异常发生时的程序计数器值。这就是我的样子(right click -> view image
放大):
这样做可以让您找到硬故障的来源,而无需覆盖默认的硬件故障处理程序,只要调试器在发生硬故障时自动中断。
希望这也有助于确定未定义的指令"故障。