nRF51822: Don't reach HardFault_Handler function in the case of Hard Fault

Hello, guys!

We have nRF51822 rev3 SoC that runs the code developed with nRF5 SDK v12.3.0. SoftDevice s130 is enabled and used. 

We want to use our custom HardFault_Handler() function that overwrites the weak HardFault_Handler implementation. To achieve this, we did the following:

  1. Enabled HardFault handler in sdk_config.h with

#ifndef HARDFAULT_HANDLER_ENABLED
#define HARDFAULT_HANDLER_ENABLED 1
#endif

          2.  Used our custom HardFault_Handler() implementation in main.c file:

void HardFault_Handler(void)
{
    uint32_t *sp = (uint32_t *) __get_MSP(); // Get stack pointer
    uint32_t ia = sp[12]; // Get instruction address from stack

    NRF_LOG_INFO("Hard Fault at address: 0x%08x\r\n", (unsigned int)ia);
    while(1)
        ;
}

However, it seems that we never reach our HardFault_Handler() implementation!

To test if we can properly reach our HardFault_Handler() implementation we created a custom illegal_instruction_execution() function that will cause the HardFault and tried to call that function in the code. The content of the function is as follows:

static int illegal_instruction_execution(void) {
  int (*bad_instruction)(void) = (void *)0xE0000000;
  return bad_instruction();
}

The function is properly causing the HardFault because we can clearly see it from the function Call Stack:

However, it seems we don't enter into our custom HardFault_Handler() function. Do you have any idea about what we are missing here?

Thanks in advance for your time and efforts.

Sincerely,
Bojan.

Parents
  • Hello,

    Segger Embedded studio enables breakpoint on hardfaults by default. This means the CPU will be halted as soon as the program enters the hardfault handler in the MBR before it has been forwarded to the Softdevice and the handler in your application. 

    You can disable the breakpoint here:

    Best regards,

    Vidar

  • Hello, .

    The same is happening even when I disable the HardFault the way you suggested. I don't enter the breakpoint that is set in my HardFault_Handler() function.

    I also used Makefile to generate the .hex file + J-Link RTT Viewer for Debugging but the result is the same - we are unable to enter our custom HardFault_Handler() function.

  • Hello,

    I was able to replicate this actually. I ran your function with and without the chip being in debug interface mode. In debug interface mode, the CPU got halted, and while not in debug mode, it got reset (lockup).

    A lockup indicates that a fault occurred within the fault exception as Memfault explains in their blog post here: https://interrupt.memfault.com/blog/cortex-m-hardfault-debug#faults-from-faults

    Anyway, the problem must be that this particular fault triggers a bug in the MBRs interrupt forwarding mechanism that triggers another fault exception. I am afraid there is not much you can do to fix this considering we have not made the source the MBR code available. 

    To test your hardfault handler you can try to trigger a different fault. For instance, by dereferencing an invalid pointer as shown below.

        uint32_t dummy = *(volatile uint32_t *) 0xFFFFFFFF;
        (void)dummy;
    

Reply
  • Hello,

    I was able to replicate this actually. I ran your function with and without the chip being in debug interface mode. In debug interface mode, the CPU got halted, and while not in debug mode, it got reset (lockup).

    A lockup indicates that a fault occurred within the fault exception as Memfault explains in their blog post here: https://interrupt.memfault.com/blog/cortex-m-hardfault-debug#faults-from-faults

    Anyway, the problem must be that this particular fault triggers a bug in the MBRs interrupt forwarding mechanism that triggers another fault exception. I am afraid there is not much you can do to fix this considering we have not made the source the MBR code available. 

    To test your hardfault handler you can try to trigger a different fault. For instance, by dereferencing an invalid pointer as shown below.

        uint32_t dummy = *(volatile uint32_t *) 0xFFFFFFFF;
        (void)dummy;
    

Children
Related