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.

cc1310 failing to enter standby because of a constraint

Other Parts Discussed in Thread: CC1310, SYSBIOS

Hi!

I'm using ti-rtos 2.20.0.06 on a cc1310 for an ultra low power application. The cc1310 is consuming about 450uA while all tasks are sleeping, which is much higher than the number published in the cc1310 data-sheet for standby mode. I double checked all the GPIO configuration and  verified using oscilloscope and a logic analyzer that there is no leakage into or from the pins. I'm using the following power config.:

const PowerCC26XX_Config PowerCC26XX_config = {
	.enablePolicy = true,
	.policyInitFxn = NULL,
	.policyFxn = &PowerCC26XX_standbyPolicy,
	.calibrateFxn = &PowerCC26XX_calibrate,PowerCC26XX_SB_DISALLOW
	.calibrateRCOSC_LF = true,
	.calibrateRCOSC_HF = true
};

In ccfg.c I have the  following line setting the LF OSC SRC to LF XOSC

#define SET_CCFG_MODE_CONF_SCLK_LF_OPTION            0x2   

I call Power_getConstraintMask() right before Task_sleep and the function always returns 4, which is (1<<PowerCC26XX_SB_DISALLOW). Am I getting this right: as long as Power_getConstraintMask() returns a non-zero value, the cc1310 is not allowed to go in standby mode? I even tried  Power_releaseConstraint(PowerCC26XX_SB_DISALLOW) before calling Task_sleep() which didn't change anything.

