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!

artless noise
  • 21,212
  • 6
  • 68
  • 105
JeffV
  • 52,985
  • 32
  • 103
  • 124

5 Answers5

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.

Igor Skochinsky
  • 24,629
  • 2
  • 72
  • 109
  • Thanks Igor, how do I fetch the PC from the stack? – JeffV Sep 22 '10 at 10:30
  • 1
    You need to fetch PSP or MSP and get a word at offset 0x18 from it. See an example implementation here: http://embdev.net/topic/170640#1636052 – Igor Skochinsky Sep 22 '10 at 10:37
  • Still trying to figure this out. Is this offset 24 bytes above the MSP?: uint32_t *pc = (uint32_t *) ((char *)_get_MSP() + 24); – JeffV Sep 22 '10 at 19:42
  • You should do it in assembler, the compiler might adjust the stack value before it gets to your code. – Igor Skochinsky Sep 22 '10 at 21:18
  • 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! – JeffV Sep 22 '10 at 23:48
  • See also http://www.freertos.org/Debugging-Hard-Faults-On-Cortex-M-Microcontrollers.html for a nice hard fault handler implementation. – Étienne Aug 01 '13 at 14:53
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.

starblue
  • 55,348
  • 14
  • 97
  • 151
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.

Richard
  • 131
  • 1
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)

doron
  • 27,972
  • 12
  • 65
  • 103
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.

leppie
  • 115,091
  • 17
  • 196
  • 297
  • 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. – JeffV Sep 21 '10 at 22:23