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 on CC2640

Expert 1340 points
Other Parts Discussed in Thread: CC2650, CC2640

I have a CC2650DK and would like to:

1) Use a random BLE address. Currently it seems to be fixed in the SimpleBLEPeripheral and HeartRate examples. 

2) I would like advertising to start on a button press (as it currently does), but I'd like it to stop (CC2650 in STANDBY) after a preset time period. The button press will bring the system ACTIVE and start BLE advertising. 

3) Is there an LED on the main board that's free to indicate whether the CC2650 is advertising (flashing on/off) or connected (on) or STANDBY (off)?

4) Use event based notifications (versus a timer based period). For example, HeartRate example uses a timer. How can I modify this example to send continuous 20 byte data packets when the master (Android Nexus 7 2013 with minimum 7.5ms connecion interval) enables notifications? I want to test the maximum BLE throughput which should be ~85kbps.

Advice on these topics is appreciated!

  • Hello,

    See the GAP_ADDR_TYPE_DEFINES in gap.h, and how GAPROLE_ADV_EVENT_TYPE is set to use private addresses.

    You can refer to how the SensorTag uses the button to enable LIMITED advertising, vs. the GENERAL advertising on the SmartRF06 board / CC2650EM.

    Yes, there are LEDS (x4) available on the SmartRF06 board.

    I doubt you'll get 85kbps due to limittions on the Android side, but you can increase the MAX_NUM_PDUs to allow for enqueing more packets.

    Best wishes
  • Hi JXS, could you please expand on MAX_NUM_PDUs and how to use it to send data? What is the actual call to send notifications? Could you please post an example of how to send a notification(s) and if necessary check if more can be sent before losing any packets? What's the max datarate achieved with CC2650 to an Android with 7.5ms connection intervals and 20B/packet? On the Nordic nRF51 I'm able to achieve 85kbps as confirmed by a Frontline BPA LE analyzer. Thank you.

  • Hello,

    The API is GATT_Notification(), however I suggest you review the included SW developer's Guide (SWRU393) on how to use this. There are many examples of sending Notifications in the SDK, including SimpleProfileChar4 in SimpleBLEPeripheral. Another good reference to look at is the UART to BLE Bridge TI Design: www.ti.com/.../TIDC-SPPBLE-SW-RD

    MAX_NUM_PDU defines the max number of enqueued packets, i.e., number of Notifications you can enqueue prior to the start of a connection event.

    Did your Frontline trace show the data rate in terms of Notification payload or raw BLE throughput? The CC2640 is capable of sending continuous data in a connection event (up to the timing constraint defined by the core spec), however most phones limit the number of packets per connection event.

    Best wishes
  • Hi JXS,

    I saw the SimpleBLEPeripheral and HeartRate examples and they use notifications to send data upon timer expiration. What I'd like to do is not use the timer, but rather just blast as many notifications as possible in a, for example, a while(true) loop. So would I call GATT_Notification() repeatedly until error? Where would I get a callback so that I can restart the GATT_Notification() calls?

    On the Nordic nRF51, I'm getting 85kbps user payload, not raw. What is the max you've gotten on CC2650DK? Is there an example code for this?


    Thanks!

  • We are working on this exact example right now but we can definitely beat 85 kbps. The CC254x was capable of beating that from the 1.2.1 release several years ago: processors.wiki.ti.com/.../CC2540_Data_Throughput
  • Hi Tim,

    I don't quite understand why you say >85kbps payload throughput. Is the green line payload throughput? It's only 50kbps max. And the text says 80B (20B * 4 notifications) are sent in 10ms connection events, so that's 64kbps. Looking forward to the example for the CC2650, but in the interim, what do I need to check for in order to call GATT_Notification() repeatedly without losing data?

    Thanks!
  • The CC254x throughput can be increased using overlapped processing: processors.wiki.ti.com/.../OverlappedProcessing

    The allocation and handling of GATT messages is described in section 5.3.5 of the 2.1 software developer's guide:
  • Hi Tim,

    I don't see a section 5.3.5 in swru393.

    Thanks for the OverlappedProcessing wiki, however it's not applicable to me since I want to use a common Android/Apple/Windows device as the master, so it will set the max number of PDUs in the connection interval. Anyhow it's a good starting point and I'd like some clarifications.

    In the wiki, it says that 20B are sent every 1ms using a timer. This is obviously slower than the min allowed connection interval of 7.5ms, so multiple packets should be ready for each connection event. But how do you know you've not saturated the number of buffers when calling GATT_Notification()? There's no else for the if statement

    if (!(GATT_Notification(0, &noti, FALSE))) //if sucessful

    So what should we do if this fails? Is the number of buffers MAX_NUM_PDU, which is 10 in bleUserConfig.h?

    In my system, 60B of data will be ready for transmission every 50ms. How can I implement data transmission without using a timer to send 3x 20B every 1ms after the interrupt? Do I simply call GATT_Notification() three times in a row with the correctly allocated data (three GATT_bm_alloc() calls)? 

    Thanks!

  • I did some testing on HeartRate_measNotify() and used the else of

    if (!(GATT_Notification(0, &noti, FALSE))) //if sucessful

    to update the values to be sent in the notification. This matches the overlapped processing example where you update the value if successful transmission, otherwise wait until the next call of  HeartRate_measNotify(). The HeartRate_measNotify() function already deallocates the GATT_bm_alloc() if the transmission is not successful, so I think this solution should work fine.

    Another thing I did was instead of using a timer that expires every 1ms to send 20B, I instead posted the semaphore with the HEARTRATE_MEAS_PERIODIC_EVT set. So instead of using a timer to call Gatt_Notification(), I did the following:

    static void HeartRate_taskFxn(UArg a0, UArg a1)
    {
      // Initialize the application.
      HeartRate_init();
      
      // Application main loop.
      for(;;)
      {
    ...    
        // Heart rate service periodic task.
        if (gHRNotifyEnabled && events & HEARTRATE_MEAS_PERIODIC_EVT)
        {
          events &= ~HEARTRATE_MEAS_PERIODIC_EVT;
          
          HeartRate_measPerTask();
        }
        
    ...
      }
    }
    
    static void HeartRate_measPerTask(void)
    {
      if (gapProfileState == GAPROLE_CONNECTED)
      {
        // Send heart rate measurement notification.
        HeartRate_measNotify();
        
        // Restart timer.
    //    Util_startClock(&measPerClock);
        events |= HEARTRATE_MEAS_PERIODIC_EVT;
        Semaphore_post(sem);
      }
    }
    
    static void HeartRate_heartRateEvt(uint8_t event)
    {
      if (event == HEARTRATE_MEAS_NOTI_ENABLED)
      {
        // If connected start periodic measurement.
        if (gapProfileState == GAPROLE_CONNECTED)
        {
    //      Util_startClock(&measPerClock);
        	gHRNotifyEnabled = 1;
        	events |= HEARTRATE_MEAS_PERIODIC_EVT;
        	Semaphore_post(sem);
        }
      }
      else if (event == HEARTRATE_MEAS_NOTI_DISABLED)
      {
        // Stop periodic measurement.
    //    Util_stopClock(&measPerClock);
    	  gHRNotifyEnabled = 0;
      }
    ...
    }

    Are there any benefits to using the 1ms timer versus what I'm doing? Both methods stream 85kbps data to an Asus Nexus 7, which is what I expect.

  • Hello. You are likely looking at the wrong SDG. The SDG for the 2.1.0 release describes GATT notifications in section 5.3.5.

    Also, I just created a wiki that blasts GATT_Notificaitons as frequently as possible: processors.wiki.ti.com/.../CC26XX_BLE_Throughput
  • Yep, I was looking at SDG v2.0; v2.1 has section 5.3.5 :)

    Thanks for the wiki. In your wiki, you don't post the semaphore after each loop in blastData(), but rather just use a while(1). Is there a drawback/benefit to posting the semaphore, or should I do it as you have done? I suppose the throughput would be slower, but I connecting to an Android device which has a limited number of connection events per connection interval. Also, does Android/iOS support ATT_MTU=255, or are they limited to 23? Thanks!

  • Each Android stack is different so they may have different ATT_MTU max sizes / packets per connection event limits.

    In your example, it looks like you are sending data, then posting an event to resend the data. The semaphore is not actually needed since you are posting the event from the same (application) task. In any case, you could adapt this event-driven mechanism to the wiki example. You will not queue up notifications as quickly but there will be opportunities for other events / queue items to process since you're not stuck in the while loop.
  • Thanks for your help Tim. I think this is working fine now. FYI the SDG link goes to v2.0; I got v2.1 in the c:\ti install directory.