HardFault异常(HardFault的可配置优先级异常)

时间:2019-04-20 16:28:18

标签: arm cortex-m

stack contents我编写了一个简单的IO中断例程,以测试ARM cortex m4(cm408F)中的IO引脚。代码在下面,非常简单,并填充了向量表(还包括弱实用注解和其他内容)。

我通过设置NVIC_ISER0和NVIC_ISPR0中的相应位来强制中断。发出中断的那一刻,处理器给我以下硬故障异常,并陷入了L1引导ROM的循环中。

处理器已将可配置优先级异常升级为HardFault。 使用无效的EPSR.T或EPSR.IT字段(CFSR.INVSTATE)执行的指令。 在PC = 0xffffffff,LR = 0x0时发生异常

在调用堆栈窗口中,我看到:

__iar_systems$$modulde + 0x1451

这可以帮助吗?

我还为HardFault_Handler添加了while(1)循环。 因此,如果处理器实际上断言了HardFault_Handler,则它应该进入这个无穷循环,但永远不会在那里。激活哪个中断都无关紧要(通过NVIC_ISER0和NVIC_ISPR0),会发生相同的问题(收到中断后,它会跳转并卡在L1引导ROM行中的循环中:1452!)。

一旦引发中断,我就会附加一个堆栈快照。在引发中断之前,我已经进行了更改 R12和R0-R3的内容(0x1238 .... 0x1234),以便在堆栈中更好地实现它们。就像我说的 当引发中断时,程序再也不会返回,所以我暂停了它,然后看了看堆栈(附图)。 似乎第一按就好;我们可以看到xPSR,PC,LR,R12,R0至R3都正确堆叠(禁用了FPU)。 但是在第二次压入堆栈PC时为零(LR很好)!我想这说明了问题。 PC不应为零。 为什么不通过将正确的返回地址地址推送到PC来使其不从中断返回。我猜第三 推入堆栈是此问题的结果。

在中断之前:SP = 0x2005FFF0 中断后:SP = 0x2005FFA4

............................

// My code is very simple as follows.    
// main.c
#include <intrinsics.h>

int main()
{



  int k1=123; 
  k1=k1+2*k1;


  while(1)
  {
    k1=k1;
  }

  return 0;
}

// =========================================

// my_int_Routines.c

void PINT0_BLOCK_Int_Handler(void)
{
    while(1)
  {
     asm("nop");
  }

}

void PINT1_BLOCK_Int_Handler(void)
{
    while(1)
  {
    asm("nop");
  }

}

void PINT2_BLOCK_Int_Handler(void)
{
    while(1)
  {
        asm("nop");
  }

}

void PINT3_BLOCK_Int_Handler(void)
{
    while(1)
  {
    asm("nop");
  }

}

void PINT4_BLOCK_Int_Handler(void)
{
    while(1)
  {
    asm("nop");
  }

}

// =====================================

// my_startup.c
// This is ARM standard cstartup.c in IAR folder. I only added the relevant lines 
// (marked as Reza)

/**************************************************
 *
 * This file contains an interrupt vector for Cortex-M written in C.
 * The actual interrupt functions must be provided by the application developer.
 *
 * Copyright 2007-2017 IAR Systems AB.
 *
 * $Revision: 112610 $
 *
 **************************************************/

#pragma language=extended
#pragma segment="CSTACK"

extern void __iar_program_start( void );

extern void NMI_Handler( void );
extern void HardFault_Handler( void );
extern void MemManage_Handler( void );
extern void BusFault_Handler( void );
extern void UsageFault_Handler( void );
extern void SVC_Handler( void );
extern void DebugMon_Handler( void );
extern void PendSV_Handler( void );
extern void SysTick_Handler( void );

extern void   PINT0_BLOCK_Int_Handler(void);  //  18  Pin Interrupt Block  Reza
extern void   PINT1_BLOCK_Int_Handler(void);  //  19  Pin Interrupt Block  Reza
extern void   PINT2_BLOCK_Int_Handler(void);  //  20  Pin Interrupt Block  Reza
extern void   PINT3_BLOCK_Int_Handler(void);  //  21  Pin Interrupt Block  Reza
extern void   PINT4_BLOCK_Int_Handler(void);  //  22  Pin Interrupt Block  Reza

