blob: d40d28b6a3500930448d6e39a832a09a1938f712 [file] [log] [blame]
/**
* \addtogroup BSP
* \{
* \addtogroup SYSTEM
* \{
* \addtogroup Exception_Handlers
* \{
*/
/**
****************************************************************************************
*
* @file hw_hard_fault.c
*
* @brief HardFault handler.
*
* Copyright (c) 2016, Dialog Semiconductor
* All rights reserved.
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
****************************************************************************************
*/
#include <stdint.h>
#include <stdio.h>
#include "sdk_defs.h"
#include "hw_hard_fault.h"
#include "hw_watchdog.h"
#include "hw_cpm.h"
/*
* Global variables
*/
uint32_t hardfault_event_data[9] __attribute__((section("hard_fault_info")));
/*
* Local variables
*/
/*
* This is the base address in Retention RAM where the stacked information will be copied.
*/
#define STATUS_BASE (0x7FC5600)
/*
* Compilation switch to enable verbose output on HardFault
*/
#ifndef VERBOSE_HARDFAULT
# define VERBOSE_HARDFAULT 0
#endif
/*
* Function definitions
*/
/**
* \brief HardFault handler implementation. During development it will copy the system's status
* to a predefined location in memory. In release mode, it will cause a system reset.
*
* \param [in] hardfault_args The system's status when the HardFault event occurred.
*
* \return void
*
*/
#if (dg_configCODE_LOCATION == NON_VOLATILE_IS_FLASH)
__attribute__((section("text_retained")))
#endif
void HardFault_HandlerC(unsigned long *hardfault_args)
{
// Stack frame contains:
// r0, r1, r2, r3, r12, r14, the return address and xPSR
// - Stacked R0 = hf_args[0]
// - Stacked R1 = hf_args[1]
// - Stacked R2 = hf_args[2]
// - Stacked R3 = hf_args[3]
// - Stacked R12 = hf_args[4]
// - Stacked LR = hf_args[5]
// - Stacked PC = hf_args[6]
// - Stacked xPSR= hf_args[7]
if (dg_configIMAGE_SETUP == DEVELOPMENT_MODE)
{
hw_watchdog_freeze(); // Stop WDOG
ENABLE_DEBUGGER;
*(volatile unsigned long *)(STATUS_BASE) = hardfault_args[0]; // R0
*(volatile unsigned long *)(STATUS_BASE + 0x04) = hardfault_args[1]; // R1
*(volatile unsigned long *)(STATUS_BASE + 0x08) = hardfault_args[2]; // R2
*(volatile unsigned long *)(STATUS_BASE + 0x0C) = hardfault_args[3]; // R3
*(volatile unsigned long *)(STATUS_BASE + 0x10) = hardfault_args[4]; // R12
*(volatile unsigned long *)(STATUS_BASE + 0x14) = hardfault_args[5]; // LR
*(volatile unsigned long *)(STATUS_BASE + 0x18) = hardfault_args[6]; // PC
*(volatile unsigned long *)(STATUS_BASE + 0x1C) = hardfault_args[7]; // PSR
*(volatile unsigned long *)(STATUS_BASE + 0x20) = (unsigned long)hardfault_args; // Stack Pointer
*(volatile unsigned long *)(STATUS_BASE + 0x24) = (*((volatile unsigned long *)(0xE000ED28))); // CFSR
*(volatile unsigned long *)(STATUS_BASE + 0x28) = (*((volatile unsigned long *)(0xE000ED2C))); // HFSR
*(volatile unsigned long *)(STATUS_BASE + 0x2C) = (*((volatile unsigned long *)(0xE000ED30))); // DFSR
*(volatile unsigned long *)(STATUS_BASE + 0x30) = (*((volatile unsigned long *)(0xE000ED3C))); // AFSR
*(volatile unsigned long *)(STATUS_BASE + 0x34) = (*((volatile unsigned long *)(0xE000ED34))); // MMAR
*(volatile unsigned long *)(STATUS_BASE + 0x38) = (*((volatile unsigned long *)(0xE000ED38))); // BFAR
if (VERBOSE_HARDFAULT)
{
printf("HardFault Handler:\r\n");
printf("- R0 = 0x%08lx\r\n", hardfault_args[0]);
printf("- R1 = 0x%08lx\r\n", hardfault_args[1]);
printf("- R2 = 0x%08lx\r\n", hardfault_args[2]);
printf("- R3 = 0x%08lx\r\n", hardfault_args[3]);
printf("- R12 = 0x%08lx\r\n", hardfault_args[4]);
printf("- LR = 0x%08lx\r\n", hardfault_args[5]);
printf("- PC = 0x%08lx\r\n", hardfault_args[6]);
printf("- xPSR= 0x%08lx\r\n", hardfault_args[7]);
}
hw_cpm_assert_trigger_gpio();
while (1);
}
else
{
# ifdef PRODUCTION_DEBUG_OUTPUT
# if (USE_WDOG)
WDOG->WATCHDOG_REG = 0xC8; // Reset WDOG! 200 * 10.24ms active time for UART to finish printing!
# endif
dbg_prod_output(1, hardfault_args);
# endif // PRODUCTION_DEBUG_OUTPUT
hardfault_event_data[0] = HARDFAULT_MAGIC_NUMBER;
hardfault_event_data[1] = hardfault_args[0]; // R0
hardfault_event_data[2] = hardfault_args[1]; // R1
hardfault_event_data[3] = hardfault_args[2]; // R2
hardfault_event_data[4] = hardfault_args[3]; // R3
hardfault_event_data[5] = hardfault_args[4]; // R12
hardfault_event_data[6] = hardfault_args[5]; // LR
hardfault_event_data[7] = hardfault_args[6]; // PC
hardfault_event_data[8] = hardfault_args[7]; // PSR
hw_cpm_reboot_system(); // Force reset
while (1);
}
}
/**
* \}
* \}
* \}
* */