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: CC1310 Issue with power consumption, with code which has only one Task and an Interrupt callback function.

Part Number: CC1310
Other Parts Discussed in Thread: ENERGYTRACE

Hi Everyone,

I am doing a project using CC1310 in which CC1310 sends RF Packet which contains the data of  On-duration, count, battery voltage and a device ID. The on-duration is obtained from a HWI which is called when switch is turned on, once it is off it goes back to the task. So in my code I have one Task- Sending RF Packets and an Interrupt Button callback function - to calculate on duration.  I have added the codes for task and button callback function below.

Task Function

/* TX task function. Executed in Task context by TI-RTOS when the scheduler starts. */
static void txTaskFunction(UArg arg0, UArg arg1)
{
    /* Enabling the battery monitoring function to check the battery voltage*/
    AONBatMonEnable();
    /* Setup callback for button pins */
    PIN_Status status = PIN_registerIntCb(buttonPinHandle, &buttonCallbackFunction);
    Assert_isTrue((status == PIN_SUCCESS), NULL);

    /* Initialize the radio */
    RF_Params rfParams;
    RF_Params_init(&rfParams);

    /* Customize the CMD_PROP_TX command for this application */
        RF_cmdPropTx.pktLen = PAYLOAD_LENGTH;
        RF_cmdPropTx.pPkt = packet;
        RF_cmdNop.startTrigger.triggerType = TRIG_NOW;
        RF_cmdNop.startTrigger.pastTrig = 1;

        /* Set up the next pointers for the command chain */
        RF_cmdNop.pNextOp = (rfc_radioOp_t*)&RF_cmdPropCs;
        RF_cmdPropCs.pNextOp = (rfc_radioOp_t*)&RF_cmdCountBranch;
        RF_cmdCountBranch.pNextOp = (rfc_radioOp_t*)&RF_cmdPropTx;
        RF_cmdCountBranch.pNextOpIfOk = (rfc_radioOp_t*)&RF_cmdPropCs;

        /* Customize the API commands with application specific defines */
        RF_cmdPropCs.rssiThr = RSSI_THRESHOLD_DBM;
        RF_cmdPropCs.csEndTime = (IDLE_TIME_US + 150) * 4; /* Add some margin */
        RF_cmdCountBranch.counter = CS_RETRIES_WHEN_BUSY;

    /* Request access to the radio */
    rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup, &rfParams);

    /* Set the frequency */
    RF_runCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL, 0);
    /* Get current time */
       times = RF_getCurrentTime();

    RF_yield(rfHandle);
    /* Enter main TX loop */

    /* Getting LSB of MAC Address for Device ID */
    uint64_t macAddrLsb = HWREG(FCFG1_BASE + FCFG1_O_MAC_15_4_0);

    /*For Full MacAddress use following code
     *
    uint64_t macAddrMsb =HWREG(FCFG1_BASE + FCFG1_O_MAC_15_4_1);
    uint64_t macAddress = (uint64_t)(macAddrMsb << 32) + macAddrLsb;
    */

          uint8_t j = 11;
        /* Reset values to avoid garbage values*/
          packet[7] = 0;
          packet[8] = 0;
          packet[9] = 0;
          packet[10] = 0;
          packet[11] = 0;

       /*Storing LSB of MAC Address in Radio Packet */
       while(macAddrLsb>0)
       {
         packet[j] = macAddrLsb%100;

         if(j!=0)
         {macAddrLsb /= 100;}
         else
         {macAddrLsb /= 10;}
         j--;
       }

    while(1)
    {
        /* Wait for a button press */
        Semaphore_pend(txSemaphoreHandle, BIOS_WAIT_FOREVER);
        /* Reading the  battery voltage */
        batteryStatus = AONBatMonBatteryVoltageGet();
        /* Convert in Milli volts*/
        batteryStatus = (batteryStatus * 125) >> 5;
        batteryVoltage = (float) batteryStatus / 100;

        /* Create packet with incrementing sequence number */
        packet[0] = (uint8_t) (seqNumber >> 8);
        packet[1] = (uint8_t) (seqNumber);
        packet[2] = batteryVoltage;
        //packet[3] = ;

        /* Set absolute TX time to utilize automatic power management */
        times += (PACKET_INTERVAL_US * 4);
        RF_cmdNop.startTime = times;


        /* Send packet */
               RF_runCmd(rfHandle, (RF_Op*)&RF_cmdNop, RF_PriorityNormal,
                         &callback, 0);

               RF_cmdNop.status = IDLE;
               RF_cmdPropCs.status = IDLE;
               RF_cmdCountBranch.status = IDLE;
               RF_cmdPropTx.status = IDLE;
               RF_cmdCountBranch.counter = CS_RETRIES_WHEN_BUSY;
               RF_yield(rfHandle);



    }
}

