Unexpected Reset Status

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Unexpected Reset Status

1,638 Views
charles0000
Contributor III

I've been trying to get my code to tell the difference between a software reset and a watchdog timeout so that it can take some extra failsafe measures to avoid getting stuck in a reset loop. When I perform a software reset, it is through SCB_AIRCR, like this:

SCB_AIRCR = SCB_AIRCR | SCB_AIRCR_VECTKEY(0x05fa) | SCB_AIRCR_SYSRESETREQ_MASK;

After reset, I inspect the RCM_SRSx registers to determine what caused the reset. The problem is that whether it is from a watchdog timeout or a software reset, the following test always evaluates to true, even if I comment out all of the code that sets up the watchdog in the first place:

if (RCM_SRS0 & RCM_SRS0_WDOG_MASK) {

    /* fail-safe code */

}

It always handles power-on reset correctly, but software reset (which is performed occasionally as part of its normal operation) is always detected as a watchdog timeout. I tried making the check more robust by specifically excluding software and power-related resets, but it did not change anything:

if (((RCM_SRS0 & RCM_SRS0_WDOG_MASK) || (RCM_SRS1 & RCM_SRS1_LOCKUP_MASK)) && !(RCM_SRS0 & RCM_SRS0_POR_MASK) && !(RCM_SRS1 & RCM_SRS1_SW_MASK)) {

    /* fail-safe code, still incorrectly gets executed on software reset */

}

I can't figure out why the WDOG bit is getting set here, even when I keep the application from configuring the watchdog at all. When I use the debugger, it detects the software reset correctly, so I can't inspect the state of the registers when the error happens.

0 Kudos
3 Replies

492 Views
mjbcswitzerland
Specialist V

Charles

Are you sure that the reset status information is being requested from the correct module in the device?

Older devices may have the information in the MC block and newer ones (revision 2) in the RCM. When using the incorrect one there are strange results because the access is to a different peripheral block.

Here is the reset detection code from the uTasker project (based on RCM_SRS0 or MC_SRSH according to the part that it is running on). The typical reset causes (commanded, reset pin, watchdog, POR) are all accurately recognised.

Regards

Mark

// Determine the cause of the last reset

//

extern unsigned char fnAddResetCause(CHAR *ptrBuffer)

