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

问题描述 投票:1回答:2

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();
}
arm cortex-m
2个回答
0
投票

在Cortex-M中,PC实际上不可能是0xffffffff,寄存器中只有物理位[31:1]。当您观察到地址为0xfffffffe的执行时,这是一个'LOCKUP'地址,这是一个archtectural livelock状态(是一个无效的提取地址,它强制PC到锁定地址,这是一个无效的提取地址)。

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

要调试Cortex-M锁定方案,查看堆栈很重要,但您无法确定上次成功堆叠的内容。您也无法确定故障的顺序,但有一个合理的假设是在故障处理程序期间发生了故障(LOCKUP意味着异常模型超出了其他选项)。

首先要检查的是这些堆叠的PC值与代码有什么关系,以及与您尝试触发ISR相关的位置。也许你的main()已经返回(它什么也没做),这个0x1452是一个UNDEF。工具链有3个选项,用于'after main()',循环永久,崩溃,或者只是继续执行任意指令。除非您拆卸/逐步浏览图像,否则这不会很明显。


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寄存器。

© www.soinside.com 2019 - 2024. All rights reserved.