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.

BLE connection drops when UART is closed on CC2650 with POWER_SAVING

Other Parts Discussed in Thread: CC2650

I am having a problem when disabling the UART on a CC2650, which causes strange sleep/standby behavior and BLE connections to be dropped. I have modified a version of 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.06 (also tried 3.32.01.22). While I have modified the characteristics, the BLE setup and default settings are unmodified.

The UART is initialized at the very end of SimpleBLEPeripheral_init(). TX blocks and RX uses a callback function. The callback uses a variation of the receive-continuously example from UARTCC26xx.h, with RETURN_PARTIAL_ENABLE, writing to a circular buffer. (I did originally try the tl.c example code, but ultimately wanted something simpler and smaller.) It functions as expected when connected to a terminal via SmartRF06 USB. To enable sleep, I can signal the system to stop reading and disable/close the UART (which is necessary for our ultimate device).

I first noticed that after disabling the UART, if there was a client connected to SimpleBLEPeripheral, the connection would shortly drop, and reconnection would be difficult and/or short-lived. (Advertising seems unaffected.) I looked at the packets and saw that prior to disconnection, the connection interval would increase significantly, perhaps in response to the fact that SimpleBLEPeripheral was missing a lot of packets when responding to the Master/Client. When disconnection occurs, the new state is given as GAPROLE_WAITING_AFTER_TIMEOUT.

I registered a power notify function that counts the number of PowerCC26XX_ENTERING_STANDBY events, and monitor this in the debugger. With the unmodified version of SimpleBLEPeripheral (i.e. no UART), standby events occur fairly slowly and regularly, about once per second. With the UART code, of course no standby events occur while the UART is continuously reading. But as soon as I disable and close the UART, the standby counter starts increasing rapidly, much faster than the unmodified case.

I have tried various things, trying to reduce the UART code to the bare minimum, but I am at a loss to solve this problem. Hopefully someone can offer a solution or some suggestions. Any help would be greatly appreciated!

I have included the code I am using. By the way, no errors or buffer overflows are occurring, as the amount of data being transferred is tiny compared to the buffer size. The call to UART_readCancel() does cause a size=0 call to the callback function, and the reads terminate prior to closing the UART.


Hardware parameters are as is from CC2650DK_7ID.c:

/* UART hardware parameter structure, also used to assign UART pins */
const UARTCC26XX_HWAttrsV1 uartCC26XXHWAttrs[CC2650DK_7ID_UARTCOUNT] = {
   {
      .baseAddr = UART0_BASE,
      .powerMngrId = PowerCC26XX_PERIPH_UART0,
      .intNum = INT_UART0_COMB,
      .intPriority = ~0,
      .swiPriority = 0,
      .txPin = Board_UART_TX,
      .rxPin = Board_UART_RX,
      .ctsPin = PIN_UNASSIGNED,
      .rtsPin = PIN_UNASSIGNED
   }
};


#define UART_BUF_LENGTH (512)
#define UART_BUF_MASK (UART_BUF_LENGTH-1)

static uint8_t rx_buf[UART_BUF_LENGTH];
static uint16_t rx_head;
static uint16_t rx_tail;

static UART_Handle uartHandle = NULL;
static uint8_t uartEnabled = FALSE;
static int uerror = 0;

// UART RX Callback function
static void readCallback(UART_Handle handle, void *buf, size_t size)
{
   size_t nextrd=0;

   // check for errors
   UARTCC26XX_Object *object = handle->object;
   UART_Status ustat = object->status;
   if (ustat)
   {
      uerror = 1;
   }

   rx_head = UART_BUF_MASK & (rx_head + size);

   // Store the event.
   events |= GP_UART_RX_EVT;

   // Wake up the application.
   Semaphore_post(sem);

   if (uartEnabled)
   {
      nextrd = UART_BUF_MASK & (rx_tail - rx_head - 1);
      if (nextrd > (UART_BUF_LENGTH - rx_head))
      {
         nextrd = UART_BUF_LENGTH - rxbuf.head;
      }
      if (nextrd > (UART_BUF_LENGTH/2))
      {
         nextrd = (UART_BUF_LENGTH/2);
      }

      // Start another read into available space
      UART_read(handle, rx_buf+rx_head, nextrd);
   }
}

