cancel
Showing results for 
Search instead for 
Did you mean: 

HardFault Exception: Why oh why??!

relaxe
Associate II
Posted on January 14, 2010 at 08:41

HardFault Exception: Why oh why??!

17 REPLIES 17
relaxe
Associate II
Posted on May 17, 2011 at 12:55

On my journey to adapt DosFS, I've kept having one problem: my STM3210E-EVAL keep going into this interrupt function:

/*******************************************************************************

* Function Name : HardFaultException

* Description : This function handles Hard Fault exception.

* Input : None

* Output : None

* Return : None

*******************************************************************************/

void HardFaultException(void)

{

/* Go to infinite loop when Hard Fault exception occurs */

while (1)

{}

}

===========================

However, I've searched all around, and never found out what exactly is a hardfault exception...

So, what is it?

How can one reproduce it?

Is it documented?

What can one deduce from a hardfault?

How can one track down exactly why is a hardfault happening?

I guess you get my drift...

Thanks!

-Relaxe

abraxa
Associate II
Posted on May 17, 2011 at 12:55

I'm facing the exact same problem. For my code, it's related to sprintf():

Code:

char s[10];

sprintf(s, ''X'');

works just fine, however a

Code:

char s[10];

int v;

sprintf(s, ''%d'', v);

generates several hard fault exceptions. The debugger kinda sucks (HiTOP 5.2) so I usually can't perform any kind of tracing. I just see that the exception occurs, though at one point I did see that it might be triggered by statements like ''str r5, [r3, #10]'' within _sinit(). Why, I have no idea.

I'm tempted to think that memory management might be the culprit since malloc() always returns 0. Is that the case for you as well?

relaxe
Associate II
Posted on May 17, 2011 at 12:55

Oops, posted too fast!

I just found this:

http://infocenter.arm.com/help/topic/com.arm.doc.ddi0337e/DDI0337E_cortex_m3_r1p1_trm.pdf

This M3-Cortex reference manual covers what/when and where causes hardfaults

-Relaxe

relaxe
Associate II
Posted on May 17, 2011 at 12:55

Oh yeah, I had problem with malloc too... I just did without, but still, it generated hardfault on IAR 5.20 too..

abraxa
Associate II
Posted on May 17, 2011 at 12:55

Personally I didn't find the TRM very helpful about the hard fault exceptions, which is why I didn't mention it. ''All classes of Fault'' isn't exactly precise 🙂

As for malloc(), I'm tempted to think in the direction of

http://www.st.com/mcu/forums-cat-7542-23.html

but I haven't yet figured out what the solution is for me (GCC 4.3.0).

relaxe
Associate II
Posted on May 17, 2011 at 12:55

Well, abraxa, seems you were right: the core manual does not properly guides anybody around....

However, this thread seems to provide a better insight:

http://www.st.com/mcu/forums-cat-6778-23.html

Still, I have absolutly no clue on how to use this code in IAR 5.20 with the ST firmware lib.

Let me copy/paste the code I would like to adapt:

==================================== FROM joseph.yiu================

You need an assembly wrapper code to extract the stack frame location:

(The following embedded assembler works with RealView Development suite,

and should also work with KEIL RealView-MDK).

// hard fault handler wrapper in assembly

// it extract the location of stack frame and pass it

// to handler in C as pointer.

__asm void hard_fault_handler_asm(void)

{

IMPORT hard_fault_handler_c

TST LR, #4

ITE EQ

MRSEQ R0, MSP

MRSNE R0, PSP

B hard_fault_handler_c

}

And then you can extract the stacked registers in C:

// 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;

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]);

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'', (*((volatile unsigned long *)(0xE000ED38))));

printf (''CFSR = %x\n'', (*((volatile unsigned long *)(0xE000ED28))));

printf (''HFSR = %x\n'', (*((volatile unsigned long *)(0xE000ED2C))));

