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();
}
答案 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寄存器配置一些自定义的值。