2016-10-05 07:16 AM
Hi.
I would like to implement some kind of fault handling mechanism, which would store some CPU registers, PC, etc. in flash if error occurs.
I tried to store SP value within HardFault Handler like this:
1.
__asm
void
HardFault_Handler(
void
)
2.
{
3.
MRS r0, MSP
4.
B __cpp(FaultHandler_Common)
5.
}
Then, I would branch to another function called FaultHandler_Common, where I would have current SP available as a function argument.
Everything compile, except that Keil shows 2 messages:
1. At the line 1 (in upper example) it shows: '' error: expected '(' after 'asm' ''
2. At the line3 (in upper example) it shows: '' error: use of undeclared identifier 'MRS' ''
Do I have to change something thate those messages will not beshown?
Thanks
2016-10-05 08:26 AM
Hello,
The issue is with your tool chain or project configuration.Probably, the include Paths is not set up properly or you are missing an include file.You'd want to review the defines, and include paths they use.Regards2016-10-05 08:26 AM
You seem to choose the path of most resistance, doing in-line assembly is generally a head-ache, and a task of figuring out exactly what will make the particular compiler version happy.
You have a file with assembler in it already, add code there, and have it deal with the stacks appropriately. In Keil we do this..//*****************************************************************************
/* Replace handler stub in startup_stm32fxxx.s with
HardFault_Handler\ ;
PROC
EXPORT HardFault_Handler
TST lr, #4 ; Determine correct stack
ITE EQ
MRSEQ R0, MSP ; Read MSP (Main)
MRSNE R0, PSP ; Read PSP (Process)
MOV R1, R4 ; Registers R4-R6, as parameters 2-4 of the function called
MOV R2, R5
MOV R3, R6 ; mailto:sourcer32@gmail.com
EXTERN hard_fault_handler_c
B hard_fault_handler_c
ENDP
*/
void hard_fault_handler_c(unsigned int * hardfault_args, unsigned int r4, unsigned int r5, unsigned int r6)
{
printf ('[Hard Fault]
'); // After Joseph Yiu
printf ('r0 = %08X, r1 = %08X, r2 = %08X, r3 = %08
X',
hardfault_args[0], hardfault_args[1], hardfault_args[2], hardfault_args[3]);
printf ('r4 = %08X, r5 = %08X, r6 = %08X, sp = %08
X',
r4, r5, r6, (unsigned int)&hardfault_args[8]);
printf ('r12= %08X, lr = %08X, pc = %08X, psr= %08
X',
hardfault_args[4], hardfault_args[5], hardfault_args[6], hardfault_args[7]);
printf ('bfar=%08X, cfsr=%08X, hfsr=%08X, dfsr=%08X, afsr=%08
X',
*((volatile unsigned int *)(0xE000ED38)),
*((volatile unsigned int *)(0xE000ED28)),
*((volatile unsigned int *)(0xE000ED2C)),
*((volatile unsigned int *)(0xE000ED30)),
*((volatile unsigned int *)(0xE000ED3C)) );
while(1);
}
//****************************************************************************
2016-10-05 11:11 AM
Thanks to both of you.
Clive, that looks promising. I read the Joseph's book and there he used such __asm function as I wrote in my first post. But if I could write that directly to startup file, it would be even better.2016-10-05 01:08 PM
Keil/ARM has changed the syntax and rules for inline assembly several times over the years, it makes for highly non-portable code, especially if you mix with GNU/GCC or downstream customers do.
The CMSIS functionality should supportvoid HardFault_Handler(void)
{
FaultHandler_Common( __get_MSP());
}
2016-10-05 01:18 PM
One should also be conscious that in the faulting condition the system can be very broken.
I've built other handlers that are less stack and external function dependent, as printf() can be a bit of a hog, and STDIO might not be viable.I'd lean to outputting to the console before committing to FLASH just in case that doesn't pan out. It is good to be able to soak-test devices without committing debugging hw to them.Consider also NVRAM area, you could fill that with diagnostic state and print out at next reboot.2016-10-05 02:44 PM
You mean NVRAM as a separate external chip, am I correct?
Second thing I want to ask is, if it is really recommended to use separate stack pointers (MSP, PSP) for application which is safety critical, but it does not use RTOS? I read this in Yoseph's Definitive Guide to Cortex-M4, but did not understand exactly in which case this would be beneficial. Is this somehow related to my case, where I want to store some data in case of a Fault. I suppose so. If Fault occurs because of some kind of stack pointer corruption, but I am not sure about whole picture. Could you explain a bit, please?2016-10-05 04:35 PM
Probably better called the BKPRAM 4KB at
0x40024000 on the STM32F4
The Cortex-M4 TRM might be a better perspective on the CPU and fault handling. Most non-RTOS code just uses one stack. There is the potential to effectively double fault if the stack goes below 0x20000000, but for the most part it is going to keep going down into the heap and statics. Stack corruption could manifest as a Hard Fault by reading a bad pointer address, or attempting to return to an address that is invalid. Could occur due to array/string bounds being overrun. You would probably want to watch the stack depth with respect to the amount allocated. Unexpected auto/local allocations, interrupt nesting, recursion or call tree going off the rails.2016-10-06 01:50 AM
Is BKPRAM similar to BKP registers? I suppose BKPRAM retains its content only when Vdd or VBAT is applied, right?
We used MPU to detect stack overflow. If this happens, MemManage Fault (or Hard Fault) is called. There I would like save all status information (let say to flash). But will this saving work, if stack already hits the bottom? Is this the case where it is good to have separate stacks?