2
votes

I am currently debugging a hard fault trap which turned out to be a precise data bus error on a STM32F205 Cortex-M3 processor, using Keil uVision. Due to a lengthy debugging and googling process I found the assembly instruction that caused the trap. Now I am looking for a way to avoid this lengthy process next time a trap occurs.

In the application note 209 by Keil it says:

PRECISEERR: Precise data bus error: 0 = no precise data bus error 1 = a data bus error has occurred, and the PC value stacked for the exception return points to the instruction that caused the fault. When the processor sets this bit it writes the faulting address to SCB->BFAR

and also this:

An exception saves the state of registers R0-R3, R12, PC & LR either the Main Stack or the Process Stack (depends on the stack in use when the exception occurred).

The last quote I am interpreting as such that there should be 7 registers plus the respective stack. When I look up my SP address in the memory I see the address that caused the error at an address 10 words higher than the stack pointer address.

My questions are:

  • Is the address of the instruction that caused the trap always saved 10 words higher than the current stack pointer? And could you please point out a document where I can read up on how and why this is?

  • Is there another register that would contain this address as well?

2
I think on a cortex-m the hardware pushes some number of registers for you so the handler doesnt have to that is one of the new things they added, so yes the hardware will do the same thing every time for each type of handler. What software does after that (which it doesnt need to add any more usually other than that the compiler needs for that function) is specific to that functionold_timer
if you are examining the stack I assume you are using asm which means you should know how many items you added to the top of the stack?old_timer
Most of the project is written in C, some of it is written in asm, however. The HardFault_Handler is written in C. But for this type of issue I do have to analyse the disassembly to find which variable on the stack represents the programme counter from when the trap was triggered.David Wright
yeah so you cant really rely on the exact offset, same code compiled with different options or a different version of the compiler or even one line of code changed could vary the stack by the time you get to the middle of the function.old_timer

2 Answers

1
votes

The precise stack location of the return address depends on how much stack the interrupt handler requires. If you look at the disassembly of your HardFault_Handler, you should be able to see how much data is stored on the stack / how many registers are pushed in addition to the registers pushed by the hardware interrupt machinery (R0-R3, R12, PC, LR & PSR)

I found this to be a pretty good idea on how to debug Hard Faults, though it requires a bit of inline assembly.

2
votes

As you said, exceptions (or interrupts) on ARM Cortex-M3 will automatically stack some registers, namely :

  • Program Counter (PC)
  • Processor Status Register (xPSR)
  • r0-r3
  • r12
  • Link Register (LR).

For a total of 8 registers (reference : Cortex™-M3 Technical Reference Manual, Chapter 5.5.1).

Now, if you write your exception handler in a language other than assembly, the compiler may stack additional registers, and you can't be sure how many.

One simple solution is to add a small code before the real handler, to pass the address of the auto-stacked registers :

void myRealHandler( void * stack );

void handler(void) {
    asm volatile("mov r0, sp");
    asm volatile("b myRealHandler");
}

The register BFAR is specific to bus faults. It will contain the faulty address, not the address of the faulty instruction. For example, if there was an error reading an integer at address 0x30005632, BFAR will be set to 0x30005632.