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.

CC3220MODA: Cannot hibernate after calling Power_enablePolicy()

Part Number: CC3220MODA

Hi Support,

I'm trying to write a simple example where my device goes into LPDS, wakes, and then hibernates. However, I'm having trouble getting my custom hardware to hibernate after it enters LPDS.

When I remove the Power_enablePolicy() call, the hibernation functionality works as expected (without LPDS).
Any ideas about what might be happening here?
I'm using SDK 2.40.

Thanks,
Brian

// main.c

void mainThread(void *pvParameters)
{
    int32_t             status = 0;
    pthread_t           spawn_thread = (pthread_t)NULL;
    struct timespec     ts = {0};
    pthread_attr_t      pAttrs_spawn;
    struct sched_param  priParam;
    long sysResetCause;
    long lpdsWakeupCause;
    uint32_t constraints;

    /* initialize the realtime clock */
    clock_settime(CLOCK_REALTIME, &ts);
    
    /* Create a thread for and start the SimpleLink Host */
    pthread_attr_init(&pAttrs_spawn);
    priParam.sched_priority = 9;
    status = pthread_attr_setschedparam(&pAttrs_spawn, &priParam);
    status |= pthread_attr_setstacksize(&pAttrs_spawn, SL_TASKSTACKSIZE);
    status |= pthread_create(&spawn_thread, &pAttrs_spawn, sl_Task, NULL);
    if (status < 0)
        powerShutdown(20 * 1000L);  // 20 seconds

    GPIO_init();
    SPI_init();
    InitTerm();
    I2C_init();

    UART_PRINT("\r\nStart.");
    sysResetCause = PRCMSysResetCauseGet();
    lpdsWakeupCause = PRCMLPDSWakeupCauseGet();
    UART_PRINT("\r\nReset = 0x%x; LPDS Wakeup = 0x%x", sysResetCause, lpdsWakeupCause);
    sleep(2);

    Power_enablePolicy();     // Hibernate functions correctly without this line
    UART_PRINT("\r\nSleep #1...");
    sleep(2);
    sysResetCause = PRCMSysResetCauseGet();
    lpdsWakeupCause = PRCMLPDSWakeupCauseGet();
    UART_PRINT("\r\nReset = 0x%x; LPDS Wakeup = 0x%x", sysResetCause, lpdsWakeupCause);
    UART_PRINT("\r\nDone.");
    Power_disablePolicy();
    sleep(3);

    UART_PRINT("\r\nHibernate.");

    constraints = Power_getConstraintMask();
    UART_PRINT("\r\nConstraints = 0x%x", constraints);

    status = Power_getTransitionState();
    UART_PRINT("\r\nTransition State = %d", status);

    status = powerShutdown(10 * 1000L);  // 10 seconds
    UART_PRINT("\r\nHibernate Status = %d", status);

    status = Power_getTransitionState();
    UART_PRINT("\r\nTransition State = %d", status);

    UART_PRINT("\r\nSTOP: I shouldn't see this message.");
}

extern void WiFi_enterLPDSHookFxn()
{
    UART_PRINT("\r\n>> WiFi_enterLPDSHookFxn");
}

extern void WiFi_resumeLPDSHookFxn()
{
    InitTerm();
    UART_PRINT("\r\n>> WiFi_resumeLPDSHookFxn");
}

// CC3220S_LAUNCHXL.c

