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

Watchdog reset: determining cause

Hi,

I'd like to determine the cause of a watchdog reset. I was hoping to utilize the WDT event handler (passed in to nrf_drv_wdt_init()) to record the PC of the application code at the time the watchdog timeout occurred, and save that to a word in uninitialized RAM (I am aware of the time constraints in the handler, and the fact that RAM isn't guaranteed to be retained on a WDT reset).

I'd imagine the application PC code must be saved in a register or pushed on to the stack at some point before the event handler is called.

Do you know where I can find this?

Parents
  • Thanks for the suggestion RK! I was able to successfully unwind the stack and find the PC at the time of the WDT timeout. Here's the code (posting as an answer since there's not enough room as a comment):

    /* 
     * wdt_event_handler() - watchdog timeout event handler
     *
     * This handler is called from the ISR WDT_IRQHandler, which has previously 
     * pushed lr onto the interrupt stack, then subtracted 12 from the SP before
     * calling this routine.  So we're adding 12 to get back to the lr
     * (which contains EXC_RETURN); then adding another 28 bytes to get back
     * to the stacked PC (since xPSR, PC, LR, R12, R3-R0 are pushed onto the 
     * interrupt stack in that order), and saving that address in the m_wdt_addr
     * variable.
     * 
     * NOTE: The max amount of time we can spend in WDT interrupt is two cycles 
     * of 32768[Hz] clock - after that, the WDT reset occurs.
    */
    
    static void wdt_event_handler(void)
    {
        __asm volatile (
                        "   ldr r0, [sp, #40]     \n" 
                        "   ldr r1, =m_wdt_addr   \n" 
                        "   str r0, [r1]          \n"
                    );
    }
    
Reply
  • Thanks for the suggestion RK! I was able to successfully unwind the stack and find the PC at the time of the WDT timeout. Here's the code (posting as an answer since there's not enough room as a comment):

    /* 
     * wdt_event_handler() - watchdog timeout event handler
     *
     * This handler is called from the ISR WDT_IRQHandler, which has previously 
     * pushed lr onto the interrupt stack, then subtracted 12 from the SP before
     * calling this routine.  So we're adding 12 to get back to the lr
     * (which contains EXC_RETURN); then adding another 28 bytes to get back
     * to the stacked PC (since xPSR, PC, LR, R12, R3-R0 are pushed onto the 
     * interrupt stack in that order), and saving that address in the m_wdt_addr
     * variable.
     * 
     * NOTE: The max amount of time we can spend in WDT interrupt is two cycles 
     * of 32768[Hz] clock - after that, the WDT reset occurs.
    */
    
    static void wdt_event_handler(void)
    {
        __asm volatile (
                        "   ldr r0, [sp, #40]     \n" 
                        "   ldr r1, =m_wdt_addr   \n" 
                        "   str r0, [r1]          \n"
                    );
    }
    
Children
No Data
Related