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

时间:2017-07-04 13:23:08

标签: arm microcontroller lpc

我正在为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用于更大的版本):

1 个答案:

答案 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放大):

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

希望这也有助于确定未定义的指令"故障。