ARM Cortex M3 How do I determine the program counter value before a hard fault?
Asked Answered
P

5

6

I have an embedded project using a STM32F103 (ARM Cortex M3), it is getting a occasionally getting hard fault in release mode. As part of recovery, I would like to retrieve the PC value from before the hard fault and store it for later debugging in the battery backed region.

How would I determine the value of the program counter at the point of the hard fault? Obviously, the PC is now set to its location within the hardfault interrupt.

Where should I look? It there an address for the normal mode register bank?

Thanks!

Pender answered 21/9, 2010 at 20:16 Comment(1)
I would like to know too, but you might get a better answer on chiphacker.com.Potsherd
B
6

Cortex-M3 uses a quite different model of exception handling from the "classic" ARM, e.g. it doesn't have "abort mode" mentioned in the other post. I suggest you to read this app note. For example, for the Hard Fault:

The value of SCB->BFAR indicates the memory address that caused a Bus Fault and is valid if the bit BFARVALID in the SCB->CFSR register is set. The value of SCB->MMFAR indicates the memory address that caused a Memory Management Fault and is valid if the bit MMFARVALID in the SCB->CFSR register is set.

To determine the PC value at the time of exception you need to examine the stack; the processor pushes R0-R3, R12, PC and LR before executing the handler. The stack used can be either Main (if bit 2 of LR is 0) or Process (otherwise). See page 13 of the app note for details.

Bagwell answered 22/9, 2010 at 9:31 Comment(6)
Thanks Igor, how do I fetch the PC from the stack?Pender
You need to fetch PSP or MSP and get a word at offset 0x18 from it. See an example implementation here: embdev.net/topic/170640#1636052Bagwell
Still trying to figure this out. Is this offset 24 bytes above the MSP?: uint32_t *pc = (uint32_t *) ((char *)_get_MSP() + 24);Pender
You should do it in assembler, the compiler might adjust the stack value before it gets to your code.Bagwell
Yes, I'm seeing that. Just correcting for the offset and getting the proper PC value now. I'll need to test in release mode to ensure the offset doesn't change. Thanks again!Pender
See also freertos.org/… for a nice hard fault handler implementation.Krieg
P
3

You should look into the ARM Architecture Reference Manual in the section on Exceptions. You need to register to get it.

Typically a relevant address will be put in the link register LR (R14), but the precise meaning varies according to the exception, and there are varying offsets.

W.r.t. accessing the User/System mode register bank, I think you need to switch the mode to access it.

Precast answered 21/9, 2010 at 20:31 Comment(3)
Ahh, cool! Just checked it while debugging (have no clue how to invoke a hard fault currently ;p ) and it indeed shows the address of the caller. Thanks a lot!Potsherd
OK, I see it is not the caller, but the return address.Potsherd
I generated the hard fault by: *((char *)0x00) = 5;Pender
L
1

When an exception occurs, the processor state change from the current state to the abort state. In the abort state the processor shifts to use a new set of registers for sp and lr (sp_abt and sp_lr respectively. For a data abort, the offending instruction can be found in lr_abt + 8 for an prefect about in lr_abt + 4 (as per the ARMv7 Architecure reference manual)

Leacock answered 21/9, 2010 at 20:49 Comment(3)
changed sp_abt to lr_abt quite a bad mistake on my part - fixed nowLeacock
This is valid for classic ARM but not Cortex-M3Bagwell
I think you meant lr_abt-8 and lr_abt-4.Krieg
S
1

I have an FAQ on this very topic. The page linked to from the FAQ includes fault handler code that will obtain the program counter from the stack for you.

Spacetime answered 12/6, 2013 at 5:43 Comment(0)
P
0

I found a common cause for these issues are those 'for loop' delays. When using -O3 they simply get optimized away if you are are not referring to volatile variables. Personally, I prefer the SysTick approach.

Potsherd answered 21/9, 2010 at 20:31 Comment(1)
Thanks @leppie, whole heartedly agree. No for loop delays here, I;m also using SysTick for my counting. Every thing is in a state machine as well, to avoid blocking. I think the problem would present itself in debug mode if I gave it enough time.Pender

© 2022 - 2024 — McMap. All rights reserved.