const PowerCC32XX_ConfigV1 PowerCC32XX_config = {
    .policyInitFxn = &PowerCC32XX_initPolicy,
    .policyFxn = &PowerCC32XX_sleepPolicy,
    .enterLPDSHookFxn = &WiFi_enterLPDSHookFxn,
    .resumeLPDSHookFxn = &WiFi_resumeLPDSHookFxn,
    .enablePolicy = false,
    .enableGPIOWakeupLPDS = true,
    .enableGPIOWakeupShutdown = true,
    .enableNetworkWakeupLPDS = true,
    .wakeupGPIOSourceLPDS = PRCM_LPDS_GPIO2,    // UART RX
    .wakeupGPIOTypeLPDS = PRCM_LPDS_RISE_EDGE,
    .wakeupGPIOFxnLPDS = NULL,
    .wakeupGPIOFxnLPDSArg = 0,
    .wakeupGPIOSourceShutdown = PRCM_HIB_GPIO4, // push button
    .wakeupGPIOTypeShutdown = PRCM_HIB_RISE_EDGE,
    .ramRetentionMaskLPDS = PRCM_SRAM_COL_1 | PRCM_SRAM_COL_2 |
        PRCM_SRAM_COL_3 | PRCM_SRAM_COL_4,
    .keepDebugActiveDuringLPDS = false,
    .ioRetentionShutdown = PRCM_IO_RET_GRP_1,
    .pinParkDefs = parkInfo,
    .numPins = sizeof(parkInfo) / sizeof(PowerCC32XX_ParkInfo)
};

Failing to hibernate:

Start. 
Reset = 0x1; LPDS Wakeup = 0x1     // LPDS woken from PRCM_LPDS_TIMER
Sleep #1... 
Reset = 0x1; LPDS Wakeup = 0x1 
Done. 
Hibernate. 
Constraints = 0x0 
Transition State = 2    // Power_ENTERING_SLEEP
Hibernate Status = -5   // Power_EBUSY
Transition State = 1    // Power_ACTIVE
STOP: I shouldn't see this message. 
Start. 
Reset = 0x5; LPDS Wakeup = 0x0     // 16-second watchdog (PRCM_WDT_RESET)
Sleep #1... 
>> WiFi_enterLPDSHookFxn 
Start. 
Reset = 0x1; LPDS Wakeup = 0x1 
Sleep #1... 
Reset = 0x1; LPDS Wakeup = 0x1 
Done. 
Hibernate. 
Constraints = 0x0 
Transition State = 2 
Hibernate Status = -5 
Transition State = 1 
STOP: I shouldn't see this message. 
Start. 
Reset = 0x5; LPDS Wakeup = 0x0 
Sleep #1... 
>> WiFi_enterLPDSHookFxn 
Start.

Hibernating correctly, without Power_enablePolicy() call:

