EmbDev.net

Forum: ARM programming with GCC/GNU tools Troubles hunting down a Hard Fault Exception


von Marco .. (borealis_1427)


Rate this post
useful
not useful
Hi,

I am having trouble finding the reason for a hard fault exception on my 
cortex-M3 (STM32F107). I have implemented the exception handler 
according to the book "The definiteve guide to the ARM Cortex-M3".

The assembler part:
1
__asm void HardFault_Handler(void)
2
{
3
  IMPORT hard_fault_handler_c
4
  TST LR, #4
5
  ITE EQ
6
  MRSEQ R0, MSP
7
  MRSNE R0, PSP
8
  B hard_fault_handler_c
9
}

And the C part:
1
void hard_fault_handler_c(unsigned int * hardfault_args)
2
{
3
4
  volatile unsigned int stacked_r0;
5
  volatile unsigned int stacked_r1;
6
  volatile unsigned int stacked_r2;
7
  volatile unsigned int stacked_r3;
8
  volatile unsigned int stacked_r12;
9
  volatile unsigned int stacked_lr;
10
  volatile unsigned int stacked_pc;
11
  volatile unsigned int stacked_psr;
12
13
  stacked_r0 = ((unsigned long) hardfault_args[0]);
14
  stacked_r1 = ((unsigned long) hardfault_args[1]);
15
  stacked_r2 = ((unsigned long) hardfault_args[2]);
16
  stacked_r3 = ((unsigned long) hardfault_args[3]);
17
18
  stacked_r12 = ((unsigned long) hardfault_args[4]);
19
  stacked_lr = ((unsigned long) hardfault_args[5]);
20
  stacked_pc = ((unsigned long) hardfault_args[6]);
21
  stacked_psr = ((unsigned long) hardfault_args[7]);
22
  
23
  printf ("[Hard fault handler]\n");
24
  printf ("R0 = %08x\n", stacked_r0);
25
  printf ("R1 = %08x\n", stacked_r1);
26
  printf ("R2 = %08x\n", stacked_r2);
27
  printf ("R3 = %08x\n", stacked_r3);
28
  printf ("R12 = %08x\n", stacked_r12);
29
  printf ("LR = %08x\n", stacked_lr);
30
  printf ("PC = %08x\n", stacked_pc);
31
  printf ("PSR = %08x\n", stacked_psr);
32
  printf ("BFAR = %08x\n", (*((volatile unsigned long *)(0xE000ED38))));
33
  printf ("CFSR = %08x\n", (*((volatile unsigned long *)(0xE000ED28))));
34
  printf ("HFSR = %08x\n", (*((volatile unsigned long *)(0xE000ED2C))));
35
  printf ("DFSR = %08x\n", (*((volatile unsigned long *)(0xE000ED30))));
36
  printf ("AFSR = %08x\n", (*((volatile unsigned long *)(0xE000ED3C))));
37
  while (1)
38
  {} 
39
}

When the CPU traps, I get the follwing output:
1
[Hard fault handler]
2
R0 = 00000000
3
R1 = 00000000
4
R2 = 00000004
5
R3 = 00000004
6
R12 = 01010101
7
LR = 08002987
8
PC = 08000768
9
PSR = 61000000
10
BFAR = e000ed38
11
CFSR = 00000400
12
HFSR = 40000000
13
DFSR = 00000000
14
AFSR = 00000000

From this I can see that in CFSR's BFSR part bit bit 2 (IMPRECISERR) is 
set. According to the book this means:
"Bus error during data access. Bus error could be caused by device not 
being initialized, access of privileged-only device in user mode, or the 
transfer size is incorrect for the specific device."

I was also able to find the source code line that causes the exception:
1
uint8_t err;
2
3
devData[minorNum]->writeMutex = OSMutexCreate(2, &err);
4
if (OS_ERR_NONE != err) {
5
  return DRV_ERR;
6
}

The assebler code for this is:
1
   124:   devData[minorNum]->writeMutex = OSMutexCreate(2, &err); 
2
0x0800074C 4669      MOV      r1,sp
3
0x0800074E 2002      MOVS     r0,#0x02
4
0x08000750 F002F8D5  BL.W     OSMutexCreate (0x080028FE)
5
0x08000754 494A      LDR      r1,[pc,#296]  ; @0x08000880
6
0x08000756 F8511024  LDR      r1,[r1,r4,LSL #2]
7
0x0800075A 6048      STR      r0,[r1,#0x04]
8
   125:   if (OS_ERR_NONE != err) { 
9
0x0800075C F89D0000  LDRB     r0,[sp,#0x00]
10
0x08000760 B110      CBZ      r0,0x08000768
11
   126:     return DRV_ERR; 
12
   127:   }

The exception occurs when executing
1
if (OS_ERR_NONE != err)
 or more exactly on instruction
1
LDRB     r0,[sp,#0x00]

Register sp conatains 0x200010f4 (before executing the LDRB 
instruction), which is in the RAM area.

Any ideas on what's going wrong here?

Thanks in advance for your tips and help!

P.S.: I am using the RealView compiler.

--
Regards,
 Marco

von Marcus H. (mharnisch)


Rate this post
useful
not useful
I'd recommend having a look at this instruction
1
STR      r0,[r1,#0x04]

von (prx) A. K. (prx)


Rate this post
useful
not useful
No.

LDR      r1,[pc,#296]  ; @0x08000880
  loads the address of devData from the constant pool
LDR      r1,[r1,r4,LSL #2]
  loads devData[minorNum]
STR      r0,[r1,#0x04]
  devData[minorNum]->writeMutex = ...

Correct so far. But we lack information about R4=minorNum. Most likely 
the STR instruction fails because the address loaded in the 2nd LDR is 
invalid (0).

von Marco .. (borealis_1427)


Rate this post
useful
not useful
Marcus Harnisch wrote:
>
1
> STR      r0,[r1,#0x04]
2
>
1
r0 = 0x20001174
2
r1 = 0x00000000

RAM starts at 0x20000000 and is 64 KB long.

So that assembler instruction should store 0 to RAM area.

von Marcus H. (mharnisch)


Rate this post
useful
not useful
Marco ... wrote:
> r0 = 0x20001174
> r1 = 0x00000000
>
> RAM starts at 0x20000000 and is 64 KB long.
>
> So that assembler instruction should store 0 to RAM area.

No. It stores 0x20001174 to 0x4.

von Marco .. (borealis_1427)


Rate this post
useful
not useful
A. K. wrote:
[...]
> Correct so far. But we lack information about R4=minorNum. Most likely
> the STR instruction fails because the address loaded in the 2nd LDR is
> invalid (0).

r4 = 0 before executing
1
LDR      r1,[r1,r4,LSL #2]

Debugger shows that minorNum = 0 too.

von Marco .. (borealis_1427)


Rate this post
useful
not useful
Thanks to your hints, I found the trace to follow and solved the problem 
now.

--> Dangling pointer for devData...

Many thanks for your help!

--
Regards,
 Marco

Please log in before posting. Registration is free and takes only a minute.
Existing account
Do you have a Google/GoogleMail account? No registration required!
Log in with Google account
No account? Register here.