printf (''DFSR = %x\n'', (*((volatile unsigned long *)(0xE000ED30))));

printf (''AFSR = %x\n'', (*((volatile unsigned long *)(0xE000ED3C))));

exit(0); // terminate

return;

}

But this will only work if the main stack pointer is still in valid region when the fault happen. Otherwise your C handler might not work.

=============================================================

If anybody knows how to adapt this code, it would be appreciated a lot!

-relaxe

relaxe
Associate II
Posted on May 17, 2011 at 12:55

Oh well....

/*******************************************************************************

* Function Name : HardFaultException

* Description : This function handles Hard Fault exception.

* Input : None

* Output : None

* Return : None

*******************************************************************************/

void HardFaultException(void)

{

//Big thanks to joseph.yiu for this handler. This is simply an adaptation of:

//http://www.st.com/mcu/forums-cat-6778-23.html

//****************************************************

//To test this application, you can use this snippet anywhere:

// //Let's crash the MCU!

// asm ('' MOVS r0, #1 \n''

// '' LDM r0,{r1-r2} \n''

// '' BX LR; \n'');

// Note that this works as-is in IAR 5.20, but could have a different syntax

// in other compilers.

//****************************************************

// hardfault_args is a pointer to your stack. you should change the adress

// assigned if your compiler places your stack anywhere else!

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;

u32* hardfault_args = (u32*) 0x20000400;

asm( ''TST LR, #4 \n''

''ITE EQ \n''

''MRSEQ R0, MSP \n''

''MRSNE R0, PSP \n'');

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]);

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'', (*((volatile unsigned long *)(0xE000ED38))));

printf (''CFSR = %x\n'', (*((volatile unsigned long *)(0xE000ED28))));

printf (''HFSR = %x\n'', (*((volatile unsigned long *)(0xE000ED2C))));

printf (''DFSR = %x\n'', (*((volatile unsigned long *)(0xE000ED30))));

printf (''AFSR = %x\n'', (*((volatile unsigned long *)(0xE000ED3C))));

while (1)

{}

}

relaxe
Associate II
Posted on May 17, 2011 at 12:55

Well, seems this is starting to look like a personnal blog... but anyway:

I've found my much dreaded problem.

First, the above handler did show nothing on my particular problem. It hanged at the top of the function, meaning it does no fit into the simpler error models.

I was using a private variable (512bytes wide) declared in main(). I passed the pointer to that buffer to many layers of functions, down to a SDIO -> DMA -> buffer function. Somehow, another private variable probably got initialised over the same buffer adress, causing mayhem.

The solution was simply to declare the ''u8 bufffer[512]'' as ''static u8 buffer[512]''.

Then, no other functions wrote over it.

So, conclusion: if you have hardfaultexceptions, try to declare your multi-layer-pointed-to-buffers as static variables.

-Relaxe

joseph239955
Associate II
Posted on May 17, 2011 at 12:55

Hi Relaxe,

Regarding malloc(), you might need to check if the heap memory is defined correctly in your project. In KEIL RealView-MDK you can define it in the startup code. I don't know how this is done in IAR.

Thanks for porting the fault handler to IAR.

One thing could you double check: could you have a look at the disassmbled code of the starting of the handler? The reason is that I wonder if the IAR compiler will insert some PUSH operations before the inline assembly code. If it does, then the offset of the registers might become different as the value of MSP has changed before the inline assembly code executed.

If this happen, you might need to change the inline assembler to

asm( ''TST LR, #4 \n''

''ITTE EQ \n''

''MRSEQ R0, MSP \n''

''ADDEQ R0, #8 \n'' (asssume two pushes is carried out before getting here)

''MRSNE R0, PSP \n'');

If your IAR project has an assembly based startup code, then it might be easier to put the assembler wrapper code there. In this way you can be sure that the correct stack pointer is extracted without worrying how many registers is pushed onto the stack before the assembly wrapper code started.

Cheers,

Joseph