typedef void( *intfunc )( void );
typedef union { intfunc __fun; void * __ptr; } intvec_elem;

// The vector table is normally located at address 0.
// When debugging in RAM, it can be located in RAM, aligned to at least 2^6.
// If you need to define interrupt service routines,
// make a copy of this file and include it in your project.
// The name "__vector_table" has special meaning for C-SPY, which
// is where to find the SP start value.
// If vector table is not located at address 0, the user has to initialize
// the  NVIC vector table register (VTOR) before using interrupts.


#pragma location = ".intvec"
const intvec_elem __vector_table[] =
{
  { .__ptr = __sfe( "CSTACK" ) },
  __iar_program_start,

  NMI_Handler,
  HardFault_Handler,
  MemManage_Handler,
  BusFault_Handler,
  UsageFault_Handler,
  0,
  0,
  0,
  0,
  SVC_Handler,
  DebugMon_Handler,
  0,
  PendSV_Handler,
  SysTick_Handler,
// *******  Reza (all zeros below)
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0, 
  PINT0_BLOCK_Int_Handler,  //  18   Pin Interrupt Block  Reza
  PINT1_BLOCK_Int_Handler,  //  19  Pin Interrupt Block   Reza
  PINT2_BLOCK_Int_Handler,  //  20  Pin Interrupt Block   Reza
  PINT3_BLOCK_Int_Handler,  //  21  Pin Interrupt Block   Reza
  PINT4_BLOCK_Int_Handler  //   22  Pin Interrupt Block   Reza
};

#pragma call_graph_root = "interrupt"
__weak void NMI_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void HardFault_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void MemManage_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void BusFault_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void UsageFault_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void SVC_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void DebugMon_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void PendSV_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void SysTick_Handler( void ) { while (1) {} }
// ======================  Reza
#pragma call_graph_root = "interrupt"
__weak void PINT0_BLOCK_Int_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void PINT1_BLOCK_Int_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void PINT2_BLOCK_Int_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void PINT3_BLOCK_Int_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void PINT4_BLOCK_Int_Handler( void ) { while (1) {} }

void __cmain( void );
__weak void __iar_init_core( void );
__weak void __iar_init_vfp( void );

#pragma required=__vector_table
void __iar_program_start( void )
{
  __iar_init_core();
  __iar_init_vfp();
  __cmain();
}

2 个答案:

答案 0 :(得分:0)

在Cortex-M中,实际上PC不可能为0xffffffff,实际上寄存器中只有[31:1]位。当您观察到似乎位于地址0xfffffffe的执行时,这是“ LOCKUP”地址,它是一种体系结构的活锁状态(由于是无效的提取地址,它将强制PC进入锁定地址,这是一个无效的提取地址)。

一旦处于锁定状态的锁定地址,唯一的出路就是使用调试器更换PC或重置内核。

要调试Cortex-M锁定方案,重要的是要查看堆栈,但不能确定最后成功堆栈的是什么。您也不能确定故障的顺序,但是可以合理地假设在故障处理程序期间发生了故障(LOCKUP表示异常模型不在其他选项之内)。

首先要检查的是这些堆叠的PC值与代码中的内容有关,以及与试图触发ISR的内容有关的地方。也许您的main()已经返回(不执行任何操作),并且此0x1452是UNDEF。工具链具有3个选项,用于“ after main()”,永久循环,崩溃或仅通过任意指令进行运行。除非您分解/逐步浏览图像,否则这将不明显。

答案 1 :(得分:0)

我指的是规范, http://infocenter.arm.com/help/topic/com.arm.doc.ddi0439b/DDI0439B_cortex_m4_r0p0_trm.pdf

这里提到向量表的默认位置是0x00000000,必须在VTOR寄存器中提及。 如果未修改该寄存器,则在收到中断后,CPU将读取LOC1的内存地址:0x00000000 +对应于中断号的一些偏移量,然后跳转到LOC1。

现在我的猜测是,ISR的位置不正确,并且LOC1的设置不正确,而是包含一些垃圾值0x00001452。 现在,CPU读取并跳转到该位置。

我认为您可以通过以下方式解决此问题,

以这样的方式配置链接器:将ISR放置在适当的位置,并为LOC1填充适当的值。此外,您可能需要为VTOR寄存器配置一些自定义的值。