Cortex-M3 development experience (three): Print the stack information HardFault
In the "Cortex-M3 development experience (two): Confirm local occurrence of HardFault", we mentioned how to find the wrong place. But it has a problem that must be linked debugger. So in some cases, we can not connect the debugger, you will not be able to read the stack information yet? We can when entering HardFault, get the stack pointer, then print out the way it through the serial port?
Went ahead and have good ideas, there must also be practical action to verify their ideas.
How to get the stack pointer?
We stuck our first question is how to get the stack pointer. Is how to obtain the SP,, PSP (process stack pointer) the value of the MSP (main stack pointer) a.
In the "Cortex-M3 Definitive Guide", there are so many words: CM3 There are two microcontroller core stack pointer, so that is supported by two stacks, when referring to R13 (writing SP), is a reference to the currently that one (MSP or PSP) used, the other must use special instructions to access (MRS and MSR instructions).
In other words, we need to use assembler instructions to get the stack pointer.
uint32_t get_msp_addr()
{
__asm("mrs r0, msp");
__asm("bx lr");
}
uint32_t get_psp_addr()
{
__asm("mrs r0, psp");
__asm("bx lr");
}
uint32_t get_sp_addr()
{
__asm("mov r0, sp");
__asm("bx lr");
}
NOTE: C different for each embedded assembly supported compiler, some compilers may __asm is not supported.
Acquired by the kernel stack pointer register value
uint32_t reg_buff[10];
uint32_t *sp = NULL;
void HardFault_Handler()
{
sp = (uint32_t*)get_msp_addr();
reg_buff[0] = *(sp++);
reg_buff[1] = *(sp++);
reg_buff[2] = *(sp++);
reg_buff[3] = *(sp++);
reg_buff[4] = *(sp++);
reg_buff[5] = *(sp++);
reg_buff[6] = *(sp++);
reg_buff[7] = *(sp++);
reg_buff[8] = *(sp++);
reg_buff[9] = *(sp++);
while(1){}
}
Compile and run!
The results somewhat unexpected!
LR value and the value of the PC before stepping do not like us! Offset of 12 bytes. why? Looked back and found a single step, we call this function in the get_msp_addr HardFault in, and call the function it implies the use of stack space. If I reg_buff HardFault put in, so that more than offset a 12 bytes!
There is no better way ah! ?
Before we get into the HardFault_Handler function on the value of the SP pointer, and pass as an argument to HardFault_Handler not can it?
Who calls the interrupt handler?
To solve the above problem, we need to know where to call to the kernel interrupt function, so that we can modify the corresponding interrupt handler, so that it can receive arguments.
"Cortex-M3 development experience (two): Confirm local occurrence of HardFault" we mentioned, the interruption / exception, the kernel to interrupt find the corresponding interrupt vector table, find the entry address of interruption. Then we look at what interrupt vector table?
Finally, we find the definition of the vector table in startup_xxx.S file 1 . We also find the definition of HardFault_Handler
.weak HardFault_Handler
.type HardFault_Handler, %function
HardFault_Handler:
B .
Although the compilation may not understand, I do not know what that means, but also to guess about the meaning, may also find information. B is found a jump instruction, this should jump to the C function of the same name. Then we can modify as follows:
.weak HardFault_Handler
.type HardFault_Handler, %function
HardFault_Handler:
MOV r0, lr
MOV r1, sp
BL hardfault_handler
This value SP and the value of LR passed to the function hardfault_handler went 2 .
Compile and run!
The result is what we want.