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.

CCS/CC3200-LAUNCHXL: How to enter in LPDS mode

Part Number: CC3200-LAUNCHXL
Other Parts Discussed in Thread: CC3200, UNIFLASH

Tool/software: Code Composer Studio

Hi,

I'm trying to activate LPDS mode but I don't get it. I'm measuring the current and I see 17mA and the launchpad don't enter in LPDS mode.
I have seen the example idle_profile but I don't get it. Can you tell me if something is missing?

I've made a simple example that it has a timer of 10secs that toggle a LED. The code is this:

In the Main.c file:

//*****************************************************************************
//                            MAIN FUNCTION
//*****************************************************************************
void main()
{
    long lRetVal = -1;
    unsigned char QueueMsg = 0;

    QueueMsg = 0;

    // Board Initialization
    BoardInit();
    
    // configure the GPIO pins for LEDs,UART
    PinMuxConfig();

    // Initialize the platform
    pm_framework_init();

    // configure LEDs
    GPIO_IF_LedConfigure(LED1|LED2|LED3); //Orange, Red
    GPIO_IF_LedOff(MCU_ALL_LED_IND);
    

    // Configure the UART
    g_tUartHndl = uart_open(PRCM_UARTA0);

    //// Display Application Banner
    DisplayBanner(APPLICATION_NAME);

    // Start the SimpleLink Host
    lRetVal = VStartSimpleLinkSpawnTask(SPAWN_TASK_PRIORITY);
    if(lRetVal < 0)
    {
        ERR_PRINT(lRetVal);
        LOOP_FOREVER();
    }

    // sync object for inter thread communication
    lRetVal = osi_MsgQCreate(&qMain, "Main_Queue", sizeof( unsigned char ),3);
    if(lRetVal < 0)
    {
        Report("could not create Main queue\n\r");
        LOOP_FOREVER();
    }


    // sync object for inter thread communication
    lRetVal = osi_MsgQCreate(&qWifi, "WIFI_Queue", sizeof( unsigned char ),6);
    if(lRetVal < 0)
    {
        Report("could not create queue Wifi\n\r");
        LOOP_FOREVER();
    }

    // Start the TimerTask task
    lRetVal = osi_TaskCreate(MainTask, (const signed char *)"Tarea Principal",
                             OSI_STACK_SIZE,NULL,2,NULL );

    if(lRetVal < 0)
    {
        ERR_PRINT(lRetVal);
        LOOP_FOREVER();
    }

    // Start the WlanStationMode task
    lRetVal = osi_TaskCreate(WLAN_Connections_Task, (const signed char*)"Wlan Station Task", \
                                OSI_STACK_SIZE, NULL, 2, NULL );
    if(lRetVal < 0)
    {
        ERR_PRINT(lRetVal);
        LOOP_FOREVER();
    }

    // Start the task scheduler
    osi_start();

    LOOP_FOREVER();

  }

//*****************************************************************************
void TimerCallback(void *vParam)
{
    unsigned char ucQueueMsg = 1;

    osi_MsgQWrite(&qMain, &ucQueueMsg, OSI_NO_WAIT);

    return;
}

void MainTask(void *pvParameters)
{
    unsigned char QueueMsg = 0;
    

    Report("sTART MAIN Task\n\r");

    QueueMsg = MSG_CONNECT_WIFI;
    osi_MsgQWrite(&qWifi, &QueueMsg, OSI_NO_WAIT);


    tTimerHndl = SetTimerAsWkUp();

    lp3p0_setup_power_policy(POWER_POLICY_STANDBY);
    cc_idle_task_pm();

    while(1) {
        // waits for the message from the TimerRTC
        osi_MsgQRead(&qMain, &QueueMsg, OSI_WAIT_FOREVER);
        switch(QueueMsg){
            case MSG_TIMER:
        GPIO_IF_LedToggle(MCU_RED_LED_GPIO);
        break;

        }
    }

    LOOP_FOREVER();

}

//*****************************************************************************
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; //10 SECS
    sIntervalTimer.nsec = LPDS_DUR_NSEC;
    cc_timer_start(tTimerHndl, &sIntervalTimer, OPT_TIMER_PERIODIC);
    return(tTimerHndl);
}

and the Wifi.c file:

