Debugging a ARM Cortex-M Hard Fault

Hello,

while implementing a hard fault handler for my embedded device, I looked up the documentation from here:

I have some questions about the code posted there:

Default_Handler:
  /* Load the address of the interrupt control register into r3. */
  ldr r3, NVIC_INT_CTRL_CONST
  /* Load the value of the interrupt control register into r2 from the
  address held in r3. */
  ldr r2, [r3, #0]
  /* The interrupt number is in the least significant byte - clear all
  other bits. */
  uxtb r2, r2
Infinite_Loop:
  /* Now sit in an infinite loop - the number of the executing interrupt
  is held in r2. */
  b  Infinite_Loop
  .size  Default_Handler, .-Default_Handler

.align 4
/* The address of the NVIC interrupt control register. */
NVIC_INT_CTRL_CONST: .word 0xe000ed04


/* The prototype shows it is a naked function - in effect this is just an
assembly function. */
static void HardFault_Handler( void ) __attribute__( ( naked ) );

/* The fault handler implementation calls a function called
prvGetRegistersFromStack(). */
static void HardFault_Handler(void)
{
    __asm volatile
    (
        " tst lr, #4                                                \n"
        " ite eq                                                    \n"
        " mrseq r0, msp                                             \n"
        " mrsne r0, psp                                             \n"
        " ldr r1, [r0, #24]                                         \n"
        " ldr r2, handler2_address_const                            \n"
        " bx r2                                                     \n"
        " handler2_address_const: .word prvGetRegistersFromStack    \n"
    );
}

This implementation wrote for GCC
I hope someone could help me translate this to IAR assembly compiler syntax, so it could compile right. I googled all websites related to this but couldn’t find complete solution for this.

Any help will be appreciated
Best regards
Igor

Why not simply using C ?

  1. How to implement it in C?
  2. Just for the record I still want to know how to implement it in assembly

just define the appropriate handler function e.g.

    #include <assert.h>
    void Default_Handler(void)
    {
        assert( 0 );
    }

I’m sure there are plenty examples including asm style provided by Google.

As I already told, I have searched google, and not found ASM replacement for IAR

some lines won’t compile under IAR compiler

" ldr r2, handler2_address_const \n"
Error Unknown symbol in inline assembly: “handler2_address_const”

" handler2_address_const: .word prvGetRegistersFromStack \n"
Error Unknown symbol in inline assembly: “handler2_address_const”

Could somebody please help with this? I have only asking for the 2 line error fix
I’m sure somebody already know that answer as if he using IAR with FreeRTOS

Igor

I don’t use IAR because I’ve never been a fan of their UI, but this has been discussed before. Perhaps this will be enough to help you.

Pilot, thanks for your response, but I have already saw this topic before and it didn’t helped me:

“If the HardFault_Handler function is a C file and you don’t have any assembler files in your project you will have to create your own assembly file and add it to the project. In IAR syntax it would look something like the following”

I do have assembly file “startup.s”, having two asm files causes relocation failure

I have asked if there inline asm workaround for:
" ldr r2, handler2_address_const \n"
" handler2_address_const: .word prvGetRegistersFromStack \n"

I’m pretty sure this known issue, someone have other suggestions?

I don’t believe the second line is needed with IAR.

Just EXTERN the prvGetRegistersFromStack and then change the ldr line to
ldr r2, prvGetRegistersFromStack

Hi Pilot,
I have tried this

	__asm volatile
    (
		" EXTERN prvGetRegistersFromStack							\n"
		" tst lr, #4                                                \n"
        " ite eq                                                    \n"
        " mrseq r0, msp                                             \n"
        " mrsne r0, psp                                             \n"
        " ldr r1, [r0, #24]                                         \n"
        " ldr r2, prvGetRegistersFromStack                          \n"
        " bx r2                                                     \n"
    );

but I have compiler error: Error[Pe020]: identifier “EXTERN” is undefined, I guess i need to know where to place EXTERN
do you know how to write it correctly?

Instead of

" ldr r2, handler2_address_const \n"
" bx r2 \n"
" handler2_address_const: .word prvGetRegistersFromStack \n"

Try

" ldr r2, handler2_address_const \n"
" bx r2 \n"
" handler2_address_const: dc32 prvGetRegistersFromStack \n"

Also - I don’t know any inline __asm() way to do it. I think you need to put the code in an assembly language file. If you’re having trouble adding a second asm file, probably best to focus on that.

jefftenney, thanks for your help,

Your guess about " handler2_address_const: dc32 prvGetRegistersFromStack \n"
didn’t help, I have still got error and new warning: Warning[Og014]: Warning in inline assembly: "DC or DS directive while in CODE area.

However after some tries I have got this finally compiled and tested:

 	__asm volatile
    (
		" tst lr, #4                                                \n"
        " ite eq                                                    \n"
        " mrseq r0, msp                                             \n"
        " mrsne r0, psp                                             \n"
        " ldr r1, [r0, #24]                                         \n"
        " ldr r2, =prvGetRegistersFromStack                         \n"
        " bx r2                                                     \n"
    );

Thanks for every one who tried to help :slight_smile:

Great you got it working! Since you don’t need handler2_address_const at all, you can probably use the simpler assembly:

B prvGetRegistersFromStack

Instead of

ldr r2, =prvGetRegistersFromStack
bx r2