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        
}
Parents
  • There is a register, RESETREAS, that is intended to tell you what caused the reset. It is documented in the datasheet. However, IIRC, there are a few problems with it, which are also documented in the PAN(Product Anomaly Notice). There is also a GPREGRET register, which sounds like a sad British doctor, but is actually a register that survives system off/on, and can be used to indicate what caused a reset. As far as I know, you will have to write your own app_error_handler if you want to make use of GPREGRET.

  • In my experience RAM is seldom cleared, it actually starts out in some random state. But anyway, the point is that by using the RESETREAS register in conjunction with the GPREGRET register, you should be able to distinguish between the various different paths your program may have taken to arrive at the beginning of main()

Reply Children
No Data
Related