void WLAN_Connections_Task(void *pvParameters)
{
    int iSocketDesc, iRetVal;
    long lRetVal = -1;
    unsigned char QueueMsg = 0;
    unsigned char i;

    Report("Inicio Wlan Connection Task\n\r");
    
    while(1)   {
        // waits for the message from the TimerRTC
        osi_MsgQRead(&qWifi, &QueueMsg, OSI_WAIT_FOREVER);
        switch(QueueMsg){

        case MSG_CONNECT_WIFI:
            Report("Iniciando Conexión WIFI.\n\r");
            iRetVal = WLAN_Connection();
            if (iRetVal < 0) {
                // Close the socket
                close(iSocketDesc);
                UART_PRINT("Socket closed\n\r");
                // Stop the driver
                lRetVal = Network_IF_DeInitDriver();
                if(lRetVal < 0)
                {
                   UART_PRINT("Failed to stop SimpleLink Device\n\r");
                 }
            }
            break;
        
    }

    //
    // Loop here
    //
    LOOP_FOREVER();
}

int WLAN_Connection() {

    long lRetVal;
    unsigned char policyVal;
    unsigned char QueueMsg = 0;

    // Reset The state of the machine
    Network_IF_ResetMCUStateMachine();


    // starting the simplelink
        //
    lRetVal = sl_Start(NULL, NULL, NULL);
        if (lRetVal < 0)
        {
            UART_PRINT("Failed to start the device \n\r");
            LOOP_FOREVER();
        }

        //
        // Swtich to STA mode if device is not
        //
        SwitchToStaMode(lRetVal);

        //
        // Set the power management policy of NWP
        //
        lRetVal = sl_WlanPolicySet(SL_POLICY_PM, SL_NORMAL_POLICY, NULL, 0);
        if (lRetVal < 0)
        {
            UART_PRINT("unable to configure network power policy\n\r");
            LOOP_FOREVER();
        }
        // Initialize AP security params
            SecurityParams.Key = (signed char *)passWifi;
            SecurityParams.KeyLen = strlen(passWifi);
            SecurityParams.Type = SECURITY_TYPE;

    sl_WlanConnect((signed char *)SSID_NAME,strlen((const char *)SSID_NAME), 0, &SecurityParams, 0);


    // Switch ON RED LED to indicate that Device acquired an IP
    GPIO_IF_LedOn(MCU_ORANGE_LED_GPIO);

    return 1;
}

in the file lp3p0_board.c:
//****************************************************************************
int pm_framework_init(void) {
    int retval = 0;
    struct platform_pm_ops lp3p0_pm_ops;
    struct cc_timer_setup timer_setup;
    struct cc_dma_cfg dma_config;
    tROMVersion* pRomVersion = (tROMVersion *)(ROM_VERSION_ADDR);
    u32 *spi_baud_rate;


    /* Initialize the PM framework */
    retval = cc_pm_framework_init();

    /* Get the SOC specific platform operations */
    lp3p0_get_pm_ops(&lp3p0_pm_ops);

    /* Register PM ops with framework */
    if(cc_pm_platform_ops_register(&lp3p0_pm_ops)){
        Report("Error: PM framework init failed");
        while(1);
    }
    /* Register the power management ISR */
            register_isr(INT_PRCM, prcm_interrupt_handler, NULL);

    /* Register the timer ISR */
    register_isr(INT_TIMERA2A, timer_interrupt_handler, NULL);

    // Initialize the platform specific services
    timer_setup.enbl_irqc = osi_ExitCritical;
    timer_setup.dsbl_irqc = osi_EnterCritical;
    retval = cc_timer_module_init(&timer_setup);
    // Initialize RTC services
    retval = rtc_module_init();

    /* Initialize timer services */
    MAP_PRCMPeripheralClkEnable(PRCM_TIMERA2, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
    
    /* Initialize GPIO services */
    retval = gpio_module_init(&gpio_list[0], (sizeof(gpio_list)/sizeof(int)));


    // Initialize the DMA module
            MAP_PRCMPeripheralClkEnable(PRCM_UDMA, PRCM_RUN_MODE_CLK|
                                        PRCM_SLP_MODE_CLK);
            dma_config.ctl_table = dma_ctrl_table;
            retval = cc_dma_init(&dma_config);

            spi_baud_rate = &(((struct cc_spi_config*)(modules[0].hw_detail))->baud_rate);
            //* deciding the SPI baud rate depending upon PG version
            if(pRomVersion->ucMinorVerNum == ROM_VER_PG1_21 )
            {
                *spi_baud_rate = SPI_RATE_13M;
            }
            else if(pRomVersion->ucMinorVerNum == ROM_VER_PG1_32)
            {
                *spi_baud_rate = SPI_RATE_13M;
            }
            else if(pRomVersion->ucMinorVerNum >= ROM_VER_PG1_33)
            {
                *spi_baud_rate = SPI_RATE_20M;
            }

            // Load the application specific modules
    #if 1
    #define NUM_SOC_MODULES(modules) (sizeof(modules) / sizeof(struct soc_module))

            if(-1 == cc_modules_load(modules, NUM_SOC_MODULES(modules))) {
                    //* Should modules be unloaded?
                    retval = -1;
            }
    #endif


    return retval;
}

//****************************************************************************
void prcm_interrupt_handler(void *intr_param)
{
        int status;

        /* Read the interrupt status, also clears the status */
        status = MAP_PRCMIntStatus();

        if((PRCM_INT_SLOW_CLK_CTR == status) || (sw_simulate_rtc)) {
                sw_simulate_rtc = 0;
                /* Invoke the RTC interrupt handler */
                cc_rtc_isr();
        } else if(0 == status) {
                /* Invoke the wake from LPDS interrupt handler */
                wake_interrupt_handler();
        } else {
        }
}

void timer_interrupt_handler(void *intr_param)
{
    sw_simulate_timer = 0;
    cc_hwt32_isr(timer_hndl);
}

THANKS.

  • Hi,

    Have you tried the power_measurement CC3200 SDK demo? It is a simple demo that allows you to set the device into a variety of use cases which covers the different power settings including LPDS.

    I suggest that you run that demo when measuring the LPDS current of the CC3200. Let me know if you need more clarification or have further questions.

    Regards,

    Michael

  • Hi Michael,

    I've seen the power_measurement demo, and I 've applied some corrections in my code. Now, my code enter in LPDS mode after 20secs controlled by TIMERA2 (configured at 1sec). The TIMERA2 has been configured just like that:

    PRCMPeripheralClkEnable(PRCM_TIMERA2, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);

    When It counts 20 times, send a message to the Main Task:

    QueueMsg = MSG_ENTER_LPDS;
    osi_MsgQWrite(&qMain, &QueueMsg, OSI_NO_WAIT);

    and then, in the Main Task:

    set_rtc_as_wk_src(WK_LPDS, 10, false);
    lp3p0_setup_power_policy(POWER_POLICY_STANDBY);
    cc_idle_task_pm();

    In the LPDS mode, I would like that it wake up every 10secs and read temperature of DHT22 sensor or toggle led and return to LPDS. How can I do it?

    Other question, when it wake up from rtc (after 10 secs) and execute  wake_interrupt_handler() function, the TIMERA2 does not continue to work, it's stopped. How can I reactivate the TIMERA2?

    Thanks.

  • I've been testing my code and modify it follow the power_measurement demo. I've configured the TIMERA0 for triger 1 sec, and RTC and GPIO 13 for wake up. The configuration is:

    //TIMERA2 PARA CORE
            PRCMPeripheralClkEnable(PRCM_TIMERA0, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
            PRCMPeripheralReset(PRCM_TIMERA0);
            TimerConfigure(TIMERA0_BASE, TIMER_CFG_A_PERIODIC );
            // register and enable the PRCM interrupt
            osi_InterruptRegister(INT_TIMERA0A, (P_OSI_INTR_ENTRY)TimerA2IntHandler, INT_PRIORITY_LVL_1);
            TimerControlEvent(TIMERA0_BASE,TIMER_A,TIMER_EVENT_POS_EDGE);
            sysTimer = ACTIVE_TIMER;
            TimerLoadSet(TIMERA0_BASE,TIMER_A, MILLISECONDS_TO_TICKS(sysTimer*1000));
            TimerIntEnable(TIMERA0_BASE,TIMER_TIMA_TIMEOUT);
            TimerEnable(TIMERA2_BASE,TIMER_A);
    
    
    void InitPRCM() {
    
        unsigned long secs, msecs;
    
        PRCMRTCInUseSet();
        // register and enable the PRCM interrupt
        osi_InterruptRegister(INT_PRCM, (P_OSI_INTR_ENTRY)PRCMIntHandler, INT_PRIORITY_LVL_1);
        PRCMRTCSet(0, 0);
        secs = secs + sysTimer;
        PRCMRTCMatchSet(secs, msecs);
        PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
     
    }
    
    void InitGPIO()
    {
    
        //Configure IRQ 
        GPIOIntTypeSet(GPIOA1_BASE,GPIO_PIN_5,GPIO_LOW_LEVEL);
        osi_InterruptRegister(INT_GPIOA1, (P_OSI_INTR_ENTRY)A1BaseInterruptHandler, INT_PRIORITY_LVL_1);
    
        GPIOIntClear(GPIOA1_BASE,GPIO_PIN_5);
        IntPendClear(INT_GPIOA1);
        IntEnable(INT_GPIOA1);
        GPIOIntEnable(GPIOA1_BASE,GPIO_INT_PIN_5);
     
    }
    
    

    For wake up, I've configured the following:

    set_gpio_as_wk_src(WK_LPDS, PRCM_LPDS_GPIO13, PRCM_LPDS_LOW_LEVEL);
    PRCMSRAMRetentionEnable( PRCM_SRAM_COL_1 | PRCM_SRAM_COL_2 | PRCM_SRAM_COL_3 | PRCM_SRAM_COL_4 ,PRCM_SRAM_LPDS_RET );
    
    set_rtc_as_wk_src(WK_LPDS, 10, true);
    lp3p0_setup_power_policy(POWER_POLICY_STANDBY);
    cc_idle_task_pm();
    void PRCMIntHandler(void)
    {
        int status;
    
        unsigned long secs, msecs;
        unsigned char updateTime = 0, updateNTP = 0;
        unsigned char QueueMsg;
        
        // Read the interrupt status, also clears the status
        status = PRCMIntStatus(); // clear
            
        GPIO_IF_LedToggle(MCU_GREEN_LED_GPIO);
    
        if((PRCM_INT_SLOW_CLK_CTR == status)) {
           
        } else if(0 == status) {
                // Invoke the wake from LPDS interrupt handler
                GPIO_IF_LedToggle(MCU_RED_LED_GPIO);
                QueueMsg = MSG_ENTER_LPDS;
                osi_MsgQWrite(&qMain, &QueueMsg, OSI_NO_WAIT);
    
                wake_interrupt_handler();
    
        } else {
        }
    
        QueueMsg = MSG_GET_TIME;
        osi_MsgQWrite(&qMain, &QueueMsg, OSI_NO_WAIT);
    }

    This code, when TIMERA0 counts 20 times (20secs), enter in LPDS mode and then wake up the RTC every 10 secs and go back to LPDS. In LPDS, if I activate the GPIO 13, the system don`t wake-up, but if I configure this:

    /* Initialize GPIO services */
    retval = gpio_module_init(&gpio_list[0],(sizeof(gpio_list)/sizeof(int)));
    tGPIOHndl = SetGPIOAsWkUp();

    and your interrupt function:

    int gpio_intr_hndlr(int gpio_num)
    {
        unsigned char QueueMsg = 4;
    
        if(GPIO_SRC_WKUP == gpio_num)
        {
            intgpiosw=1;
            osi_MsgQWrite(&qMain, &QueueMsg, OSI_NO_WAIT);
        }
        return 0;
    }

    then, the system does wake up when the GPIO 13 is activated.

    I don't understand why do I have inicialize the gpio module with gpio_module_init if the GPIO is already defined with InitGPIO function?

    Other doubt, when the system wake up for the LPDS, why does the A0 timer do nothing?, Do I have to reconfigure it every time I leave the LPDS mode?

  • Hi Federico,

    Your InitGPIO() only configures the GPIO interrupt which applies when the device is already awake. Wake from LPDS must be configured differently with the power manager - this is what cc_gpio_enable_notification() inside of SetGPIOAsWkUp() does.

    The peripherals must be restored every time the device wakes from LPDS. The power management framework can do this for you if configured correctly. In in the idle_profile example, this is done in by platform_init() using the structs in user_app_config.h.

    The idle_profile example by default configures gpio_intr_hndlr() as the handler to execute when the device wakes from GPIO. You can change this in gpio_module_init() in lp3p0_board.c, or set it to null.

    Please take a closer look at lp3p0_plat_ops.c and lp3p0_board.c. These files contain the application-specific implementations for some of the handlers, initialization functions, and restore sequence. These functions then are used by the PM framework library (cc3200-sdk/middleware/framework/pm/cc_pm.c) to automatically handle moving between power modes.

    Best regards,

    Sarah

  • Hi Sarah,

    thanks for your response.

    I have restored the timers every time the devide when wake from LPDS and run it.

    I have seen the idle_profile but I can't understand it at all becase the device loses the debug sesion. Can I do something for doesnt lose it?

    Thanks.

  • Hi Federico,

    Losing the debug interface when entering a low power mode is expected because the host shuts down many system blocks to save power. What are you trying to understand? Why is debug session preventing you from understanding?

    Jesu

  • Hi Jesu,

    In the idle_profile example, pin gpio 13 triggers the interrupt and the gpio_intr_hndlr () function is executed when it is in LPDS, if we set another interrupt in gpio 13 with the osi_InterruptRegister () function, which one will be executed first? And where would it be more convenient to leave the LPDS?

    Is there any way to debug on LPDS?

    Federico.

  • Hi Federico,

    If GPIO 13 triggers the wake from LPDS, it should not also trigger the osi interrupt.

    In LPDS, you will retain your state before you go to sleep. You should return to your application in the same place that you went to sleep.

    Best regards,

    Sarah

  • Hi,

    I've finally got the LPDS to work. Now my device works properly and enters LPDS and after 10 seconds it wakes up and does the pending tasks.

    The problem is that when recording the bin with the uniflash, then the device does not work, it does nothing. It's strange because the same code loaded from the CSS does work. Do you have to configure something in uniflash for LPDS?

  • resolved. I don't know why but the fault was when initializing UART0 with the command
    g_tUartHndl = uart_open (PRCM_UARTA0);

    I have configured UART0 with the UARTConfigSetExpClk function and it already works.
    Thanks for the support.