HWI

/***** Button Callback function *****/

static void buttonClockCb(UArg arg) {

    PIN_Handle buttonHandle = (PIN_State *) arg;
    /* Stop the button clock */
    /* Re-enable interrupts to detect button release. */
    Clock_stop(hButtonClock);
    /* Check that there is active button for debounce logic*/
    if (activeButtonPinId != PIN_TERMINATE)
    {
      /* Checking whether the button is actively pressed*/
      if(!PIN_getInputValue(activeButtonPinId))
      {
          /* Wait here till the button is released */
          while(!PIN_getInputValue(activeButtonPinId))
          {
              usleep(50000);
          }
          /* Checking whether the button is released*/
          if (PIN_getInputValue(activeButtonPinId))
          {
              switch (activeButtonPinId)
              {
                  case Board_DIO10:
                      /* Getting time form the Timestamp function*/
                       time1 = Timestamp_get32();
                       /* Calculating the time between switch pressed and released*/
                       timePeriod = time1-time0;
                       /* Converting the time to microseconds from clock ticks*/
                       microTime = timePeriod/0.065536;
                       /* Converting the time from microseconds to centiseconds */
                       realTime = microTime/10000;
                       /* Reset values to avoid garbage values*/
                       packet[3] = 0;
                       packet[4] = 0;
                       packet[5] = 0;
                       packet[6] = 0;
                       /* Encoding the time in different packets for radio transmission*/
                       i = 6;
                       while(realTime>0)
                       {
                           packet[i] = realTime%100;
                           realTime /= 100;
                           i--;
                       }
                       /* Posting the semaphore for the radio functions*/
                       Semaphore_post(txSemaphoreHandle);
                      break;
                  default:
                      /* Do nothing */
                      break;
              }
          }
      }
    }

    /* Re-Enabling the interrupt for detecting the button press*/
    PIN_setConfig(buttonHandle, PIN_BM_IRQ, activeButtonPinId | PIN_IRQ_NEGEDGE);
    /* Set activeButtonPinId to none... */
    activeButtonPinId = PIN_TERMINATE;
}

My issue is the with power consumption, I am using Lithium CR2032 3V battery and it only last 2 or 3 days, however I ran a test where it sends data every 3 seconds by running only the task and keeping the switch in off position, it lasted for more than 2 weeks. Could anyone please let me know what I am doing wrong in  the code or what can be done to improve the battery life?  Also the all the variables are declared  static.

