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
  • If you're using gcc, aren't deeply coupled to the nRF5 SDK WDT API, and if necessary translate this to plain C, the following also works:

    extern "C" {
      /* This little joy loads r0 with the main or process stack pointer then
       * jumps to the systemState watchdog IRQ handler, which will then
       * pull the exception return address out and use that as the value
       * of last_pc showing where the program was when the reset occurred.
       *
       * See https://stackoverflow.com/questions/38618440
       */
      __attribute__((__naked__))
      void WDT_IRQHandler ()
      {
        __ASM (
    #if (NRF51 - 0) /* Cortex M0/M1 */
              "mrs r0, msp\n\t"
              "mov r1, lr\n\t"
              "mov r2, #4\n\t"
              "tst r1, r2\n\t"
              "beq 1f\n\t"
              "mrs r0, psp\n"
    #else /* Cortex M3/M4 */
              "tst lr, #4\n\t"
              "ite eq\n\t"
              "mrseq r0, msp\n\t"
              "mrsne r0, psp\n\t"
    #endif /* ARM Cortext Variant */
              "1:\tldr r1, =%0\n\t"
              "bx r1\n"
              : // no outputs
              : "i" (nrfcxx::systemState::wdt_irqhandler)
              );
      }
    } // extern C
    
    void
    systemState::wdt_irqhandler (void * sp)
    {
        auto statep = nrfcxx::systemState::statep_;
        if (statep) {
          struct exception_frame_type {
            uint32_t r0;
            uint32_t r1;
            uint32_t r2;
            uint32_t r3;
            uint32_t r12;
            uint32_t lr;
            uint32_t pc;
            uint32_t xpsr;
          } const * const efp = reinterpret_cast<const exception_frame_type *>(sp);
    
          statep->wdt_status = NRF_WDT->REQSTATUS;
          if (efp) {
            statep->last_pc = efp->lr;
            statep->reset_reas_ = state_type::RESET_REAS_WDTBARKED;
          }
        }
        do_reset(false);
    }
    

Reply
  • If you're using gcc, aren't deeply coupled to the nRF5 SDK WDT API, and if necessary translate this to plain C, the following also works:

    extern "C" {
      /* This little joy loads r0 with the main or process stack pointer then
       * jumps to the systemState watchdog IRQ handler, which will then
       * pull the exception return address out and use that as the value
       * of last_pc showing where the program was when the reset occurred.
       *
       * See https://stackoverflow.com/questions/38618440
       */
      __attribute__((__naked__))
      void WDT_IRQHandler ()
      {
        __ASM (
    #if (NRF51 - 0) /* Cortex M0/M1 */
              "mrs r0, msp\n\t"
              "mov r1, lr\n\t"
              "mov r2, #4\n\t"
              "tst r1, r2\n\t"
              "beq 1f\n\t"
              "mrs r0, psp\n"
    #else /* Cortex M3/M4 */
              "tst lr, #4\n\t"
              "ite eq\n\t"
              "mrseq r0, msp\n\t"
              "mrsne r0, psp\n\t"
    #endif /* ARM Cortext Variant */
              "1:\tldr r1, =%0\n\t"
              "bx r1\n"
              : // no outputs
              : "i" (nrfcxx::systemState::wdt_irqhandler)
              );
      }
    } // extern C
    
    void
    systemState::wdt_irqhandler (void * sp)
    {
        auto statep = nrfcxx::systemState::statep_;
        if (statep) {
          struct exception_frame_type {
            uint32_t r0;
            uint32_t r1;
            uint32_t r2;
            uint32_t r3;
            uint32_t r12;
            uint32_t lr;
            uint32_t pc;
            uint32_t xpsr;
          } const * const efp = reinterpret_cast<const exception_frame_type *>(sp);
    
          statep->wdt_status = NRF_WDT->REQSTATUS;
          if (efp) {
            statep->last_pc = efp->lr;
            statep->reset_reas_ = state_type::RESET_REAS_WDTBARKED;
          }
        }
        do_reset(false);
    }
    

Children
No Data
Related