2014-03-24 5:44 AM
Hi All,
I'm running some code on Discovery STM32L152 board. I'm getting Hard Fault each time I initiate structure fields in a function:
1.
void pid_Init(float p_factor, float i_factor, float d_factor, pidData_t *pidPtr)
2.
{
3.
pidPtr->lastProcessValue = 0;
4.
pidPtr->sumError = 0;
5.
}typedef struct {
int16_t lastProcessValue;
int32_t sumError;
float P_Factor;
float I_Factor;
float D_Factor;
int16_t maxError;
int32_t maxSumError;
} pidData_t;pid_Init(K_P,K_I,K_D,&pidData);pid_Init*pidPtrpidPtr->lastProcessValue
1.
/*----------Stack Configuration-----------------------------------------------*/ 
2.
#define STACK_SIZE 0x00000500 /*!< Stack size (in Words) */
3.
__attribute__ ((section(''.co_stack'')))
4.
unsigned long pulStack[STACK_SIZE];
1.
Program Size:
2.
182488 10328 9192 202008 31518 DiscoveryCooCox.elf
3.
text data bss dec hex filename
4.
5.
BUILD SUCCESSFUL
6.
Total time: 3 seconds2014-03-24 6:02 AM
Tom,
assuming that pidData is statically allocated (global variable, isn't it?), it can not change it's address. I suspect the problem lies in space reserved in register/stack to pass floats to pid_Init. Can you try for a test to move the declaration of pidPtr argument at the first position in pid_Init ?2014-03-24 6:05 AM
I'm getting a confusing mix of descriptions and code fragments, please condense this into a complete/concise example that is compilable.
Provide a disassembly of the subroutine and processor registers at the fault. Do you have the ability to using printf() via a serial/debug terminal? *pidPtr reads the value stored at pidPtr, what does pidPtr read as? printf(''%08lX %08lX\n'', (unsigned long)pidPtr, (unsigned long)*pidPtr); At the entry to pid_Init(), what is in R42014-03-24 6:57 AM
Hello Laurent!
You are right! I rearranged the input variables:void pid_Init(pidData_t *pidPtr,float p_factor, float i_factor, float d_factor)0800d1d6: nop 
70 {
pid_Init:
0800d1d8: push {r3, r4, r5, r6, r7, lr}
0800d1da: mov r4, r0
0800d1dc: mov r7, r2
73 pidPtr->lastProcessValue = 0;
0800d1de: movs r6, #0
0800d1e0: strh r6, [r0, #0]
74 pidPtr->sumError = 0;
0800d1e2: str r6, [r0, #4]
77 pidPtr->P_Factor = p_factor;
0800d1e4: str r1, [r0, #8]
79 pidPtr->I_Factor = i_factor;
0800d1e6: str r2, [r4, #12]
80 PID_I_On=0;
0800d1e8: movw r5, #10356 ; 0x2874
0800d1ec: movt r5, #8192 ; 0x2000
0800d1f0: strb r6, [r5, #0]
82 pidPtr->D_Factor = d_factor;
0800d1f2: str r3, [r0, #16]
88 pidPtr->maxError = MAX_INT / (pidPtr->P_Factor + 1);
0800d1f4: mov r0, r1
0800d1f6: mov.w r1, #1065353216 ; 0x3f800000
0800d1fa: bl 0x800dc6c <
__aeabi_fadd
>
0800d1fe: mov r1, r0
0800d200: mov.w r0, #65024 ; 0xfe00
0800d204: movt r0, #18175 ; 0x46ff
0800d208: bl 0x800dfe4 <
__divsf3
>
0800d20c: bl 0x800e11c <
__fixsfsi
>
0800d210: strh r0, [r4, #20]
89 pidPtr->maxSumError = MAX_I_TERM / (pidPtr->I_Factor + 1);
0800d212: mov r0, r7
0800d214: mov.w r1, #1065353216 ; 0x3f800000
0800d218: bl 0x800dc6c <
__aeabi_fadd
>
0800d21c: mov r1, r0
0800d21e: mov.w r0, #1317011456 ; 0x4e800000
0800d222: bl 0x800dfe4 <
__divsf3
>
0800d226: bl 0x800e11c <
__fixsfsi
>
0800d22a: str r0, [r4, #24]
0800d22c: pop {r3, r4, r5, r6, r7, pc}Core 
r0 0x200034ec 
r1 0x402e0000 
r2 0x00000000 
r3 0x40000000 
r4 0x200034ec 
r5 0x40000000 
r6 0x00000000 
r7 0x00000000 
r8 0x2000289b 
r9 0x2000287c 
r10 0x40020400 
r11 0x20002894 
r12 0x01010101 
sp 0x20004bf8 
lr 0x08000655 
pc 0x0800d1e0 
xpsr 0x61000000 2014-03-24 7:05 AM
The ABI should permit 4 32-bit parameters to be passed by register, beyond that the stack would be used.
Not sure why this would be a problem unless GNU/GCC is broken. Then you'd want to review the version of the compiler being used, and if this is a known issue.2014-03-25 1:37 AM
Tom,
this generated code looks good. the pointer goes into R0 and the three floats each 32-bit stored into R1, R2, R3. (R4 has nothing todo with this parameter passing stuff. Clive1 certainly wanted you to look at R3 to find the value of the pointer). Anyway, to have a successful call, the caller and the callee must agree on parameter passing, and in particular on the way to pass floats (aren't they declared as doubles in the caller ???). Can you show us the caller disassembly (the better is to show us disassembly from the version that made the hard fault). Does caller and callee are compiled from the same source file or from distinct source file. In the latter case what is the prototype declared for Pid_init ?2014-03-25 3:47 AM
Hello guys,
You were right again :)pid_Init2014-03-25 6:32 AM
Yes, so was my bet. Let's suppose the caller makes the calls passing doubles, so the compiler implicitly think that the target function takes doubles as arguments and pass them appropriately (they are 64-bit value each).
Will you have declared a prototype of PidInit, the compiler will have done an implicit cast, and pass arguments as floats (32-bit each).2014-03-25 7:15 AM
I see one has to be very carefull with gcc and take warnings as seriously as errors.
Many thanks for your help. Topic closed. Regards Tom