In this code in POWER26XX.c:Power_init()  (lines 318-326) the if-condition is always true in my case:

 /*                                                                                                                               
     * if LF source is RCOSC_LF or XOSC_LF: assert the SB_DISALLOW constraint                                                        
     * and start a timeout to check for activation                                                                                   
     */                                                                                                                              
    if ((ccfgLfClkSrc == CCFGREAD_SCLK_LF_OPTION_RCOSC_LF) ||                                                                        
        (ccfgLfClkSrc == CCFGREAD_SCLK_LF_OPTION_XOSC_LF)) {                                                                         
                                                                                                                                     
        /* disallow STANDBY pending LF clock quailifier disabling */                                                                 
        Power_setConstraint(PowerCC26XX_SB_DISALLOW);                      

I don't quite understand why is the SB_DISALLOW constraint is set here, even thought the LF OSC isn't derived from the HF OSC as required to enter standby mode.

I'd appreciate any help!

Best regards

Eqbal

  • Hi Eqbal!

    I'm going to move this to our Sub 1GHz forum so the CC1310 experts can help address your question.

    Best Regards,
    Ben
  • Have you tried to run the pinStandby example in TI-RTOS unmodified to verify that you manage to measure the correct current using this example? Note that the JTag interface has to be disconnected when measuring Standby current.
  • Hello TER and thank you for you response.


    I'm not using a TI launch pad. I'm using a board with a lot of peripherals and other chips, that are controlled by the cc1310. The main task running on the cc1310 puts all the other chips on the board in sleep mode, which I verified. When I modify and adapt the pinStandby example to configure the GPIOs to match the configuration of the other chips, I need to call PIN_init() which calls Power_init where a power constraint is set, as I mentioned before.


    Can you help me with the other question: is the cc1310 is not allowed to go in standby mode as long as Power_getConstraintMask() returns a non-zero value? And if yes, why won't a Power_releaseConstraints() help?

    Kind regards

    Eqbal

  • Hi Eqbal.
    The CC1310 running TI-RTOS has a power management system which puts the device into standby automatically between activities. There is no need to make any calls to the power subsystem as this will be handled by the RTOS itself.
  • Hello Fred and thank you!
    I'm not calling the Power API functions to manually put the device into standby. I'm trying to figure out why it's not working and I'm suspecting that a driver sets a power constraint and doesn't release it. I still don't know which one yet. I had a lot of debug sessions. If I didn't miss something then the only driver setting the PowerCC26XX_SB_DISALLOW is the GPIO driver: GPIO_init -> Power_init ->Power_setConstraint and there is not matching Power_releaseConstraint before Task_sleep is called.


    Kind regards,
    Eqbal
  • Do you have a board with only CC1310 populated? Since the pinStandby example works without issues on our hardware I find it strange that if used with a different pin configuration that it's not going to standby. It could sound like some other part of your board is active/ in a state that prevent the CC1310 to go down in standby.
  • Ok understood.
    Let me check this out and come back to you.
  • I think we must have one here.... somewhere... I must ask my colleagues :-)
    The other parts on the the board are put into sleep or some other low power mode by the cc1310. It's easy to verify that there other parts are sleeping, because they output signals that can be tested for activity (for example one chip outputs a ref clock when not sleeping, another chip enables/disables an external voltage regulator depending on sleep/active mode etc..). All the output/input pins on all the chips connected to cc1310 are correctly configured, so that no pullup/pulldown pin on one side is connected to a pulldown/pullup pin on the other.
  • I even tried the following evil:

    pwrConst = Power_getConstraintMask(); /* pwrConst == 4 */
    Power_releaseConstraint(PowerCC26XX_SB_DISALLOW);   /* pwrConst == 4!! this function call doesn't change anything */
    PowerCC26XX_module.constraintMask = 0;  /* this should be set by Power_releaseConstraint(), which fails*/
    
    Task_sleep((uint32_t)period); /*PowerCC26XX_module.constraintMask == 0 and it stays 0 while sleeping*/
    
    
    

    Still no reduction in current consumption.

  • Hi Eqbal,

    First of all, thank you for the detailed explanations. That makes things much easier to debug,

    I am suspecting that your LF XTAL has not started properly up due to the following reasons:

    • The power driver will put a constraint on standby until it the system is running on the selected LF clock
    • If the system tries to go down to into standby without having switched to the LF XTAL, the LF clock will still be sourced from the 48MHz RCOSC / 1536 which is the power-on setting.

    You can check this by either:

    Regards,

    Svend

  • Hello Svend and thanks for the help, hello all!

    Calling OSCClockSourceGet(OSC_SRC_CLK_LF) just before Task_sleep() always returns OSC_XOSC_LF . I probed the crystal and I saw a pretty sine wave at 32,768kHz.

    Can a standby power policy be enabled partly, such that some domains are clock and power gated, while some domains stay in a higher power mode like idle? For when I disable the policy in PowerCC26XX_config with .enablePolicy = false, the current consumption is 6 times higher.

    Kind regards,
    Eqbal
  • Hi Eqbal,

    In your code below - is the PowerCC26XX_SB_DISALLOW a typo?
    This is not a part of the default power configuration, not sure what this syntax would do in C :)

    const PowerCC26XX_Config PowerCC26XX_config = {
    	.enablePolicy = true,
    	.policyInitFxn = NULL,
    	.policyFxn = &PowerCC26XX_standbyPolicy,
    	.calibrateFxn = &PowerCC26XX_calibrate,PowerCC26XX_SB_DISALLOW
    	.calibrateRCOSC_LF = true,
    	.calibrateRCOSC_HF = true
    };


    A very basic test to check functionality would be to have only a single task containing the following snippet:
    Task_sleep(BIOS_WAIT_FOREVER)

    This would put the device directly into standby when executing the task and nothing else that can interfere with operation.

    Regards,
    Svend

  • Hi,
    yes that was a typo :-)
    I'll try the single task and get back to you.

    Kind regards,
    Eqbal
  • Hi Svend!
    I tried what you suggested. I have now one task with some initialization code, which is needed to put all other chips in sleep mode. After this initialization the task calls Task_sleep(BIOS_WAIT_FOREVER). The current consumption is the same.

    I have another related note: even thought the SPI driver sets a power constrains AND releases it, after the SPI communication is done, calling SPI_close() before Task_sleep() reduces the current by 100uA!!

    Kind regards,
    Eqbal
  • I forgot to mention, that the SPI handles need to be called again after Task_sleep() returns.
  • Yes, closing the SPI will disable the SPI module and its clock, also it will turn of the PERIPH power domain if not peripherals in the domain are not used any more. The CC1310 data sheet section 5.4 contains current draw numbers for various modules.

    In standby, all these modules are turned off, and drivers will restore the peripherals which are not retained while in standby once waking up again.

    Other ideas:
    - Have you checked that you have no floating input pins leaking current?
    - Are you sure the current draw is coming from the CC1310 and no other sensors? Any external circuits powered through GPIOs?

    Regards,
    Svend
  • Did you manage to find the board with only CC1310 on?
  • Hi!

    I had the same problem (Power_getConstraintMask() always gives 4) and found a bug (or at least a weird behaviour) which may help you out.

    Power_getConstraintMask gives 4 (even if it should give 0 because of none activated driver-modules) until the first call to Task_sleep(1000); (or any other Task_sleep with sufficient tickcount (that is enough for the power-manager to even try to goto standby)).

    Regards,

    Peter

  • I still have another problem.

    It seems that the use of LM4-Timers also prevents the Power-Manager from entering StandBy.

    I verified with a small example-application (wakeup by Port or Timer). If i use the GPTimerCC26XX it works fine (Power_getConstraintMask() gives 0 after Timer-Stop), but if i use the LM4-Timer (var Timer = xdc.useModule('ti.sysbios.family.arm.lm4.Timer'); in *.cfg) the constraint is still there after Timer-Stop...

    Here are the relevant parts of my code:

    // Timer
    //#define USE_LM_TIMER
    #define USE_GP_TIMER
    //#define USE_CLOCK_TIMER
    
    #ifdef USE_LM_TIMER
    	Timer_Struct t1sTimer;
    #elif defined(USE_GP_TIMER)
    	GPTimerCC26XX_Handle hTimer;
    #elif defined(USE_CLOCK_TIMER)
    	Clock_Struct clk0Struct;
    #else
    	#error select Timer
    #endif
    
    
    ...
    
    
    // Timer-Function 1s
    #ifdef USE_LM_TIMER
    	void timerFn1s(UArg arg)		// use LM4-Timer
    #elif defined(USE_GP_TIMER)
    	void timerCallback(GPTimerCC26XX_Handle handle, GPTimerCC26XX_IntMask interruptMask)	// use GPTimerCC26XX
    #elif defined(USE_CLOCK_TIMER)
    	static void clk0Fxn(UArg arg)	// use Clock
    #endif
    {
    	PIN_setOutputValue(ledPinHandle, ID_R_LED, !PIN_getOutputValue(ID_R_LED));		// toggle red LED
    }
    
    
    /*
     *  ======== taskFxn ========
     *  Toggle the Board_LED0. The Task_sleep is determined by arg0 which
     *  is configured for the heartBeat Task instance.
     */
    Void taskFxn(UArg arg0, UArg arg1)
    {
    	unsigned int mask;
    	
    	Task_sleep(1000);	//is mandatory for Power_getConstraintMask() giving correct values		
    	
    	while (1) {
    		mask = Power_getConstraintMask();	// gives 4 as long as Timer is running
    
    		// this should remove the Power_SB_Disallow-Constraint
    #ifdef USE_LM_TIMER
    		Timer_stop(Timer_handle(&t1sTimer));
    #elif defined(USE_GP_TIMER)
    		GPTimerCC26XX_stop(hTimer);
    #endif
    		
    		mask = Power_getConstraintMask();	// should give 0	
    		
    		Semaphore_pend(Semaphore_handle(&wakeupSem), BIOS_WAIT_FOREVER);
    	}
    }
    
    /*
     *  ======== main ========
     */
    int main(void)
    {
    
    ...
    	// Timer-Init for 1s Interval
    #ifdef USE_LM_TIMER
    	Error_Block eb;
    	Error_init(&eb);
    	
    	Timer_Params timerParams;
    	Timer_Params_init(&timerParams);
    	timerParams.runMode = Timer_RunMode_CONTINUOUS; //periodic timer
    	timerParams.period = 48000000;	// 1s Period	// 48MHz Timer
    	timerParams.periodType = Timer_PeriodType_COUNTS;
        Timer_construct(&t1sTimer, Timer_ANY, timerFn1s, &timerParams, &eb);
    #elif defined(USE_GP_TIMER)
    	GPTimerCC26XX_Params params;
    	GPTimerCC26XX_Params_init(&params);
    	params.width          = GPT_CONFIG_32BIT;	//GPT_CONFIG_16BIT;
    	params.mode           = GPT_MODE_PERIODIC_UP;
    	params.debugStallMode = GPTimerCC26XX_DEBUG_STALL_OFF;
    	hTimer = GPTimerCC26XX_open(CC1310DK_7XD_GPTIMER0A, &params);
    	if(hTimer == NULL) {
    		System_abort("Failed to open GPTimer");
    	}
    
    	Types_FreqHz  freq;
    	BIOS_getCpuFreq(&freq);
    //	GPTimerCC26XX_Value loadVal = freq.lo / 1000 - 1; //47999	// 1ms
    	GPTimerCC26XX_Value loadVal = freq.lo - 1; //47999999	// 1s
    	GPTimerCC26XX_setLoadValue(hTimer, loadVal);
    	GPTimerCC26XX_registerInterrupt(hTimer, timerCallback, GPT_INT_TIMEOUT);
    	GPTimerCC26XX_start(hTimer);
    #elif defined(USE_CLOCK_TIMER)
    //	clockParams.arg = (UArg)0;
    	clockParams.period = 1000000/Clock_tickPeriod;	// 1s (1Mio us)
    	/* Construct a periodic Clock Instance */
    	Clock_construct(&clk0Struct, (Clock_FuncPtr)clk0Fxn, 0, &clockParams);
    	Clock_setTimeout(Clock_handle(&clk0Struct), (1000000 / Clock_tickPeriod));
    	Clock_start(Clock_handle(&clk0Struct));
    #endif
    		
    	/* Configure wakeup semaphore. */
    	Semaphore_Params semParams;
    	Semaphore_Params_init(&semParams);
    	semParams.mode = Semaphore_Mode_BINARY;
    	Semaphore_construct(&wakeupSem, 0, &semParams);
    	
    	/* Open LED pins */
    	ledPinHandle = PIN_open(&ledPinState, ledPinTable);
    	if(!ledPinHandle) {
    		System_abort("Error initializing board LED pins\n");
    	}
    
    
    	/* Start BIOS */
    	BIOS_start();
    
    	return (0);
    }
    

    Regards,

    Peter