Posted on:
I'm a little confused about writing a fault handler. I'd like to write
one to track down the occasional crash and display it on my LCD. I'd
guess that most, if not all the faults I see are because of invalid
memory address access (as in, trying to r/w a RAM address that doesn't
exist), so I believe that would be a Bus Fault. I've found there is a
BFAR register I could use, or by looking at the stack by way of a
register, PSP or MSP, although I don't know which one would be valid, or
what the disadvantages of each are. It seems like there's some
conflicting info out there regarding this.
What I have really had trouble with is how to get a register into a C
variable. I've searched the web looking for answer, but nothing that
seems clear. I though I could use
register int x asm("r1")
to get r1 into the variable "x", for example, but I'm not sure if this
will always work. What is a good way to do this in GCC? I've used my
debugger before to view the offending address, but I can't rely on that
(because random crashes never happen when it's connected).
Is there a set of C fault handler functions somewhere that do a good job
of this?
Posted on:
Hi Jerry, this is helpful for you I guess: https://my.st.com/public/STe2ecommunities/mcu/List... The guy who give the hint there has written a very good book, may be you know it already: The definitive guide to the ARM Cortex-M3 I can suggest this book. It is really good.
Posted on:
Jerry Milner wrote: > so I believe that would be a Bus Fault. Look at the fault status registers. > I've found there is a BFAR register I could use, or by looking at the > stack by way of a register, PSP or MSP, although I don't know which > one would be valid, or what the disadvantages of each are. What information are you looking for on the stack? The return address? You will want to find out which stack pointer was used before entering the exception (information in link register). Then look for the return address at the appropriate offset. > What I have really had trouble with is how to get a register into a C > variable. A decent compiler will do a good job allocating registers for variables. > I though I could use > > register int x asm("r1") > > to get r1 into the variable "x", for example, but I'm not sure if this > will always work. What this does is a hardwired mapping of the variable x to the register r1. While this is very useful for special purpose registers (e.g. PSP, MSP), I don't recommend this for general use unless you can explain why exactly you need this. Regards Marcus http://www.doulos.com/arm/
Posted on:
Marcus Harnisch wrote: > What information are you looking for on the stack? The return address? > You will want to find out which stack pointer was used before entering > the exception (information in link register). Then look for the return > address at the appropriate offset. The return address and all the other status informations are found on the stack at a exception. The third posting of my link above gives an example (in 'C') how to get these informations from the stack.
Posted on:
Marcus, I wanted to map a register to a C variable (whichever way is best) so I could have the fault information in a C variable, since often asm is given to extract this information, then left in "r1" for example. 900ss, thanks for the link. This looks like something I would like to try, though they don't say it's for GCC. I'm going to see if I can get it to work.
Posted on:
Hi Jerry Jerry Milner wrote: > Marcus, I wanted to map a register to a C variable (whichever way is > best) so I could have the fault information in a C variable, since often > asm is given to extract this information, then left in "r1" for example. I don't think the mapping using named register variables is what you are looking for. Locate fault status and address via appropriate memory mapped NVIC registers (as you apparently did already) and determine the address of the faulting instruction by retrieving the return address from stack and subtracting 2. The code example posted by 900ss illustrates this approach. -- Marcus http://www.doulos.com/arm/
Posted on:
Hi Jerry, have the code converted to GNU (Codesourcery Toolchain). The assembler code:
.type _hard_fault_handler_asm, %function _hard_fault_handler_asm: TST LR, #4 ITE EQ MRSEQ R0, MSP MRSNE R0, PSP B hard_fault_handler_c |
The C code (modified a little):
// hard fault handler in C, // with stack frame location as input parameter void hard_fault_handler_c(unsigned int * hardfault_args) { unsigned int stacked_r0; unsigned int stacked_r1; unsigned int stacked_r2; unsigned int stacked_r3; unsigned int stacked_r12; unsigned int stacked_lr; unsigned int stacked_pc; unsigned int stacked_psr; unsigned int rBFAR; unsigned int rCFSR; unsigned int rHFSR; unsigned int rDFSR; unsigned int rAFSR; stacked_r0 = ((unsigned long) hardfault_args[0]); stacked_r1 = ((unsigned long) hardfault_args[1]); stacked_r2 = ((unsigned long) hardfault_args[2]); stacked_r3 = ((unsigned long) hardfault_args[3]); stacked_r12 = ((unsigned long) hardfault_args[4]); stacked_lr = ((unsigned long) hardfault_args[5]); stacked_pc = ((unsigned long) hardfault_args[6]); stacked_psr = ((unsigned long) hardfault_args[7]); rBFAR = (*((volatile unsigned long *)(0xE000ED38))); rCFSR = (*((volatile unsigned long *)(0xE000ED28))); rHFSR = (*((volatile unsigned long *)(0xE000ED2C))); rDFSR = (*((volatile unsigned long *)(0xE000ED30))); rAFSR = (*((volatile unsigned long *)(0xE000ED3C))); printf ("[Hard fault handler]\n"); printf ("R0 = %x\n", stacked_r0); printf ("R1 = %x\n", stacked_r1); printf ("R2 = %x\n", stacked_r2); printf ("R3 = %x\n", stacked_r3); printf ("R12 = %x\n", stacked_r12); printf ("LR = %x\n", stacked_lr); printf ("PC = %x\n", stacked_pc); printf ("PSR = %x\n", stacked_psr); printf ("BFAR = %x\n", rBFAR); printf ("CFSR = %x\n", rCFSR); printf ("HFSR = %x\n", rHFSR); printf ("DFSR = %x\n", rDFSR); printf ("AFSR = %x\n", rAFSR); while(1); return; } |
Posted on:
Thanks again 900ss. I'm not too good at doing asm on ARM, especially the GCC syntax.