我目前在STM32F4上遇到一些问题,进程“挂起”,我无法理解它在什么时候“锁定”。发生这种情况时,我为以下变量收集了以下值(我创建了变量stepError来“翻译” CFSR变量):
void prvGetRegistersFromStack (uint32_t * pulFaultStackAddress)
{
volatile uint32_t CFSRValue = SCB-> CFSR;
volatile uint32_t HFSRValue = SCB-> HFSR;
char stepError [1024] = "";
if ((HFSRValue & (1 << 30)) = 0) {
CFSRValue >> = 16;
if ((CFSRValue & (1 << 9)) = 0) strcpy (stepError, "Divide by zero");
if ((CFSRValue & (1 << 8))! = 0) strcpy (stepError, "Unaligned access");
if ((CFSRValue & (1 << 3)) = 0) strcpy (stepError, "No UsageFault coprocessor");
if ((CFSRValue & (1 << 2)) = 0) strcpy (stepError, "Invalid PC load UsageFault");
if ((CFSRValue & (1 << 1))! = 0) strcpy (stepError, "Invalid state");
if ((CFSRValue & (1 << 0))! = 0) strcpy (stepError, "Undefined instruction");
}
/ * These are volatile to try and prevent the compiler / linker optimizing them
away the variables never actually get used. If the debugger will not show the
values of the variables, make them global my moving their declaration outside
of this function. * /
volatile uint32_t r0;
volatile uint32_t r1;
volatile uint32_t r2;
volatile uint32_t r3;
volatile uint32_t r12;
volatile uint32_t lr; / * Link register. * /
volatile uint32_t pc; / * Program counter. * /
volatile uint32_t psr; / * Program status register. * /
r0 = pulFaultStackAddress [0];
r1 = pulFaultStackAddress [1];
r2 = pulFaultStackAddress [2];
r3 = pulFaultStackAddress [3];
r12 = pulFaultStackAddress [4];
lr = pulFaultStackAddress [5]; // Bit (2 or 3) = 0 determines MSP (Main Stack Pointer); 1 = PSP (Process Stack Pointer)
pc = pulFaultStackAddress [6]; // Variable that contains the address where the error occurred. To check where it was, search the Disassembly on the screen Debug the address
psr = pulFaultStackAddress [7];
/ * When the following line is hit, the variables contain the register values. * /
// Joseph Yiu:
/ *
1) Look at LR value when the core enter hardfault, if bit 2 is 0, then read the value of MSP. Otherwise, read the value of PSP.
2) Based on the MSP / PSP value, you should be able to locate the start of stack frame, stacked PC is in address SP + 24.
3) Generate a disassembled listing of the program you run, and try to locate the stack PC address in the disassembled program list.
* /
GPIO_WriteLed (0,1);
for (int i = 0; i <= 10; i ++)
{
PWM_Change_DutyCycle (i, 0);
}
for (;;);
}
HFSRValue 1073741824 CFSRValue 0 StepError 0x2001fbb0“”
r0 0 r1 0 r2 0 r3 11
r12 536890019 lr 134334773 pc 0x0801bab0 psr 3221225472
但是我不能从这些值中知道错误发生的位置,它是由USB,串行,编码器还是ADC转换器等引起的。如何实现 void HardFault_Handler(void) ,这样我就可以识别出错误发生在哪里?
答案 0 :(得分:1)
您可以从异常堆栈帧中找到导致错误的指令/功能的地址:
在您提供的示例中,这似乎已经传递给了您作为prvGetRegistersFromStack
参数发布的pulFaultStackAddress
函数。当您有兴趣找出导致HardFault的代码的哪一部分时,可以在已堆叠的PC
和LR
中找到它们-在您的示例中,这些内容取自{{1} }和pulFaultStackAddress[6]
。
pulFaultStackAddress[5]
应该包含程序计数器,它是发生故障时正在执行的指令。 PC
应该包含链接寄存器值,该值是返回地址,或者换言之-调用子例程/函数的地址。
您已发布这些值是:LR
和pc 0x0801bab0
(十六进制为0x801C935)。这两个值都是STM32F407ZE内部闪存中的有效地址,因此我们可以假定它们是有效的。剩下的就是将内存地址转换回源代码中的行。这样做的两个例子:
使用您的IDE
如今,大多数IDE都具有“反汇编”视图。在窗口->显示视图->其他->调试->反汇编下,可以使用常用的基于Eclipse的工具(例如SW4STM32或TrueSTUDIO for STM32)。 IAR也有一个。打开后,在调试过程中将内存地址(例如lr 134334773
(即0x0801bab0
值)粘贴到框中,然后按Enter。那应该向您显示与源代码行交错的相应反汇编。那应该让您了解HardFault发生的位置。
另一种方法是..
使用您的工具链
工具链还具有命令行工具,可让您执行与上述选项相同的操作。举个例子,我假设您正在使用PC
。在那里,您可以使用arm-none-eabi
将内存地址转换回源代码行:
addr2line
其中arm-none-eabi-addr2line.exe -e [your executable].elf -i 0x0801bab0
是您已加载到MCU上的ELF文件的路径。 [your executable]
开关尝试展开内联函数,这有时有助于更好地了解调用的来源。
无论选择哪种方法,都可以对-i
值(发生故障的地址)和PC
(呼叫者)进行相同的操作。