我开始使用TivaWare时最沮丧的事情之一(当时的StellarisWare) 在FaultISR()中结束时,我在尝试使用外围设备或其它类似问题之前未启用外围设备,而是不得不单步浏览我的源代码以找到它出错的位置。 标准建议(1)似乎是解密 NVIC_FAULTSTAT和 NVIC_FAULTDDR寄存器中的值,然后手动解码中断堆栈以确定导致故障的指令之后的指令地址(2)。 我已经这样做了,但99 % 当时使用修改的FaultISR(),我可以用更少的工作来发现问题,如下所示:
static void
FaultISR(void)
{
volatile int i = 1;
while(i)
{
}
}
使用此实现,当您暂停调试器并发现您在FaultISR()中时,通常可以如下所示找到原因:
- 使用调试器的变量视图将I的值更改为0,这样它将退出循环。
- 单击C步入按钮(通常两次),直到调用栈显示从底部变为第二个显示main()。
- 单击调用栈中从顶部开始的第二个项目。 它应显示您的源代码。
- 查看指示前的说明。 可能是导致故障的原因。
我建议TI将FaultISR()的默认实现更改为类似的方式。 我使用的版本中也有许多注释;我将在下面添加(3)。
更好的是,也许可以更改调试器,以便它能够从中断服务例程中解码堆栈跟踪。 我意识到通过输入ISR推入的堆栈帧与函数的堆栈帧不同,因此需要有一些方法来解密要使用的解码方法。 如果在一般情况下不能自动执行此操作,我可以设想一种方法,让用户提供一个提示(可能使用复选框),即特定的堆栈帧是用于ISR的。 也许调试器可以维护一个符号名称的列表,这些符号名称都是以这种方式标记的,这样它就知道下次也会将它们视为ISR。 该列表可能默认包含已知ISR,如FaultISR(),NmiISR()和ResetISR(),也可能使用g_pfnVectors []中的条目进行初始化。 这样,新用户就可以立即看到他们的错误所在;我的猜测是这样做可以消除本论坛中有关FaultISR()的许多问题。 即使存在嵌套ISR (处理低优先级中断时发生的高优先级中断)和调用函数的ISR,也应该可以对堆栈进行解码。
我应该注意,如果有东西覆盖堆栈(堆栈太小,缓冲区溢出等),调用堆栈将被损坏,这些方法都不能解决问题。 下面是一些有关检测堆栈溢出的源代码注释(再次为3)。
Steve
(2)- SPMA043介绍如何手动解码堆栈跟踪。 我将尝试在后续帖子中包括一个示例。 /cfs/file/__key/communityserver-discussions-组件-files/908/0842.spma043_2D00_Diagnosing-Software-Faults-in-Stellaris_AE00_-Microcontrollers.pdf
(3)- FaultISR()的完整版本。 与我上面所说的大多数不同之处是评论,有些不适用于其他人。 可以添加注释,说明未初始化的外围设备是导致FaultISR()终止的常见原因。
//*****************************************************************************
//
// This is the code that gets called when the processor receives a fault
// interrupt. It prints any queued debug messages (including tracepoints)
// then enters an infinite loop, preserving the system state for examination
// by a debugger.
//
// If have trouble figuring out why we get here, check to see if there is a
// way to see which vector was used. Could also make multiple ISRs and make
// each suspect vector point to a different one. Update: it looks like FaultISR(),
// unlike IntDefaultHandler(), is pointed to by only one vector. Might still
// be able to look at register values and determine what triggered the "hard fault".
// - Also consider setting a global to different values at various places in the
// code so can check its value here and see which of those places it was last set.
// Perhaps use a macro that sets a "checkpoint" (pointer to the filename or
// maybe function name and an int to the line number). Search for
// "ktowyawesctlcic". Todo.
//
//*****************************************************************************
static void
FaultISR(void)
{
// Print messages before going into infinite loop. If the COP watchdog is
// enabled, this printing probably would have happened in a bit anyway when
// watchdogTimeoutISR() got called.
extern volatile uint32_t sysTickMillisecondCount; // defined in sysTick2.c
blockWhilePrintAllDebugMessages( sysTickMillisecondCount, "FaultISR" );
//
// Enter an infinite loop.
//
// There are a couple of ways to (sometimes) determine which code was running
// when the fault occurred:
// - Exit this loop and single-step out of this ISR to the calling code.
// To trace back out of this ISR, use debugger to change the value
// of i to 0, then click the "Assembly Step Into" button several times
// (usually 4 to 6) or try the C step-into button.
// - See "Debugging - tracing how got into ISR.docx" for how to inspect
// the stack by hand and modify the PC to make the debugger show the calling
// code.
//
// If unable to trace back out, it may be because the stack got hammered.
// - It could be that the stack is too small and is overflowing.
// - There is a process for checking the available stack space documented
// in the firmware release procedure.
// - You can set a watchpoint on __stack as described in
// processors.wiki.ti.com/.../Watchpoints_for_Stellaris_in_CCS
// to get the debugger to stop at the point the stack overflows.
// - It could be that the stack frame is being overwritten even if the stack
// itself is not overflowing.
// - Can hammer the stack frame without overflowing the stack. For
// example, could have a local array on the stack and overflow it.
// - The stack pointer itself could get changed to an invalid location.
//
// Other possible ways to get clues about the cause:
// - Look at contents of stack for clues (like strings).
// - Enable IF_DEBUG_LOCKUPS_USING_TRACEPOINTS_MAIN_LOOP and similar code
// to help track down where the buffer overflow is occurring. Search for
// "ktowyawesctlcic".
// - Acquire a "reverse debugger" (perhaps using debug hardware with trace)
// so can look back to the point it all went wrong.
//
volatile int i = 1;
while(i)
{
}
}