void uartInit(void)
{
   if (!uartEnabled)
   {
      // Configure UART parameters.
      UART_Params params;

      UART_Params_init(&params);
      params.baudRate = 115200;
      params.writeDataMode = UART_DATA_BINARY;
      params.readMode = UART_MODE_CALLBACK;
      params.readDataMode = UART_DATA_BINARY;
      params.readCallback = readCallback;

      // Open / power on the UART.
      uartHandle = UART_open(Board_UART, &params);
      uartEnabled = TRUE;

      //Enable Partial Reads on all subsequent UART_read()
      UART_control(uartHandle, UARTCC26XX_CMD_RETURN_PARTIAL_ENABLE, NULL);

      rx_head = rx_tail = 0;

      // initiate reading from port
      UART_control(uartHandle, UARTCC26XX_CMD_RX_FIFO_FLUSH, NULL);
      UART_read(uartHandle, rx_buf, UART_BUF_LENGTH/2);
   }
}

void disableUart(void)
{
   if (uartEnabled)
   {
      uartEnabled = FALSE;
      UART_readCancel(uartHandle);
      // should not be necessary, because UART_write is blocking, but try anyway
      UART_writeCancel(uartHandle);
      UART_close(uartHandle);
      uartHandle = NULL;
   }
}

  • Hi Dave,

    Thank you for providing such detailed information about your setup. Are you using IAR or CCS?

    If I understand correctly, you are modifying SimpleBLEPeripheral to use your own UART driver. The UART seems to be communicating correctly but when you attempt to turn off the UART functionality, the BLE connection drops.

    You mentioned that advertising seems unaffected but then you also mentioned that you see GAPROLE_WAITING_AFTER_TIMEOUT. Does it return to advertising after you see this state?

    Can you provide a sniffer capture of the connection interval increasing and reconnection issues? Do you see the same issue if you use the UART driver without modifications?
  • Hi Rachel,

    Thanks for looking into this.  I am using CCS, and I am using unmodified versions of all the TI drivers, including UARTCC26XX.c/h.  I only added the  code above to use the stock UART driver.

    Yes, after the connection drops, advertising starts again, and I can intermittently connect to it, but it drops each time. My only means of packet capture is using an adafruit sniffer, which outputs to Wireshark using some parser that was installed with driver.  I can probably post a screen shot of the relevant information, however.

    Here is some new information:  Maybe this is not surprising, but the problem seems to occur much faster when operating in the debugger, perhaps because of the all the additional standby events.  (Note, however, that the unmodified version of SimpleBLEPeripheral runs fine in the debugger.)

    I am also exploring whether or not commenting out the UART_close() has any effect, i.e. if the problem occurs after the UART_readCancel().  Still not sure.  I will take a look at it with fresh eyes tomorrow.  If you have any suggestions in the mean time, please let me know.

    dave

  • Hi Rachel (and anyone else who might be listening),

    I looked at this more, and I think I have narrowed down the problem. I do not think it has anything specifically to do with the UART, but rather the power constraints that are made when a read is initiated, like in my uartInit() function above. I found that if I call that function from SimpleBLEPeripheral_init() (or anytime before ICall_wait() in the task function for loop), the problem would occur. If it started it later (I tied the UART enable/disable to a switch on the evaluation board), there was no problem.

    So to simplify the problem I tried just adding to the end of the initialization function:

    Power_setConstraint(PowerCC26XX_SB_DISALLOW);
    Power_setConstraint(PowerCC26XX_IDLE_PD_DISALLOW);

    and then added:

    Power_releaseConstraint(PowerCC26XX_SB_DISALLOW);
    Power_releaseConstraint(PowerCC26XX_IDLE_PD_DISALLOW);

    in response to a switch being pressed (using an interrupt with the event flag and semaphore etc.) to allow the device to go into standby. The UART is disabled and not used. With this configuration, I initiate a connection, and then push the switch to release the constraints. As expected, SimpleBLEPeripheral can go into standby, but the packet responses are missed, and the connection fails.

    If instead I make the calls to Power_setConstraint *after* ICall_wait() (using the same event flag/semaphore method above), the everything works fine.

    Can someone else please try this?