{

    static const CHAR cJtag[]          = "JTAG";

    static const CHAR cLockup[]        = "Lockup";

    static const CHAR cSoftwareReset[] = "Software";

    static const CHAR cPowerOn[]       = "Power-on";

    static const CHAR cUndervoltage[]  = "Undervoltage";

    static const CHAR cWakeup[]        = "Wakeup reset";

    static const CHAR cWakeupOther[]   = "Wakeup";

    static const CHAR cResetInput[]    = "External";

    static const CHAR cWatchdog[]      = "WDOG";

    static const CHAR cClockLoss[]     = "Clock loss";

    static const CHAR cUnknown[]       = "???";

    const CHAR *ptrStr;

#if defined KINETIS_K_FPU || defined KINETIS_KL || defined KINETIS_REVISION_2 || (KINETIS_MAX_SPEED > 100000000) // {7}

    static const CHAR cHostDebug[]     = "Host debugger";

    static const CHAR cEZPORT[]        = "EZPORT";

    static const CHAR cPerFailure[]    = "peripheral failure";

    static const CHAR cTamper[]        = "tamper";

    if (RCM_SRS0 & RCM_SRS0_POR) {                                       // power on reset

        ptrStr = cPowerOn;

    }

    else if (RCM_SRS0 & RCM_SRS0_LVD) {                                  // low voltage detector

        ptrStr = cUndervoltage;

    }

    else if (RCM_SRS0 & RCM_SRS0_LOC) {                                  // loss of external clock

        ptrStr = cClockLoss;

    }

    else if (RCM_SRS0 & RCM_SRS0_WDOG) {                                 // watchdog

        ptrStr = cWatchdog;

    }

    else if (RCM_SRS0 & RCM_SRS0_WAKEUP) {

        if (RCM_SRS0 & RCM_SRS0_PIN) {

            ptrStr = cWakeup;                                            // wakeup via reset pin

        }

        else {

            ptrStr = cWakeupOther;                                       // wakeup from other source

        }

    }

    else if (RCM_SRS0 & RCM_SRS0_PIN) {                                  // reset pin

        ptrStr = cResetInput;

    }

    else if (RCM_SRS1 & RCM_SRS1_JTAG) {                                 // jtag

        ptrStr = cJtag;

    }

    else if (RCM_SRS1 & RCM_SRS1_LOCKUP) {                               // core lockup

        ptrStr = cLockup;

    }

    else if (RCM_SRS1 & RCM_SRS1_SW) {                                   // software reset

        ptrStr = cSoftwareReset;

    }

    else if (RCM_SRS1 & RCM_SRS1_MDM_AP) {                               // host debugger

        ptrStr = cHostDebug;

    }

    else if (RCM_SRS1 & RCM_SRS1_EZPT) {                                 // EZPORT reset

        ptrStr = cEZPORT;

    }

    else if (RCM_SRS1 & RCM_SRS1_SACKERR) {                              // peripheral failed to acknowledge attempt to enter stop mode

        ptrStr = cPerFailure;

    }

    else if (RCM_SRS1 & RCM_SRS1_TAMPER) {                               // tamper detect

        ptrStr = cTamper;

    }

    else {                                                               // unexpected

        ptrStr = cUnknown;

    }

#else

    if (MC_SRSH & MC_SRSH_JTAG) {                                        // jtag reset

        ptrStr = cJtag;

    }

    else if (MC_SRSH & MC_SRSH_LOCKUP) {                                 // lockup reset

        ptrStr = cLockup;

    }

    else if (MC_SRSH & MC_SRSH_SW) {                                     // software reset

        ptrStr = cSoftwareReset;

    }

    else if (MC_SRSL == (MC_SRSL_POR | MC_SRSL_LVD)) {                   // power on reset

        ptrStr = cPowerOn;

    }

    else if (MC_SRSL == MC_SRSL_LVD) {                                   // low voltage detect reset

        ptrStr = cUndervoltage;

    }

    else if (MC_SRSL == (MC_SRSL_PIN | MC_SRSL_WAKEUP)) {                // low leakage wakeup reset due to reset pin

        ptrStr = cWakeup;

    }

    else if (MC_SRSL == MC_SRSL_WAKEUP) {                                // low voltage wakeup due to other source

        ptrStr = cWakeupOther;

    }

    else if (MC_SRSL & MC_SRSL_PIN) {                                    // reset input

        ptrStr = cResetInput;

    }

    else if (MC_SRSL & MC_SRSL_COP) {                                    // watchdog reset

        ptrStr = cWatchdog;

    }

    else if (MC_SRSL & MC_SRSL_LOC) {                                    // clock-loss

        ptrStr = cClockLoss;

    }

    else {                                                               // unexpected

        ptrStr = cUnknown;

    }

#endif

    if (ptrBuffer == 0) {                                                // {8}

        fnDebugMsg((CHAR *)ptrStr);

        return 0;

    }

    return (uStrcpy(ptrBuffer, ptrStr) - ptrBuffer);                     // return the length of the string

}

0 Kudos

492 Views
charles0000
Contributor III

Thank you for your response. I am using a MK20DX256VLK7. I tried using MC_SRSL, but that register does not appear to be defined for this platform. I also added the checks that precede the watchdog check in the if/else-if sequence you posted, but it still detects a watchdog reset after I issue a software reset. I can't say conclusively that the watchdog isn't getting triggered somehow, but the behavior is the same even when I completely remove the watchdog component from the project and comment out all of the code that uses it. At present, the only way I have to get feedback from the dev board I'm using (other than the JTAG debugger, which somehow causes the reset code to perform correctly) is through two LEDs, but I've suggested to my boss to break out another pin or two on the next version so I can get more detailed feedback without using the debugger.

0 Kudos

492 Views
mjbcswitzerland
Specialist V

Charles

Maybe the watchdog is firing when your code starts and then at the second attempt it runs - this would explain why a software reset results in the watchdog reset status being set. It may also explain a difference when using the debugger because the debuggers often perform actions which affect the behaviour.

Note that your startup code must either initialise or disable the watchdog within 256 clock cycles or else it will fire. Perhaps you have a routine which can take varying times to disable the watchdog (eg. due to configuring a clock and waiting for it to be initialised or lock beforehand)?

Regards

Mark

0 Kudos