Thanks in advance

  • The first thing you need to do is to actually measure the current consumption using a power analyzer, or by connecting your HW to one of our LP having EnergyTrace (CC13x2/CC26x2) to be able to figure out which power mode you are in and how much extra current you draw.

    Are you for example entering Standby, but the standby current is too high dues to some wrong configuration of some I/Os, or are you in IDLE state so that something is preventing you for entering standby?

    It is also a good idea to start by checking your HW with known good SW to verify that you get the correct current consumption there. For this you can for example use the pinStandby example from our SDK, and verify that you are able to enter standby with a current consumption of less than 1 uA.

    When running our default examples on your HW you need to make sure that you do the necessary changes to the board files etc, to comply with your HW, unless it is identical to our LPs.

    Siri

  • Hi Siri, 

    Thanks for your reply, I tried to measure current consumption of my HW and I noticed two main issues,

    1. when the device power up it start executing a task and go to standby mode where it is waiting for semaphore post, however it is drawing more current than expected about 250 to 200 micro Amp 

    2. When an HW interrupt call it goes to the callback function device goes to Active mode, do some process and at the end calls semaphore post, once it is done when it comes back to the task it never goes to standby mode even when it reaches semaphore pend. It continues to draw current in milli Amps.

    Is there something I can do in code to avoid this power consumption. Please help.

    Thanks in Advance

  • Hi Antony

    1) The 200 uA current in standby sound like a GPIO. Please make sure that all GPIOs are setup correctly and that you do not have any pins floating.

    2) I assume that you are still testing with your code and not with known good SW?

    I have altered the pinInterrupt example int the SDK to use a semaphore, and have tested that it goes in and out of standby as it should. Code is below:

    /*
     *  ======== pinInterrupt.c ========
     */
    #include <unistd.h>
    
    /* Driver Header files */
    #include <ti/drivers/PIN.h>
    
    /* Example/Board Header files */
    #include "Board.h"
    
    /* BIOS Header files */
    #include <ti/sysbios/BIOS.h>
    #include <ti/sysbios/knl/Semaphore.h>
    #include <ti/sysbios/knl/Task.h>
    
    /* Pin driver handles */
    static PIN_Handle buttonPinHandle;
    static PIN_Handle ledPinHandle;
    
    /* Global memory storage for a PIN_Config table */
    static PIN_State buttonPinState;
    static PIN_State ledPinState;
    
    /* Button Semaphore */
    static Semaphore_Struct buttonSemaphore;
    static Semaphore_Handle buttonSemaphoreHandle;
    
    PIN_Config ledPinTable[] = {
        Board_PIN_LED0 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX,
        Board_PIN_LED1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW  | PIN_PUSHPULL | PIN_DRVSTR_MAX,
        PIN_TERMINATE
    };
    
    PIN_Config buttonPinTable[] = {
        Board_PIN_BUTTON0  | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_NEGEDGE,
        Board_PIN_BUTTON1  | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_NEGEDGE,
        PIN_TERMINATE
    };
    
    static PIN_Id button;
    
    void buttonCallbackFxn(PIN_Handle handle, PIN_Id pinId) {
    
        /* Debounce logic, only toggle if the button is still pushed (low) */
        CPUdelay(8000*50);
        if (!PIN_getInputValue(pinId)) 
        {
            switch (pinId)
            {
                case Board_PIN_BUTTON0:
                    button = Board_PIN_BUTTON0;
                    break;
    
                case Board_PIN_BUTTON1:
                    button = Board_PIN_BUTTON1;
                    break;
    
                default:
                    break;
            }
            Semaphore_post(buttonSemaphoreHandle);
        }
    }
    
    void *mainThread(void *arg0)
    {
    
        ledPinHandle = PIN_open(&ledPinState, ledPinTable);
        if(!ledPinHandle) 
        {
            while(1);
        }
    
        buttonPinHandle = PIN_open(&buttonPinState, buttonPinTable);
        if(!buttonPinHandle)
        {
            while(1);
        }
    
        if (PIN_registerIntCb(buttonPinHandle, &buttonCallbackFxn) != 0)
        {
            while(1);
        }
    
        Semaphore_construct(&buttonSemaphore, 0, NULL);
        buttonSemaphoreHandle = Semaphore_handle(&buttonSemaphore);
    
        while(1)
        {
            uint32_t currVal = 0;
    
            Semaphore_pend(buttonSemaphoreHandle, BIOS_WAIT_FOREVER);
            if (button == Board_PIN_BUTTON0)
            {
                currVal =  PIN_getOutputValue(Board_PIN_LED0);
                PIN_setOutputValue(ledPinHandle, Board_PIN_LED0, !currVal);
            } else
            {
                currVal =  PIN_getOutputValue(Board_PIN_LED1);
                PIN_setOutputValue(ledPinHandle, Board_PIN_LED1, !currVal);
            }
        }
    }
    

    When running the code, and pushing the buttons to post the semaphore and exit Standby, the current profile looks like below:

    I strongly recommend that you test this example and are able to get the correct current profile with this, before you start adding your application specific code, one step at the time. Then it will be easier to figure out what code preventing the device to enter standby again.

    As you can see from the plot above, the device is in Standby almost all the time (you can see this because of the re-charge pulses). However, the current consumption is high in Standby since we are sometimes driving the LEDs.

    You need to figure out if your high current consumption is due to not entering Standby, or if it simply some peripherals on you HW that are consuming a lot of power. Unfortunately I cannot pinpoint what exactly the problem is at your end, since we are not testing on the same HW.

    Good luck debugging :-)

    Siri

  • Thanks a million for your valuable advice. Much appreciated.