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.

LPDS mode in CC3200

Other Parts Discussed in Thread: CC3200

Hi 

we are working on CC3200. and we come across the LPDS mode. 

According to datasheet, memory retention handled during LPDS mode. we would like to know the following things.

-> What is the actual purpose of this mode?

-> Where this memory retention is being handled, either in bootloader or application ?

-> If it is in application side then how to do this?

Please share if any specific documentations regarding this LPDS mode are available.

Regards,

Hardik

  • Hi Hardik,

    Regarding the LPDS mode,

    -> What is the actual purpose of this mode?

    This is the lowest power mode that can be excersied while continuing to maintain the application context (by means of memory retention) and also the networking context (continue to maintain the WiFi connection) - with some entry-exit latency overheads.

    An example usecase of this mode is the "Idle-Connected profile" wherein the device is in its lowest power state (LPDS) while maintaining the connection with the AP. Whenever there is a packet over the network, the application processor wakes up from LPDS and services the packet (can be a command) and takes action.

    Note: The CPU and peripheral state is lost during entry into LPDS and it is the applications responsibility to take care of this.

    -> Where this memory retention is being handled, either in bootloader or application ?

    The memory retention has to be handled in the application and there are APIs to enable this.

    -> If it is in application side then how to do this?

    We have a power management framework that aids the entry-exit LPDS using some easy to use hooks. Most of the low level details of retaining the CPU and peripheral (only some UART, GPIO, SPI) context are abstracted out.

    Please refer to cc3200-sdk\docs\CC3200-Power_Management_Framework.pdf for documentation on the low power states and the power management framework.

    Also refer to the examples, "idle_profile" and "sensor_profile" for the implementation details.

    Best regards,

    Naveen

     

  • Hi,

    I have a few questions about LPDS. At first I reed a CC32xx Power Management Framework. Now, I look for understand idle_profile example and would like to ask next:

    Where it goes in LPDS mode in code? Is it always in sleep and when interrupt happend it done interrupt routine and again go to sleep???

    Thanks,

    Srdjan

  • Hi,

    I can not complete understand idle_profile example. Do you have any additional documentation or example, without RTOS???
    Confirm complete understand of sleep_deepsleep example, but now I want to understand LPDS.

    thanks

  • Hi Srdjan,

    You can look at the following functions for the LPDS settings:

    cc_set_up_wkup_srcs - To setup the wake sources for LPDS

    lp3p0_back_up_soc_data - Backup the SoC data

    cc_enter_S3 - Enters LPDS

    cc_handle_S3_wakeup,  lp3p0_restore_soc_data - Perform the restoration operations

    The files of interest will be cc3200-sdk\example\idle_profile\*, cc3200-sdk\middleware\framework\pm\*, cc3200-sdk\middleware\soc\*.

    Also refer to the setion "LPDS entry-exit sequence" to understand the sequence of operations that happen.

    Best regards,

    Naveen

  • Hi,

    now I clearly looked at this example. I want to make changes on my way.
    To have a CC3200 always in LPDS, wake up it every X seconds on timer interrupt
    and print message in timer interrupt.
    I made some changes in idli_profile example to achieve my goal, but it didn't work.
    Here is code:

    //*****************************************************************************
    //
    // Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ 
    // 
    // 
    //  Redistribution and use in source and binary forms, with or without 
    //  modification, are permitted provided that the following conditions 
    //  are met:
    //
    //    Redistributions of source code must retain the above copyright 
    //    notice, this list of conditions and the following disclaimer.
    //
    //    Redistributions in binary form must reproduce the above copyright
    //    notice, this list of conditions and the following disclaimer in the 
    //    documentation and/or other materials provided with the   
    //    distribution.
    //
    //    Neither the name of Texas Instruments Incorporated nor the names of
    //    its contributors may be used to endorse or promote products derived
    //    from this software without specific prior written permission.
    //
    //  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
    //  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
    //  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    //  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
    //  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
    //  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
    //  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    //  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    //  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
    //  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
    //  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    //
    //*****************************************************************************
    
    //*****************************************************************************
    //
    // Application Name     - Idle Profile
    // Application Overview - Idle profile enables the user to measure current
    //                        values, power consumption and other such parameters
    //                        for CC3200, when the device is essentially idle(both
    //                        NWP and APPS subsystems in low power deep sleep
    //                        condition). The other main objective behind this
    //                        application is to introduce the user to the easily
    //                        configurable power management framework.
    // Application Details  -
    // http://processors.wiki.ti.com/index.php/CC32xx_Idle_Profile_Application
    // or
    // docs\examples\CC32xx_Idle_Profile_Application.pdf
    //
    //*****************************************************************************
    
    //****************************************************************************
    //
    //! \addtogroup idle_profile
    //! @{
    //
    //****************************************************************************
    
    // Standard includes
    #include <string.h>
    
    //driverlib includes
    #include "hw_ints.h"
    #include "hw_types.h"
    #include "hw_memmap.h"
    #include "interrupt.h"
    #include "prcm.h"
    #include "wdt.h"
    #include "utils.h"
    #include "rom.h"
    #include "rom_map.h"
    
    //middleware includes
    #include "cc_types.h"
    #include "rtc_hal.h"
    #include "gpio_hal.h"
    #include "uart_drv.h"
    #include "cc_timer.h"
    #include "cc_pm_ops.h"
    
    // Common interface includes
    #include "wdt_if.h"
    
    #include "pinmux.h"
    
    
    #define APPLICATION_VERSION "1.1.0"
    //
    // Values for below macros shall be modified as per access-point(AP) properties
    // SimpleLink device will connect to following AP when application is executed
    //
    
    #define LPDS_DUR_SEC            3//60
    #define LPDS_DUR_NSEC           0
    #define FOREVER                 1
    #define BUFF_SIZE               1472
    #define SL_STOP_TIMEOUT         30
    #define OSI_STACK_SIZE          1024
    #define CONNECTION_RETRIES      5
    #define UART_PRINT(x)           uart_write(g_tUartHndl, x, strlen(x))
    
    #define MAP_SysCtlClockGet          80000000
    #define MILLISECONDS_TO_TICKS(ms)   ((MAP_SysCtlClockGet/1000) * (ms))
    
    enum ap_events{
        EVENT_CONNECTION = 0x1,
        EVENT_DISCONNECTION = 0x2,
        EVENT_IP_ACQUIRED = 0x4,
        WDOG_EXPIRED = 0x8,
        CONNECTION_FAILED = 0x10
    };
    
    //****************************************************************************
    //                      LOCAL FUNCTION PROTOTYPES
    //****************************************************************************
    static void DisplayBanner();
    void PrintIPAddr(unsigned int uiIpaddr);
    void TimerCallback(void *vParam);
    cc_hndl SetTimerAsWkUp();
    static void BoardInit();
    
    //*****************************************************************************
    //                 GLOBAL VARIABLES -- Start
    //*****************************************************************************
    #ifndef USE_TIRTOS
    #if defined(ccs) || defined(gcc)
    extern void (* const g_pfnVectors[])(void);
    #endif
    #if defined(ewarm)
    extern uVectorEntry __vector_table;
    #endif
    #endif
    
    #ifdef DEBUG_GPIO
    #define GPIO_09                    9
    cc_hndl tGPIODbgHndl;
    #endif
    
    cc_hndl g_tUartHndl;
    
    //*****************************************************************************
    //                 GLOBAL VARIABLES -- End
    //*****************************************************************************
    
    
    //*****************************************************************************
    //                      Local Function Prototypes
    //*****************************************************************************
    extern void lp3p0_setup_power_policy(int power_policy);
    extern int platform_init();
    
    // Loop forever, user can change it as per application's requirement
    #define LOOP_FOREVER() \
                {\
                    while(1); \
                }
    
    // check the error code and handle it
    #define ASSERT_ON_ERROR(error_code)\
                {\
                     if(error_code < 0) \
                       {\
                            sprintf(g_cErrBuff,"Error [%d] at line [%d] in "\
                                    "function [%s]", error_code,__LINE__,\
                                    __FUNCTION__);\
                            UART_PRINT(g_cErrBuff);\
                            UART_PRINT("\n\r");\
                            return error_code;\
                     }\
                }
    
    //*****************************************************************************
    //
    //! DisplayBanner
    //!
    //! \param  none
    //!
    //! \return none
    //!
    //*****************************************************************************
    static void
    DisplayBanner()
    {
        UART_PRINT("\n\n\n\r");
        UART_PRINT("\t\t   *********************************************\n\r");
        UART_PRINT("\t\t          CC3200 Idle Profile Application   \n\r");
        UART_PRINT("\t\t   *********************************************\n\r");
        UART_PRINT("\n\n\n\r");
    
    }
    
    //*****************************************************************************
    //
    //! Application defined hook (or callback) function - the tick hook.
    //! The tick interrupt can optionally call this
    //!
    //! \param  none
    //!
    //! \return none
    //!
    //*****************************************************************************
    void vApplicationTickHook( void )
    {
    }
    
    //*****************************************************************************
    //
    //! Application defined hook (or callback) function - assert
    //!
    //! \param  none
    //!
    //! \return none
    //!
    //*****************************************************************************
    void vAssertCalled( const char *pcFile, unsigned long ulLine )
    {
        while(1)
        {
        }
    }
    
    //*****************************************************************************
    //
    //! Application defined idle task hook
    //!
    //! \param  none
    //!
    //! \return none
    //!
    //*****************************************************************************
    void vApplicationIdleHook( void )
    {
        cc_idle_task_pm();
    }
    
    //*****************************************************************************
    //
    //! Application defined malloc fail hook
    //!
    //! \param  none
    //!
    //! \return none
    //!
    //*****************************************************************************
    void vApplicationMallocFailedHook()
    {
        while(1)
        {
        }
    }
    
    //*****************************************************************************
    //
    //! Application defined stack overflow hook
    //!
    //! \param  none
    //!
    //! \return none
    //!
    //*****************************************************************************
    void vApplicationStackOverflowHook()
    {
        while(1)
        {
        }
    }
    
    //*****************************************************************************
    //
    //! Board Initialization & Configuration
    //!
    //! \param  None
    //!
    //! \return None
    //
    //*****************************************************************************
    static void
    BoardInit(void)
    {
    /* In case of TI-RTOS vector table is initialize by OS itself */
    #ifndef USE_TIRTOS
      //
      // Set vector table base
      //
    #if defined(ccs) || defined(gcc)
        IntVTableBaseSet((unsigned long)&g_pfnVectors[0]);
    #endif
    #if defined(ewarm)
        IntVTableBaseSet((unsigned long)&__vector_table);
    #endif
    #endif
      //
      // Enable Processor
      //
      MAP_IntMasterEnable();
      MAP_IntEnable(FAULT_SYSTICK);
    
      PRCMCC3200MCUInit();
    }
    
    //*****************************************************************************
    //
    //! \brief callback function for gpio interrupt handler
    //!
    //! \param gpio_num is the gpio number which has triggered the interrupt
    //!
    //! \return 0
    //
    //*****************************************************************************
    void gpio_intr_hndlr(int gpio_num)
    {
    }
    
    //*****************************************************************************
    //
    //! \brief callback function for timer interrupt handler
    //!
    //! \param vParam is a general void pointer (not used here)
    //!
    //! \return None
    //
    //*****************************************************************************
    void TimerCallback(void *vParam)
    {
        UART_PRINT("\n\r---tajmerski prekid---");
    }
    
    //*****************************************************************************
    //
    //! \brief set Timer as a wake up source from low power modes.
    //!
    //! \param none
    //!
    //! \return handle for the Timer setup as a wakeup source
    //
    //*****************************************************************************
    cc_hndl SetTimerAsWkUp()
    {
        cc_hndl tTimerHndl;
        struct cc_timer_cfg sRealTimeTimer;
        struct u64_time sInitTime, sIntervalTimer;
        //
        // setting up Timer as a wk up source and other timer configurations
        //
        sInitTime.secs = 0;
        sInitTime.nsec = 0;
        cc_rtc_set(&sInitTime);
    
        sRealTimeTimer.source = HW_REALTIME_CLK;
        sRealTimeTimer.timeout_cb = TimerCallback;
        sRealTimeTimer.cb_param = NULL;
    
        tTimerHndl = cc_timer_create(&sRealTimeTimer);
    
        sIntervalTimer.secs = LPDS_DUR_SEC;
        sIntervalTimer.nsec = LPDS_DUR_NSEC;
        cc_timer_start(tTimerHndl, &sIntervalTimer, OPT_TIMER_PERIODIC);
        return(tTimerHndl);
    }
    
    //****************************************************************************
    //                            MAIN FUNCTION
    //****************************************************************************
    void main(void)
    {
        //
        // Board Initialization
        //
        BoardInit();
        
        //
        // Configure the pinmux settings for the peripherals exercised
        //
        PinMuxConfig();
        
        //
        // Initialize the platform
        //
        platform_init();
    
        //
        // Configuring UART
        //
        g_tUartHndl = uart_open(PRCM_UARTA0);
    
        //
    	// Displays the Application Banner
    	//
    	DisplayBanner();
    	//
    	// setting Timer as one of the wakeup source
    	//
    	SetTimerAsWkUp();
    
        //
        // setting Apps power policy
        //
        lp3p0_setup_power_policy(POWER_POLICY_STANDBY);
    
        while(FOREVER)
    	{
    
    	}//while
    }//main
    

    Timer interrupt never happens.
    CC3200 never goes to LPDS, I know it because
    I do not lose connection between CCS and CC3200 in console.

    I know that I miss something to understand. I do not have knowledge about RTOS.
    So, I have to ask another questions:
    ---in main we calls platform_init(). Deep inside this function execute MAP_PRCMLPDSEnter(), is it executes LPDS when we call platform_init()??? Or just initi it???
    ---If is first no, when it calls again and again go to LPDS???
    ---When I exercised debag of idle_profile example I understood that cc3200 goes to LPDS when go iniside while(FOREVER) of TimerGPIOTask.
    When wakes up it execute switch(ucQueueMsg) and goes again to LPDS, it confuse me???

    Thanks
    Srdjan

  • Hi Srdjan,

    Whenever the application is blocked on the message queue (refering to idle_profile), the idle task would execute and invoke the vApplicationIdleHook function. This inturn would invoke the "cc_idle_task_pm" function that would cause the system to enter the low power mode based on the applications choice.

    Hope this clarifies the operation in the idle_profile example.

    Best regards,

    Naveen

  • Hi,

    now I decides to wake up my board on UDP connection and start to understand idle_profile example at all.

    There is a problem with connection to Wlan station. It is always happen to WDG expired. Wlan station parameters are correct(SSID_NAME, SECURITY_TYPE and SECURITY_KEY).
    I can confirm this, because I was run tcp_socket example and everything works fine.

    When I debag idle_example I was concluded that two handle function never happen. Function sl_WlanEvtHdlr and sl_NetAppEvtHdlr. In sl_WlanEvtHdlr it must write
    queue message EVENT_CONNECTION. In sl_NetAppEvtHdlr it must write queue message EVENT_IP_ACQUIRED. This two gueue message are wait to read in function
    WlanConnection(). After 5 times WDG timer expired, it stops to true to connect.

    Anyone have idea???

    Thanks'

  • Hi Srdjan,

    The idle_profile example by default connects to an open AP. Could you please set the right parameters in the secParams structure that is passed into sl_WlanConnect and retry?

    The WDT timer expires if the connection to the AP is not successful within the specified duration. Hence, do recheck the parameters passed to the WLAN connect API.

    Best regards,

    Naveen

     

  • Naveen Thanks,

    your advice helped me to conclude what is a problem. 

    Problem was a secParams.KeyLen. In sdk that I use this parameter gets value from sizeof(SECURITY_KEY), which is wrong. It's always 4.

    My security key has a 11 characters. I made change and replaced  sizeof with strlen and everything work fine.

    Srdjan

  • Hi Srdjan,

    Thanks for sharing this! I am closing this thread.

    Best regards,

    Naveen

  • Hi,

    now I want to change my wakeup time from LPDS every time when I wake up from LPDS. How can I do it???

    Thanks, Srki

  • Hi Srdjan,

    1. change the wake up timer to absolute timer instead of periodic.

    cc_timer_start(timer_hndl, &interval_time, OPT_TIME_ABS_VALUE);

    2. when the device comes out of LPDS, configure the new wake time(again absolute). The new wake up time will be relative to initial time that you have set using cc_rtc_set APIIf you want to set the new time relative to the current time, make sure to set the initial time to zero( every time before setting the new wake up time).

    the flow will be something like:

    // Chip comes out of low power mode

    ..

    ..

    cc_rtc_set(&init_time);

    cc_timer_start(timer_hndl, &abs_time, OPT_TIME_ABS_VALUE);

    ..

    ..

    // Chip enters into low power mode

     

    if you keep init_time to be zero, in that case abs_time will be the wake time interval.

    Let me know if you need more clarification on this.

    Regards,

    Rahul

    Regards,
    Rahul

  • Hi,

    I tried this but it does not work fine. I change a little function SetTimerAsWkUp() from idle_profile example. Put function a parameter which represent a seconds

    In my while(1) every time when it wakes up from LPDS I forward different seconds to function SetTimerAsWkUp(x seconds). 

    Problem occurs after it 6 time wakes up. It puts new value, go to lpds and never wakes up.

    Thanks, Srki


    cc_hndl SetTimerAsWkUp(int timeDur) { cc_hndl tTimerHndl; struct cc_timer_cfg sRealTimeTimer; struct u64_time sInitTime, sIntervalTimer; // // setting up Timer as a wk up source and other timer configurations // sInitTime.secs = 0; sInitTime.nsec = 0; cc_rtc_set(&sInitTime); sRealTimeTimer.source = HW_REALTIME_CLK; sRealTimeTimer.timeout_cb = TimerCallback; sRealTimeTimer.cb_param = NULL; tTimerHndl = cc_timer_create(&sRealTimeTimer); sIntervalTimer.secs = timeDur;//LPDS_DUR_SEC; sIntervalTimer.nsec = LPDS_DUR_NSEC; cc_timer_start(tTimerHndl, &sIntervalTimer, OPT_TIME_ABS_VALUE); return(tTimerHndl); }

    
    

  • Hi Srdjan,

    Try removing the highlighted lines from the code.
    Ideally, the timer should not be created every time, only the reconfiguration is required

    cc_hndl SetTimerAsWkUp(int timeDur)
    {
        cc_hndl tTimerHndl;
        struct cc_timer_cfg sRealTimeTimer;
        struct u64_time sInitTime, sIntervalTimer;
        //
        // setting up Timer as a wk up source and other timer configurations
        //
        sInitTime.secs = 0;
        sInitTime.nsec = 0;
        cc_rtc_set(&sInitTime);
        sRealTimeTimer.source = HW_REALTIME_CLK;
        sRealTimeTimer.timeout_cb = TimerCallback;
        sRealTimeTimer.cb_param = NULL;
        tTimerHndl = cc_timer_create(&sRealTimeTimer);
        sIntervalTimer.secs = timeDur;//LPDS_DUR_SEC;
        sIntervalTimer.nsec = LPDS_DUR_NSEC;
        cc_timer_start(tTimerHndl, &sIntervalTimer, OPT_TIME_ABS_VALUE);
        
        return(tTimerHndl);
    }



    Let me know if this resolves your issue.

    Regards,
    Rahul

     

  • Hi Naveen,

    I was finding an anwser for a similar question with Hardik's and found this thread. Thanks for the useful info you have provided.

    From your earlier response, I understand that while in LPDS, I can always setup an interrupt to wake up the MCU upon receiving some packet over the air. Is this correct or the interrupt to wake up the MCU is already handled in the framework for LPDS mode?

    Also, is this LPDS that you mentioned the "NWP LPDS" mode in the datasheet? The datasheet says while in NPW LPDS, the current consumption is only 0.12mA. For the wake-up interrupt to work, is it only 0.12mA needed here for both MCU and RX? I hope it is but it sounds too good to be true to me, so I just want to confirm.

    Thanks very much for your help.

  • Hi Tung Dao,

    The interrupt on the wakeup is handled by the simplelink driver and the setting up of the wake source on Host IRQ is done by the PM framework. Hence the application neednt perform any specific operation. For ex., application only invokes sl_recv and sl_recv returns with the data received (the system could enter LPDS in the interim and wake up on data received). 

    The mode of operation that is of interest  to you seems to be (MCU LPDS+NWP Idle Connected) which has a current consumption of 0.695mA as mentioned in the datasheet.

    (MCU LPDS + NWP LPDS) row in the datasheet corresponds to the condition where APPs MCU enters LPDS and the networking engine is not started (NWP LPDS is the default).

    Best regards,

    Naveen

  • Hi Naveen,

    While in LPDS+NWP Iddle Connected, which communication mode would work for the interrupt? (i.e. Station, AP or WiFi Direct or all of them). Also, for the modes that work, does the requester need to be already connected to the CC3200 earlier or can it be any random WiFi device?

    Thanks for your help.

    TD.