UPDATED WITH IMPLEMENTATION
Is there a way to know what is triggering a chip boot :
- Power off (battery replacement or deffective electrical connection)
- The watch dog reset chip
- Reboot due to app error in
app_error_handler
- sd_power_system_off
- ...
POSSIBLE IMPLEMENTATION
I don't use system off
, but it would be easy to implement. save_reset_reason
is called from main.
#define RESET_FROM_PIN 0x00000001
#define RESET_FROM_WDT 0x00000002
#define RESET_FROM_SOFTWARE 0x00000004
#define RESET_FROM_LOCKUP 0x00000008
#define RESET_FROM_SYSTEM_OFF_GPIO 0x00010000
#define RESET_FROM_SYSTEM_OFF_LPCOMP 0x00020000
#define RESET_FROM_SYSTEM_OFF_DEBUG 0x00040000
#define INC_RESET_REASON_PIN 0x00000001
#define INC_RESET_REASON_WDT 0x00000100
#define INC_RESET_REASON_SOFT 0x00010000
#define INC_RESET_REASON_SOFT_ERROR 0x01000000
#define MAX_RESET_REASON 0xFF
/**@brief Error handler function, which is called when an error has occurred.
*
* @warning This handler is an example only and does not fit a final product. You need to analyze
* how your product is supposed to react in case of error.
*
* @param[in] error_code Error code supplied to the handler.
* @param[in] line_num Line number where the handler is called.
* @param[in] p_file_name Pointer to the file name.
*/
void app_error_handler(uint32_t error_code, uint32_t line_num, const uint8_t * p_file_name)
{
// Copying parameters to static variables because parameters may not be accessible in debugger.
static volatile uint8_t s_file_name[MAX_LENGTH_FILENAME];
static volatile uint16_t s_line_num;
static volatile uint32_t s_error_code;
strncpy((char *)s_file_name, (const char *)p_file_name, MAX_LENGTH_FILENAME - 1);
s_file_name[MAX_LENGTH_FILENAME - 1] = '\0';
s_line_num = line_num;
s_error_code = error_code;
UNUSED_VARIABLE(s_file_name);
UNUSED_VARIABLE(s_line_num);
UNUSED_VARIABLE(s_error_code);
#ifdef RTT
SEGGER_RTT_SetTerminal(0);
SEGGER_RTT_printf(0,"%sErr %d, ln %d, file %s%s\n",RTT_CTRL_BG_BRIGHT_RED,error_code,line_num,p_file_name,RTT_CTRL_RESET);
#endif
// Set info that reboot occurred due to soft error
sd_power_gpregret_clr(GP_REG_RET_CLEAR);
sd_power_gpregret_set(GP_REG_RET_APP_ERROR_CAUSE_REBOOT);
#ifdef DEBUG
led_kernel_on();
#else
// On assert, the system can only recover on reset
NVIC_SystemReset();
#endif
}
/**@brief Save reset reasons in flash
See the nRF51_Reference_Manual v3 for RESETREAS documentation.
Note: Unless cleared, the RESETREAS register will be cumulative. A field is cleared by writing '1' to it. If none of the reset sources are flagged, this indicates
that the chip was reset from the on-chip reset generator, which will indicate a power-on-reset or a brown out reset.
* RESET_FROM_PIN is set after pin reset.
* RESET_FROM_WDT is set when watchdog triggers the reset.
* RESET_FROM_SOFTWARE is set when software triggers a reset.
* RESET_FROM_LOCKUP is set when CPU lock-up triggers a reset.
* RESET_FROM_SYSTEM_OFF_GPIO is set after waking up from System Off when wakeup source is GPIO pin.
* RESET_FROM_SYSTEM_OFF_LPCOMP is set after waking up from System Off when the wakeup source is LPCOMP.
* RESET_FROM_SYSTEM_OFF_DEBUG is set after waking up from System Off wehn the wakeup source is DEBUG mode.
*/
static void save_reset_reasons()
{
uint32_t current_reboot_reason;
uint32_t flash_reboot_reason;
uint32_t gpregret;
uint8_t val;
// Read reset reasons register
sd_power_reset_reason_get(¤t_reboot_reason);
sd_power_reset_reason_clr(0xFFFFFFFF);
// Read and clear GP Ret register
sd_power_gpregret_get(&gpregret);
sd_power_gpregret_clr(GP_REG_RET_CLEAR);
// Read and clear stored flash reasons from flash
flash_reboot_reason = flash_kernel_read32(FLASH_ADDR_RESET_REASON);
// First init
if(flash_reboot_reason == PSTORAGE_FLASH_EMPTY_MASK)
{
flash_reboot_reason = 0;
#ifdef RTT
SEGGER_RTT_TerminalOut(0,"FLASH reset reasons init");
#endif
}
if(current_reboot_reason & RESET_FROM_PIN)
{
val = (uint8_t)((flash_reboot_reason & 0x000000FF) >> 0);
if(val < MAX_RESET_REASON)
{
flash_reboot_reason += INC_RESET_REASON_PIN;
}
}
if(current_reboot_reason & RESET_FROM_WDT)
{
val = (uint8_t)((flash_reboot_reason & 0x00FF0000) >> 8);
if(val < MAX_RESET_REASON)
{
flash_reboot_reason += INC_RESET_REASON_WDT;
}
}
if(current_reboot_reason & RESET_FROM_SOFTWARE)
{
if(gpregret == GP_REG_RET_APP_ERROR_CAUSE_REBOOT)
{
val = (uint8_t)((flash_reboot_reason & 0xFF000000) >> 24);
if(val < MAX_RESET_REASON)
{
flash_reboot_reason += INC_RESET_REASON_SOFT_ERROR;
}
}
else
{
val = (uint8_t)((flash_reboot_reason & 0x00FF0000) >> 16);
if(val < MAX_RESET_REASON)
{
flash_reboot_reason += INC_RESET_REASON_SOFT;
}
}
}
// Save the new reset reasons in flash if needed
if(current_reboot_reason)
{
flash_kernel_write32(FLASH_ADDR_RESET_REASON,flash_reboot_reason);
}
#ifdef RTT
SEGGER_RTT_SetTerminal(0);
SEGGER_RTT_printf(0,"FLASH reset reasons val [%X]\n",flash_reboot_reason);
#endif
}