This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

RTOS/CC2630: watchdog reset can't run to main()

Part Number: CC2630
Other Parts Discussed in Thread: TIMAC, , CC2650

Tool/software: TI-RTOS

platform:2630

sdk: timac 1.5.2

issue:can't run to main() after watchdog timeout.

test code is as follow:

call stack while watchdog reset  is as follow:

  • Hi,

    If a debugger is connected, the ICEPick will halt the CPU after a watchdog reset to allow for debugging. If you run the device without a debugger attach, are you able to properly start after a watchdog timeout?
  • No,can't properly start.If i use while(1) not ICall_wait(),it can properly start after watchdog timeout.
  • The call stack you give above is should be long before ICall is even started. What do you mean it would not start properly with this ICall_wait, do you mean this gives you the same call stack as above? If so, how do you read this out without having the debugger connected?

    Also, could you share some insight on how this "epdWatchdogStart" function works and what it does?

  • M-W,

    1. When the debugger is not connected, CC2630 also can NOT reset successfully. 

    2. The function is copied from attached demo code. 

    3. From debugging, we do see if remove the ICALL_WAIT, the chip can successful reset.

    #include <stdbool.h>
    #include <stdint.h>
    #include <stdlib.h>
    #include <xdc/std.h>
    #include <xdc/runtime/Error.h>
    #include <xdc/runtime/System.h>
    #include <ti/sysbios/BIOS.h>
    #include <ti/sysbios/knl/Clock.h>
    #include <ti/sysbios/family/arm/m3/Hwi.h>
    #include <ti/sysbios/knl/Semaphore.h>
    #include <ti/sysbios/family/arm/cc26xx/Power.h>
    #include <ti/drivers/PIN.h>
    #include <string.h>
    #include <inc/hw_ints.h>
    #include "ICall.h"
    #include "Macs.h"
    #include "MacStackMSG.h"
    #include <aon_event.h>
    #include <ioc.h>
    #include "Board.h"
    
    #include "watchdogp.h"
    #include "epdwatchdog.h"
    extern uint32_t halTime2Ticks(uint32 ms);
    
    WatchdogCC26XX_Object watchdogCC26XXObjects[CC26X2R1_LAUNCHXL_WATCHDOGCOUNT];
    
    const WatchdogCC26XX_HWAttrs watchdogCC26XXHWAttrs[CC26X2R1_LAUNCHXL_WATCHDOGCOUNT] = {
        {
            .baseAddr    = WDT_BASE,
            .reloadValue = WDT_TIMEOUT_MS /* Reload value in milliseconds */
        },
    };
    
    const Watchdog_Config Watchdog_config[CC26X2R1_LAUNCHXL_WATCHDOGCOUNT] = {
        {
            .fxnTablePtr = &WatchdogCC26XX_fxnTable,
            .object      = &watchdogCC26XXObjects[CC26X2R1_LAUNCHXL_WATCHDOG0],
            .hwAttrs     = &watchdogCC26XXHWAttrs[CC26X2R1_LAUNCHXL_WATCHDOG0]
        },
    };
    
    const uint_least8_t Watchdog_count = CC26X2R1_LAUNCHXL_WATCHDOGCOUNT;
    
    /* Default Watchdog parameters structure */
    const Watchdog_Params Watchdog_defaultParams = {
        NULL,                    /* callbackFxn */
        Watchdog_RESET_ON,       /* resetMode */
        Watchdog_DEBUG_STALL_ON, /* debugStallMode */
        NULL                     /* custom */
    };
    
    static bool isInitialized = false;
    
    /*
     *  ======== Watchdog_clear ========
     */
    void Watchdog_clear(Watchdog_Handle handle)
    {
        handle->fxnTablePtr->watchdogClear(handle);
    }
    
    /*
     *  ======== Watchdog_close ========
     */
    void Watchdog_close(Watchdog_Handle handle)
    {
        handle->fxnTablePtr->watchdogClose(handle);
    }
    
    /*
     *  ======== Watchdog_control ========
     */
    int_fast16_t Watchdog_control(Watchdog_Handle handle, uint_fast16_t cmd,
                                  void *arg)
    {
        return (handle->fxnTablePtr->watchdogControl(handle, cmd, arg));
    }
    
    /*
     *  ======== Watchdog_init ========
     */
    void Watchdog_init(void)
    {
        uint_least8_t i;
        uint_fast32_t key;
    
        key = Hwi_disable();
    
        if (!isInitialized) {
            isInitialized = (bool) true;
    
            /* Call each driver's init function */
            for (i = 0; i < Watchdog_count; i++) {
                Watchdog_config[i].fxnTablePtr->watchdogInit((Watchdog_Handle)&(Watchdog_config[i]));
            }
        }
    
        Hwi_restore(key);
    }
    
    /*
     *  ======== Watchdog_open ========
     */
    Watchdog_Handle Watchdog_open(uint_least8_t index, Watchdog_Params *params)
    {
        Watchdog_Handle handle = NULL;
    
        /* Verify driver index and state */
        if (isInitialized && (index < Watchdog_count)) {
            /* If params are NULL use defaults */
            if (params == NULL) {
                params = (Watchdog_Params *) &Watchdog_defaultParams;
            }
    
            handle = (Watchdog_Handle)&(Watchdog_config[index]);
            handle = handle->fxnTablePtr->watchdogOpen(handle, params);
        }
    
        return (handle);
    }
    
    /*
     *  ======== Watchdog_Params_init ========
     */
    void Watchdog_Params_init(Watchdog_Params *params)
    {
        *params = Watchdog_defaultParams;
    }
    
    
    /*
     *  ======== Watchdog_setReload ========
     */
    int_fast16_t Watchdog_setReload(Watchdog_Handle handle, uint32_t ticks)
    {
        return (handle->fxnTablePtr->watchdogSetReload(handle, ticks));
    }
    
    /*
     *  ======== Watchdog_convertMsToTicks ========
     */
    uint32_t Watchdog_convertMsToTicks(Watchdog_Handle handle, uint32_t milliseconds)
    {
        return (handle->fxnTablePtr->watchdogConvertMsToTicks(handle, milliseconds));
    }
    
    /* Watchdog function table for CC26XX implementation */
    const Watchdog_FxnTable WatchdogCC26XX_fxnTable = {
        WatchdogCC26XX_clear,
        WatchdogCC26XX_close,
        WatchdogCC26XX_control,
        WatchdogCC26XX_init,
        WatchdogCC26XX_open,
        WatchdogCC26XX_setReload,
        WatchdogCC26XX_convertMsToTicks
    };
    
    /* Maximum allowable setReload value */
    #define MAX_RELOAD_VALUE        0xFFFFFFFF
    #define WATCHDOG_DIV_RATIO      32            /* Watchdog division ratio */
    #define MS_RATIO                1000          /* millisecond to second ratio */
    
    /*
     *  ======== WatchdogCC26XX_clear ========
     */
    void WatchdogCC26XX_clear(Watchdog_Handle handle)
    {
        WatchdogIntClear();
    }
    
    /*
     *  ======== WatchdogCC26XX_close ========
     */
    void WatchdogCC26XX_close(Watchdog_Handle handle)
    {
        /*
         *  Not supported for CC26XX - Once the INTEN bit of the WDTCTL
         *  register has been set, it can only be cleared by a hardware
         *  reset.
         */
    //    DebugP_assert(false);
    }
    
    /*
     *  ======== WatchdogCC26XX_control ========
     *  @pre    Function assumes that the handle is not NULL
     */
    int_fast16_t WatchdogCC26XX_control(Watchdog_Handle handle, uint_fast16_t cmd,
            void *arg)
    {
        /* No implementation yet */
        return (Watchdog_STATUS_UNDEFINEDCMD);
    }
    
    /*
     *  ======== Watchdog_init ========
     */
    void WatchdogCC26XX_init(Watchdog_Handle handle)
    {
        WatchdogCC26XX_Object *object = handle->object;
    
        object->isOpen = false;
    }
    
    /*
     *  ======== WatchdogCC26XX_open ========
     */
    Watchdog_Handle WatchdogCC26XX_open(Watchdog_Handle handle, Watchdog_Params *params)
    {
        unsigned int                   key;
    //    HwiP_Params                     hwiParams;
        WatchdogCC26XX_Object         *object;
    
        /* get the pointer to the object and hwAttrs */
        object = handle->object;
    
        /* disable preemption while checking if the WatchDog is open. */
        key = Hwi_disable();
    
        /* Check if the Watchdog is open already with the HWAttrs */
        if (object->isOpen == true) {
            Hwi_restore(key);
    //        DebugP_log1("Watchdog: Handle %x already in use.", (uintptr_t)handle);
            return (NULL);
        }
    
        object->isOpen = true;
        Hwi_restore(key);
    
        /* initialize the Watchdog object */
        object->debugStallMode = params->debugStallMode;
        object->resetMode      = params->resetMode;
    
        /* Construct Hwi object for Watchdog */
        /*
        HwiP_Params_init(&hwiParams);
        hwiParams.arg = (uintptr_t)handle;
        */
    
        /* setup callback function if defined */
        if (params->callbackFxn != NULL) {
            Hwi_plug(INT_NMI_FAULT, (void *)params->callbackFxn);
        }
    
        /* initialize the watchdog hardware */
        WatchdogCC26XX_initHw(handle);
    
    //    DebugP_log1("Watchdog: handle %x opened" ,(uintptr_t)handle);
    
        /* return handle of the Watchdog object */
        return (handle);
    }
    
    /*
     *  ======== WatchdogCC26XX_setReload ========
     */
    int_fast16_t WatchdogCC26XX_setReload(Watchdog_Handle handle, uint32_t ticks)
    {
        unsigned int                   key;
    
        /* disable preemption while unlocking WatchDog registers */
        key = Hwi_disable();
    
        /* unlock the Watchdog configuration registers */
        WatchdogUnlock();
    
        /* make sure the Watchdog is unlocked before continuing */
        while(WatchdogLockState() == WATCHDOG_LOCK_LOCKED)
        { }
    
        /* update the reload value */
        WatchdogReloadSet(ticks);
    
        /* lock register access */
        WatchdogLock();
    
        Hwi_restore(key);
    
    //    DebugP_log2("Watchdog: WDT with handle 0x%x has been set to "
    //        "reload to 0x%x", (uintptr_t)handle, ticks);
    
        return (Watchdog_STATUS_SUCCESS);
    }
    
    /*
     *  ======== WatchdogCC26XX_hwInit ========
     *  This function initializes the Watchdog hardware module.
     *
     *  @pre    Function assumes that the Watchdog handle is pointing to a hardware
     *          module which has already been opened.
     */
    void WatchdogCC26XX_initHw(Watchdog_Handle handle) {
        unsigned int                   key;
        uint32_t                       tickValue;
        WatchdogCC26XX_Object          *object;
        WatchdogCC26XX_HWAttrs const   *hwAttrs;
    
        /* get the pointer to the object and hwAttrs */
        object = handle->object;
        hwAttrs = handle->hwAttrs;
    
        /* convert milliseconds to watchdog timer ticks */
        tickValue = WatchdogCC26XX_convertMsToTicks(handle, hwAttrs->reloadValue);
    
        /* disable preemption while unlocking WatchDog registers */
        key = Hwi_disable();
    
        /* unlock the Watchdog configuration registers */
        WatchdogUnlock();
    
        /* make sure the Watchdog is unlocked before continuing */
        while(WatchdogLockState() == WATCHDOG_LOCK_LOCKED)
        { }
    
        WatchdogReloadSet(tickValue);
    
        /* set reset mode */
        if (object->resetMode == Watchdog_RESET_ON) {
            WatchdogResetEnable();
        }
        else {
            WatchdogResetDisable();
        }
    
        /* set debug stall mode */
        if (object->debugStallMode == Watchdog_DEBUG_STALL_ON) {
            WatchdogStallEnable();
        }
        else {
            WatchdogStallDisable();
        }
    
        /* enable the Watchdog interrupt as a non-maskable interrupt */
        WatchdogIntTypeSet(WATCHDOG_INT_TYPE_NMI);
    
        /* enable the Watchdog */
        WatchdogEnable();
    
        /* lock the Watchdog configuration registers */
        WatchdogLock();
    
        Hwi_restore(key);
    }
    
    /*
     *  ======== WatchdogCC26XX_convertMsToTicks ========
     *  This function converts the input value from milliseconds to
     *  Watchdog clock ticks.
     */
    uint32_t WatchdogCC26XX_convertMsToTicks(Watchdog_Handle handle,
        uint32_t milliseconds)
    {
        uint32_t wdtTicks;
    
        wdtTicks = milliseconds*8;
    //    wdtTicks = milliseconds;
        wdtTicks = halTime2Ticks(wdtTicks);
        return wdtTicks;
    }
        
    Watchdog_Handle watchdogHd = NULL;
    void epdWatchdogClear(void)
    {
        if(watchdogHd)
        {
            Watchdog_clear(watchdogHd);
        }
    }
    
    void epdWatchdogStart(void)
    {
        Watchdog_Params params;
        uint32_t timeout;
    
        Watchdog_init();
        Watchdog_Params_init(&params);
        params.resetMode = Watchdog_RESET_ON;
    
        watchdogHd = Watchdog_open(0, &params);
    
        if(NULL != watchdogHd)
        {
            timeout = WatchdogCC26XX_convertMsToTicks(watchdogHd, WDT_TIMEOUT_MS);
            Watchdog_setReload(watchdogHd, timeout);
        }
    }
    
    

  • Hi,

    Would you be able to put together a simple example project and share with me so that I may debug it locally?
  • Due size limitation, the example code is put on below link
    pan.baidu.com/.../1O6dG6KGcJDnswRpMjO6LPA
    passcode: uuqi
  • No matter Run this device with the debugger attach. Properly start after watchdog timeout without I call wait. It would not start properly with I call wait.

  • Hi Morris,

    I tested your code by taking the untouched stack example (<TIMAC SDK>/Projects/mac/Sample/cc26xx_RTOS/IAR Projects/Application/CC2650) and adding in your changes instead of calling the "msa_task()" which was originally done. I also added in turning on a LED right after enabling the watchdog to see if we are able to reset as intended (in theory it should blink if we get proper resets from the watchdog).

    This resulted in the following task function:

    Void taskFxn(UArg a0, UArg a1)
    {
    #if defined( USE_FPGA )
      SysCtrlPowerEverything();
      Power_setConstraint(Power_SB_DISALLOW);
      Power_setDependency(PERIPH_RFCORE, Power_GLOBAL);
    #endif  
    
      /* Disallow shutting down JTAG, VIMS, SYSBUS during idle state
       * since TIMAC requires SYSBUS during idle. */
      Power_setConstraint(Power_IDLE_PD_DISALLOW);
    
      /* Initialize ICall module */
      ICall_init();
    //
    #ifdef FEATURE_MAC_SECURITY
       CryptoCC26XX_Params CryptoCC26XXParams;
       extern CryptoCC26XX_Handle CryptoCC26XXHandle;
    
       CryptoCC26XX_init();
       CryptoCC26XX_Params_init(&CryptoCC26XXParams);
       CryptoCC26XXHandle = CryptoCC26XX_open(Board_CRYPTO, false, &CryptoCC26XXParams);
       if (!CryptoCC26XXHandle)
       {
         Task_exit();
       }
       Crypto_init();
       
       /*
        * Copy the extended address from the CCFG area
        * Assumption: the memory in CCFG_IEEE_MAC_0 and CCFG_IEEE_MAC_1
        * is contiguous and LSB first.
        */
        memcpy(msa_ExtAddr,
               (uint8_t *)&(__ccfg.CCFG_IEEE_MAC_0), EXTADDR_LEN);
    
        /* Check to see if the CCFG IEEE is valid */
        if(memcmp(msa_ExtAddr, dummyExtAddr, EXTADDR_LEN) == 0)
        {
          /* No, it isn't valid.  Get the Primary IEEE Address */
          memcpy(msa_ExtAddr,
                 (uint8_t *)(FCFG1_BASE + EXTADDR_OFFSET), EXTADDR_LEN);
        }
    #endif
    // 
    #ifdef NV_RESTORE
      /* Setup the NV driver */
      NVOCTP_loadApiPtrs( &user1Cfg.nvFps );
    
      if ( user1Cfg.nvFps.initNV )
      {
        user1Cfg.nvFps.initNV( NULL );
      }
      
      pfnMacCfgNvFps = &user1Cfg.nvFps;
    
    #endif
    //   
      /* Start tasks of external images */
      ICall_createRemoteTasks();
    
        /* Kick off application */
        PRCMPowerDomainOn(PRCM_DOMAIN_PERIPH);
        PRCMPeripheralRunEnable(PRCM_PERIPH_GPIO);
        PRCMLoadSet();
        while (!PRCMLoadGet()) {
                    ;
                }
        Task_sleep(100000);
        epdWatchdogStart();
        IOCPinTypeGpioOutput(IOID_6);
        while(1)
        {
            GPIOPinWrite(GPIO_PIN_6, 1);
            ICall_wait(ICALL_TIMEOUT_FOREVER);
        }
    }

    I tested this out on a CC2650 launchpad and I did not see the problem you describe as the device was able to reset as expected. I assume you are seeing this problem on your own custom hardware, could you in this case reproduce it on a launchpad?

    I had some problems to run it using your main file, this was related to "FEATURE_MAC_SECURITY" being defined in both the application and stack project, removing this define let me run the test. As you are not initializing the crypto in the example you provided, have you disabled this feature in both projects?

  • Hi M-W,

     

    You tell me that you tested on a CC2650 and did not see the problem.

    We tested on a CC2650 and did not see the problem we describe. The result is the same with you!

    Only see the problem when we test on a CC2630. Would you please test on a CC2630?

     

    Thanks,

    Morris.Yang

  • Hi Morris,

    There should be no difference between the CC2630 and CC2650, the later is the development platform for the former. The code should be binary compatible between the two devices when going from CC2630 -> CC2650.

    In your test I assume the difference is that the CC2650 is a development platform and the CC2630 sits on custom hardware, is that correct?

  • Hi M-W,

    The problem when we tested on a CC2630. But you tested on a CC2650.
    We tested on CC2630 Launchpad and customer hardware. And see the problem we describe.
    We Only see the problem when we test on a CC2630. Please test on a CC2630.

    Thanks,
    Morris.Yang
  • Hi Morris,

    There is no CC2630 LaunchPad, only CC2650 LaunchPad. I was told you did not see this issue while testing on the CC2650 which I would guess is the LaunchPad. I would take a check at the hardware and backdoor boot code and see if there is a conflict there.

    In startup_iar.c you can find "BackdoorCheck" which is the place your callstack says you are stuck in when testing your custom hardware. This function is set to trap the device if a "button" is pressed. This in the original example file this is IOID11.
    If I take the working CC2650 example test and ground IOID11, I will also halt in the same location as you do following a reset. Could you verify on your custom hardware if this is the case?