This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

How to know why a chip boot or reboot : power off, errors, watchdog, ...

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(&current_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        
}
Related