Sleep #1...
Reset = 0x0; LPDS Wakeup = 0x0
Done.
Hibernate.
Constraints = 0x0
Transition State = 1
Start.
Reset = 0x7; LPDS Wakeup = 0x0     // Hibernate successfully (PRCM_HIB_EXIT)
Sleep #1...
Reset = 0x7; LPDS Wakeup = 0x0
Done.
Hibernate.
Constraints = 0x0
Transition State = 1
Start.
Reset = 0x7; LPDS Wakeup = 0x0

  • Hi Brian,

    It looks like you are printing out PowerCC32XX_module.state in your logs, and when you try to enter hibernate, the power policy is already preparing to enter LPDS (sleep). When you get Power_EBUSY, can you try again?

    You can also disable the power policy before you enter hibernate. When the application wakes from hibernate, the power policy will need to be re-enabled again anyway. The power policy will stop running in the idle loop (how you automatically enter LPDS), but it keeps the wake configurations set in Power_init().

    Best regards,

    Sarah

  • Hi Sarah,

    I'm calling Power_disablePolicy() in line #44. Is there anything that would cause this function call to fail?
    Invoking a hibernate a second time appears to clear the Power_EBUSY and successfully enter hibernation. However, the application then trips the watchdog (0x5), which is not tripped (0x7) when the power policy is never enabled.
        status = powerShutdown(10 * 1000L);  // 10 seconds
        UART_PRINT("\r\nHibernate Status = %d", status);
        status = powerShutdown(10 * 1000L);  // 10 seconds
        UART_PRINT("\r\nHibernate Status = %d", status);
    Start.
    Reset = 0x1; LPDS Wakeup = 0x1
    Sleep #1...
    Reset = 0x1; LPDS Wakeup = 0x1
    Done.
    Hibernate.
    Constraints = 0x0
    Transition State = 2
    Hibernate Status = -5
    Start.
    Reset = 0x5; LPDS Wakeup = 0x0
    Sleep #1...
    >> WiFi_enterLPDSHookFxn
    Start.
    Reset = 0x1; LPDS Wakeup = 0x1
    Sleep #1...
    Reset = 0x1; LPDS Wakeup = 0x1
    Done.
    Hibernate.
    Constraints = 0x0
    Transition State = 2
    Hibernate Status = -5
  • Hi Brian,

    After disabling the power policy, can you check if Power_idleFunc() is still being called? You can copy the file source/ti/drivers/power/PowerCC32xx.c into your CCS project for easy debugging.

    It also looks like there is a Power_registerNotify() in the watchdog driver that automatically reconfigures the peripheral when exiting from LPDS, but not from hibernate.

    Best regards,

    Sarah

  • Hi Sarah,

    After disabling the power policy, can you check if Power_idleFunc() is still being called? You can copy the file source/ti/drivers/power/PowerCC32xx.c into your CCS project for easy debugging.

    Sorry, I'm struggling to follow your instructions on checking if Power_idleFunc() is being called.

    However, I tried updating to the latest SDK (5.20). Even with the new SDK, I'm still getting an error code when attempting to hibernate.

    Start. 
    Reset = 0x1; LPDS Wakeup = 0x1 
    Sleep #1... 
    Reset = 0x1; LPDS Wakeup = 0x1 
    Done. 
    Hibernate. 
    Constraints = 0x0 
    Transition State = 2 
    Hibernate Status = -5

    But if I set a constraint on the LPDS then the application works like I expect:

        Power_setConstraint(PowerCC32XX_DISALLOW_LPDS); // <==
        Power_enablePolicy();
        UART_PRINT("\r\nSleep #1...");
        sleep(2);
        sysResetCause = PRCMSysResetCauseGet();
        lpdsWakeupCause = PRCMLPDSWakeupCauseGet();
        UART_PRINT("\r\nReset = 0x%x; LPDS Wakeup = 0x%x", sysResetCause, lpdsWakeupCause);
        UART_PRINT("\r\nDone.");
        Power_disablePolicy();
        Power_releaseConstraint(PowerCC32XX_DISALLOW_LPDS); // <==
        sleep(3);

    Reset = 0x0; LPDS Wakeup = 0x0 
    Done. 
    Hibernate. 
    Constraints = 0x0 
    Transition State = 1 
    Start. 
    Reset = 0x7; LPDS Wakeup = 0x0 
    Sleep #1... 
    Reset = 0x7; LPDS Wakeup = 0x0 
    Done. 
    Hibernate. 
    Constraints = 0x0 
    Transition State = 1 
    Start. 
    Reset = 0x7; LPDS Wakeup = 0x0 
    Sleep #1... 
    Reset = 0x7; LPDS Wakeup = 0x0 
    Done. 
    Hibernate. 
    Constraints = 0x0 
    Transition State = 1

    Thanks,
    Brian

  • Hi Sarah,

    Currently, I am using the power_measure.c demo as the foundation of my example. Does TI have other LPDS example code? An example that utilizes the hook functions and wakes from LPDS via an interrupt would be particularly appreciated.

    Thanks,
    Brian

  • Hi Brian,

    If you copy PowerCC32xx.c into your project, you can set a breakpoint inside Power_idleFunch. Or add a print.

    Setting the power constraint before you enter hibernate is a good workaround as well.

    The portable demo in the SDK uses the power policy with a GPIO wake and simple hook.

    Best regards,

    Sarah

  • Hi Sarah,

    Please see the results below from copying the PowerCC32XX driver into my source code.

    I will take a look at the portable demo.

    Thanks,
    Brian

    /*
     *  ======== Power_idleFunc ========
     *  Function needs to be plugged into the idle loop.
     *  It calls the configured policy function if the
     *  'enablePolicy' flag is set.
     */
    void Power_idleFunc()
    {
        UART_PRINT("\r\nPower_idleFunc");
        if (PowerCC32XX_module.enablePolicy) {
            UART_PRINT("\r\nPower_idleFunc => policy enabled");
            if (PowerCC32XX_module.policyFxn != NULL) {
                UART_PRINT("\r\nPower_idleFunc: calling policy function (%p)",
                    (uintptr_t) PowerCC32XX_module.policyFxn);
                (*(PowerCC32XX_module.policyFxn))();
            }
        }
    }

    Start.
    Reset = 0x1; LPDS Wakeup = 0x1
    Power_idleFunc
    Power_idleFunc => policy enabled
    Power_idleFunc: calling policy function (0x2000ea15)
    ...
    Power_idleFunc
    Power_idleFunc => policy enabled
    Power_idleFunc: calling policy function (0x2000ea15)
    Sleep #1...
    Power_idleFunc
    Power_idleFunc => policy enabled
    Power_idleFunc: calling policy function (0x2000ea15)
    ...
    Power_idleFunc
    Power_idleFunc => policy enabled
    Power_idleFunc: calling policy function (0x2000ea15)
    Reset = 0x1; LPDS Wakeup = 0x1
    Done.
    Power_idleFunc
    Power_idleFunc
    Power_idleFunc
    ...
    Power_idleFunc
    Power_idleFunc
    Power_idleFunc
    Hibernate.
    Constraints = 0x0
    Transition State = 2
    Hibernate Status = -5
    Start.
    Reset = 0x5; LPDS Wakeup = 0x0
    Power_idleFunc
    Power_idleFunc
    Power_idleFunc
    ...
    Power_idleFunc
    Power_idleFunc
    Power_idleFunc
    Sleep #1...
    Power_idleFunc
    Power_idleFunc => policy enabled
    Power_idleFunc: calling policy function (0x2000ea15)
    >> WiFi_enterLPDSHookFxn
    Start.
    Reset = 0x1; LPDS Wakeup = 0x1
    Power_idleFunc
    Power_idleFunc => policy enabled
    Power_idleFunc: calling policy function (0x2000ea15)
    Power_idleFunc
    Power_idleFunc => policy enabled
    Power_idleFunc: calling policy function (0x2000ea15)
    ...
    Power_idleFunc
    Power_idleFunc => policy enabled
    Power_idleFunc: calling policy function (0x2000ea15)
    Sleep #1...
    Power_idleFunc
    Power_idleFunc => policy enabled
    Power_idleFunc: calling policy function (0x2000ea15)
    ...
    Power_idleFunc
    Power_idleFunc => policy enabled
    Power_idleFunc: calling policy function (0x2000ea15)
    Reset = 0x1; LPDS Wakeup = 0x1
    Done.
    Power_idleFunc
    Power_idleFunc
    Power_idleFunc
    ...
    Power_idleFunc
    Power_idleFunc
    Power_idleFunc
    Hibernate.
    Constraints = 0x0
    Transition State = 2
    Hibernate Status = -5

  • Hi Sarah,

    I was able to resolve my issue.

    It appears there is an issue with using UART in the LPDS resume hook. When I removed this callback from the configuration settings the code runs correctly.

    Are there any examples of using the LPDS hooks functions in the SDK demos?

    Thanks,
    Brian

    // main.c
    extern void WiFi_resumeLPDSHookFxn()
    {
        InitTerm();
        UART_PRINT("\r\n>> WiFi_resumeLPDSHookFxn");
    }

    // CC3220S_LAUNCHXL.c
    const PowerCC32XX_ConfigV1 PowerCC32XX_config = {
        .policyInitFxn = &PowerCC32XX_initPolicy,
        .policyFxn = &PowerCC32XX_sleepPolicy,
        .enterLPDSHookFxn = &WiFi_enterLPDSHookFxn,
        .resumeLPDSHookFxn = NULL,    // <== ** Removed hook **
        .enablePolicy = false,
        .enableGPIOWakeupLPDS = true,
        .enableGPIOWakeupShutdown = true,
        .enableNetworkWakeupLPDS = true,
        .wakeupGPIOSourceLPDS = PRCM_LPDS_GPIO2,
        .wakeupGPIOTypeLPDS = PRCM_LPDS_RISE_EDGE,
        .wakeupGPIOFxnLPDS = NULL,
        .wakeupGPIOFxnLPDSArg = 0,
        .wakeupGPIOSourceShutdown = PRCM_HIB_GPIO4,
        .wakeupGPIOTypeShutdown = PRCM_HIB_RISE_EDGE,
        .ramRetentionMaskLPDS = PRCM_SRAM_COL_1 | PRCM_SRAM_COL_2 |
            PRCM_SRAM_COL_3 | PRCM_SRAM_COL_4,
        .keepDebugActiveDuringLPDS = false,
        .ioRetentionShutdown = PRCM_IO_RET_GRP_1,
        .pinParkDefs = parkInfo,
        .numPins = sizeof(parkInfo) / sizeof(PowerCC32XX_ParkInfo)
    };

    Start.
    Reset = 0x7; LPDS Wakeup = 0x0
    Sleep #1...
    >> WiFi_enterLPDSHookFxn
    Reset = 0x1; LPDS Wakeup = 0x1
    Done.
    Hibernate.
    Constraints = 0x0
    Transition State = 1
    Start.
    Reset = 0x7; LPDS Wakeup = 0x0
    Sleep #1...
    >> WiFi_enterLPDSHookFxn
    Reset = 0x1; LPDS Wakeup = 0x1
    Done.
    Hibernate.
    Constraints = 0x0
    Transition State = 1
    Start.
    Reset = 0x7; LPDS Wakeup = 0x0
    Sleep #1...
    >> WiFi_enterLPDSHookFxn
    Reset = 0x1; LPDS Wakeup = 0x1
    Done.
    Hibernate.
    Constraints = 0x0
    Transition State = 1
    

  • Hi Brian,

    Ah, I didn't catch the UART prints in the LPDS resume hook. Driver commands should not be used in that hook, as it executes before the peripherals are re-initialized. This means this hook is best used with a non-blocking semaphore or message queue that can trigger a thread once the policy has exited LPDS. The GPIO wake hook is safe though.

    This explains the watchdog issue, but I'm not sure yet why it would keep the power policy from entering hibernate. I'm glad it's now working for you!

    Best regards,

    Sarah

  • Hi Sarah,

    Thanks for the explanation on the drivers in the resume hook.

    My 2 cents on the hibernation failure:
    It seems like calling the LPDS resume hook (when it contained the UART call) was causing a soft system reset. When the application tried to resume from LPDS it restarted the application. But perhaps the power driver was not reset or re-initialized at that time and thus was responding as BUSY.

    Start.                             // <== app started
    Reset = 0x5; LPDS Wakeup = 0x0     // 16-second watchdog (PRCM_WDT_RESET)
    Sleep #1... 
    >> WiFi_enterLPDSHookFxn 
    Start.                             // <== app restarted
    Reset = 0x1; LPDS Wakeup = 0x1 
    Sleep #1... 
    Reset = 0x1; LPDS Wakeup = 0x1 
    Done. 
    Hibernate. 
    Constraints = 0x0 
    Transition State = 2 
    Hibernate Status = -5 
    Transition State = 1 
    STOP: I shouldn't see this message.

    Thanks for your assistance,
    Brian