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.

CC2650 Power constraints interaction with BLE stack causing connection problems

I originally posted this message with regard to using the UART: https://e2e.ti.com/support/wireless_connectivity/bluetooth_low_energy/f/538/t/558238  The problem was that I wanted to disable/close the UART after a some time, but at soon as I did, any BLE connection would become unstable and drop, as would further connection attempts (advertising seems to be unaffected, and the device always returns to advertising after a connection drop).  But I have since found that the problem is not specifically with the UART, but more generally about timing when using power constraints and their interaction with the BLE stack. I am hoping that someone at TI can follow up and see if there is a real issue, or if this is just an operator-error thing on my part!

I still have the same setup described in the other posting:  simple_peripheral_cc2650em_app with POWER_SAVING defined, running on a SmartRF06; Software versions are BLE SDK 2.02.00.31, TI-RTOS 2.18.00.03, and XDCtools 3.32.00.0.  Here is a simple experiment to reproduce the problem.  I modified the original version of simple_peripheral.c and main.c with the following (everything else, including the drivers, is unmodified):

simple_peripheral.c:

#define SBP_DLY_START_EVT                    0x0010

#define SBP_DLY_STOP_EVT                      0x0020

static Clock_Struct pcTimer;

uint8_t pctype = 0;

.

.

.

static void SimpleBLEPeripheral_taskFxn(UArg a0, UArg a1)

{

  // Initialize application

  SimpleBLEPeripheral_init();

  if (pctype == 1)

  {

     unsigned int ikey = Hwi_disable();  // Disable interrupts

     Power_setConstraint(PowerCC26XX_SB_DISALLOW);

     Hwi_restore(ikey); // Re-enable interrupts

     PIN_setOutputValue(hSbpPins, Board_LED4, 1);

     Util_constructClock(&pcTimer, SimpleBLEPeripheral_clockHandler,

           10000, 0, false, SBP_DLY_STOP_EVT);

     Util_startClock(&pcTimer);

  }

  else if (pctype == 2)

  {

     Util_constructClock(&pcTimer, SimpleBLEPeripheral_clockHandler,

           10000, 0, false, SBP_DLY_START_EVT);

     Util_startClock(&pcTimer);

  }

  // Application main loop

  for (;;)

  {

.

.

.

    if (events & SBP_DLY_START_EVT)

    {

       unsigned int ikey = Hwi_disable();  // Disable interrupts

       events &= ~SBP_DLY_START_EVT; //clear event

       Power_setConstraint(PowerCC26XX_SB_DISALLOW);

       Hwi_restore(ikey); // Re-enable interrupts

       PIN_setOutputValue(hSbpPins, Board_LED4, 1);

       Clock_destruct(&pcTimer);

       Util_constructClock(&pcTimer, SimpleBLEPeripheral_clockHandler,

                            10000, 0, false, SBP_DLY_STOP_EVT);

       Util_startClock(&pcTimer);

    }

    if (events & SBP_DLY_STOP_EVT)

    {

       unsigned int ikey = Hwi_disable();  // Disable interrupts

       events &= ~SBP_DLY_STOP_EVT; //clear event

       Power_releaseConstraint(PowerCC26XX_SB_DISALLOW);

       Hwi_restore(ikey); // Re-enable interrupts

       PIN_setOutputValue(hSbpPins, Board_LED4, 0);

       Clock_destruct(&pcTimer);

    }

.

.

.

I also added some code to main.c to monitor when the device goes into standby from the debugger:

#ifdef POWER_SAVING

// Power Notify Object for wake-up callbacks

static Power_NotifyObj powerNotifyObj;

static uint8_t powerNotifyCb(uint8_t eventType, uint32_t *eventArg, uint32_t *clientArg);

#endif //POWER_SAVING

int main()

{

.

.

.

#ifndef POWER_SAVING

  /* Set constraints for Standby, powerdown and idle mode */

  Power_setConstraint(PowerCC26XX_SB_DISALLOW);

  Power_setConstraint(PowerCC26XX_IDLE_PD_DISALLOW);

#endif // POWER_SAVING

#ifdef POWER_SAVING

  Power_registerNotify(&powerNotifyObj,

                       PowerCC26XX_ENTERING_STANDBY,//| PowerCC26XX_AWAKE_STANDBY,

                       (Power_NotifyFxn)powerNotifyCb, NULL);

#endif //POWER_SAVING

.

.

.

#ifdef POWER_SAVING

int standbycnt=0;

static uint8_t powerNotifyCb(uint8_t eventType, uint32_t *eventArg, uint32_t *clientArg)

{

  if (eventType == PowerCC26XX_ENTERING_STANDBY)

  {

     standbycnt++;

  }

  // Notification handled successfully

  return Power_NOTIFYDONE;

}

#endif

With these modifications, while in the debugger, standbycnt and pctype can be watched, and the latter modified:

pctype = 0: this is the original configuration of simpleBLEPeripheral

pctype = 1: The device is initially constrained from entering standby for 10 seconds, after which the constraint is released

pctype = 2: The device is constrained from entering standby after 10 seconds (by which time the device is up and advertising), and released from that constraint after another 10 seconds.

With pctype = 1, connections to the client have a significant number of missed SimpleBLEPeripheral packets, and depending upon the client, the connection make actually drop with new GAProle state GAPROLE_WAITING_AFTER_TIMEOUT. (I am using LightBlue on Mac OS, which sometimes seems more tolerant of the missing packets, even though the—default—connection parameters are set for slave latency of 0.)  Because the connection may not drop (or make take a while to drop), the problem is best viewed using some kind of BLE sniffer.  (I use a adafruit/WireShark combination.)

pctype = 2 is a workaround that allows the constraint to be used as long as it delayed “sufficiently”.  I do not know what the minimum time is.  I do know that it has to come with advertising enabled, and after advertising has begun.  If I try it with advertising initially disabled, the connection problem still exists regardless of delay(s).

My current solution is a variation of pctype = 2, but in my mind that is kind of a kludge.  I am hoping there is a better solution or at least an explanation of why my assumptions about power constraint use (including the ones in the UART driver) are wrong.  Any help would be greatly appreciated.

dave

  • I saw in your custom events, you are disabling HW interrupt in the event. You don't need to do that in order to set up the power constraint. Also disable HW interrupt in your application layer might break the radio operation.

    Can you try to run the code without Hwi_disable and Hwi_restore?
  • Hi Christin, thanks for responding.

    I just tried it without disabling/enabling HWI, but the problem still exists.  Actually, that was the way I originally had it (without), but tried adding that after seeing similar code in threadSafeStdbyDisSet() and threadSafeStdbyDisRelease() in UART26XX.c to see if it made a difference (it didn't!).

    I should also point out that the my original tests were done with optimization level 1.  I just tested it again with optimization level 4 (the default for simple_peripheral_cc2650em_app), but I had to make pctype volatile so that the code path options would not get optimized out.  With that change, pctype = 1 still causes the problem, and the pctype = 2 workaround still works. (By the way, the matching stack project is also unmodified, and at optimization level 4.)

    Can someone (TI or otherwise) please try these tests and see if you can duplicate my results?