This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Connection Parameter Selection for Central Device with 10 Peripheral Simultaneous Connections

Hi,

I am developing both Central and Peripheral devices with nRF52840. For consistency, both are using SDK 15.3.0 and S140 V7.

I am able to connect to peripherals and negotiate MTU ATT size of 247 and I am able to negotiate 2 Mbps phy. Logging on both peripheral and central devices confirm this is working.

My challenge is getting notification data from my peripherals to my central. If I set up (for example) 2 peripherals to notify my central device every 500 mSec with approx 160 bytes of data, all data comes into the BLE event handler (BLE_GATTC_EVT_HVX) within my central device just fine. If I double the data speed on peripherals (ie. 160 bytes every 250 mSec from each of the 2 devices), I only get BLE_GATTC_EVT_HVX events notifying me of incoming data from the first peripheral only.

I believe that I am not getting correct connection service intervals setup after peripheral connection.

For a scenario where a central is talking to 10 peripherals and getting notification data from each every 250 mSec, what would good connection interval, slave latency values be? I cannot seem to find a good reference for setup of connection intervals for multiple simultaneous peripheral connections to a central device - where each peripheral is notifying the central independently.

Note that my connection event length is 6 x 1.25 mSec or 7.5 mSec. This should be plenty long enough to get an MTU of 247 bytes transferred.

I have been using default min and max connection intervals of 7.5 and 30 mSec respectively and a slave latency of 0 (for both central and peripheral devices).

Suggestions for my scenario would be much appreciated.

Thanks in advance,

Mark J

  • I have not looked at a Softdevice spec for a long time and was pleasantly surprised to find this very helpful page showing simple connection timing when no scanning occurs:

    Connection timing as a Central

    and this one with the addition of scanning:

    Primary channel scanner timing

    My requirements are to send a 160 byte notification from EACH of 10 peripherals every 250 mSec. Because I am setup for MTU size of 247 bytes, I can assume 1 packet will support this notification. I will also need to be able to scan when connected with reasonable reliability over a 10-20 sec scan, so I will setup a scan window that is 50 percent of my scan interval.

    I can see from this online resource that (at 2 Mbps phy) I should be able to use an event time of 2.5 mSec for each connection event.:

    Bluetooth 5 speed: How to achieve maximum throughput for your BLE application 

    So, I set my NRF_SDH_BLE_GAP_EVENT_LENGTH (within sdk_config.h) to "2" (2 x 1.25 = 2.5 mSec).

    The Primary channel scanner timing ref suggests that the scan interval should be set to match the connection interval when scanning occurs in sequence with connection events. So, I will setup both as the interval that includes servicing of:

    - each of 10 connections for 2.5 mSec each or 25 mSec total for 10 connections.

    - scan window that will be 50% of the scan interval / connection interval. If I use 30 mSec - I will use a scan interval and connection interval of 60 mSec.

    - scan interval / connection interval of 60 mSec (ie. I set both scan interval and connection interval to 60 mSec). This will support 25 mSec for 10 events with length 2.5 mSec each plus 5 mSec for other things that occur between connection events and scanning and my 30 mSec scan window.

    Using these settings (and confirming the connection parameter update is completing on each peripheral via a BLE_GAP_EVT_CONN_PARAM_UPDATE event on the central for each peripheral connection), I am noticing 2 issues when testing with only 2 peripherals...

    1. Setting the NRF_SDH_BLE_GAP_EVENT_LENGTH to 2 (2.5 mSec) causes problems with sd_ble_gattc_write(). Periodically - it is returning BLE_ERROR_INVALID_CONN_HANDLE - even though this handle (0x0000) is successfully used before the sd_ble_gattc_write() call that fails (ie. it works for some time and then fails) Not sure how the NRF_SDH_BLE_GAP_EVENT_LENGTH could effect a handle validity. Softdevice Bug? If I use a NRF_SDH_BLE_GAP_EVENT_LENGTH value of 6 - I never see this issue. I also see it when using a valud of 3 (3.75 mSec).

    2. Even when I do NOT see the first issue (1 above) I am not able to consistently get all notifications to my BLE event handler (BLE_GATTC_EVT_HVX event). I do get all notifications from both peripherals sometimes, but during most tests I only get notifications from 1 peripheral device. On occasion, I do not get notifications from either peripheral device.

    I may misunderstand what the NRF_SDH_BLE_GAP_EVENT_LENGTH represents. I see that it can be set as high as 320 (400 mSec) in the ble_app_hrs_c example. This seems huge for the amount of time to spend on a connection. My understanding is that it is the amount of time to service each connection. If a single packet (even 256 bytes) is transferred on a 1 Mbps link (default) this should only take less than couple of mSec. Perhaps far more packets are read/written during a connection event? If I am only getting notification from each peripheral with < 200 bytes and I have confirmed an MTU of 247 bytes, how long do I need the event length to be? To service more connections and each of those connections faster, I would expect this NRF_SDH_BLE_GAP_EVENT_LENGTH should be as low as possible.

    Perhaps I misunderstand what the connection interval means for multiple connections. I expect it to be the time taken to service ALL connections plus the scan window. So, if each connection needs 7.5 mSec (if event time is 7.5 mSec) and I have 10 connections, I will need 75 mSec to handle all connection events and then more time for scanning before the connection interval has completed. Is this understanding correct?

    Thanks,

    Mark J

  • Hello Mark,

    Sorry for the late reply. We are quite short staffed on support due to summer holidays. I am sorry, I didn't have time to reply before the weekend. Answering only your first post first:

    Are you sure that you are only receiving data from one peripheral connection? Perhaps you are spending too much time in the interrupt from the first device, so that the second device is not handling. I assume (based on your case history) that you are using the Nordic Uart Service (NUS). Do you print all the incoming data on the UART? What happens if you only try to leave the interrupt immediately, and just print something like: NRF_LOG_INFO("notification received from conn_handle %02x", conn_handle) whenever you receive data? Do you get both devices then?

  • So the second post:

    Total throughput:

    160bytes  * 10 devices * 4Hz * 8bit/byte = 51 200bps, which is within the theoretical limit.

     

    Mark J said:

    - each of 10 connections for 2.5 mSec each or 25 mSec total for 10 connections.

    - scan window that will be 50% of the scan interval / connection interval. If I use 30 mSec - I will use a scan interval and connection interval of 60 mSec.

     Things start to get a bit messy when you do a lot of things at the same time, and expect a high throughput. First of all, a 50% scan window will block up to half of your possible throughput. There is only one radio, so you can only do one thing at the time. Advertise, scan or maintain a connection.

     

    Mark J said:
    1. Setting the NRF_SDH_BLE_GAP_EVENT_LENGTH to 2 (2.5 mSec) causes problems with sd_ble_gattc_write(). Periodically - it is returning BLE_ERROR_INVALID_CONN_HANDLE - even though this handle (0x0000) is successfully used before the sd_ble_gattc_write() call that fails (ie. it works for some time and then fails) Not sure how the NRF_SDH_BLE_GAP_EVENT_LENGTH could effect a handle validity. Softdevice Bug? If I use a NRF_SDH_BLE_GAP_EVENT_LENGTH value of 6 - I never see this issue. I also see it when using a valud of 3 (3.75 mSec).

     If you try to ignore this return (don't pass it onto APP_ERROR_CHECK()), do you get a disconnected event immediately after this?

     

    Mark J said:
    2. Even when I do NOT see the first issue (1 above) I am not able to consistently get all notifications to my BLE event handler (BLE_GATTC_EVT_HVX event). I do get all notifications from both peripherals sometimes, but during most tests I only get notifications from 1 peripheral device. On occasion, I do not get notifications from either peripheral device.

     Can you test not printing all the data from the notification, but just monitoring that they have arrived? Does it still behave like that?

    The NRF_SDH_BLE_GAP_EVENT_LENGTH will apply for all connections (individially), but unless you are using the entire event length in one connection, it will finish off the event when both parts are satisfied. 

    Mark J said:
    Perhaps far more packets are read/written during a connection event?

     Indeed they are. They can keep sending everything that is queued up before the connection event for as long as the connection event length has not ran out.

     

    Mark J said:
    Perhaps I misunderstand what the connection interval means for multiple connections. I expect it to be the time taken to service ALL connections plus the scan window. So, if each connection needs 7.5 mSec (if event time is 7.5 mSec) and I have 10 connections, I will need 75 mSec to handle all connection events and then more time for scanning before the connection interval has completed. Is this understanding correct?

     That is correct. And to make it even more complicated. Your connection events may not be nicely stacked in the beginning of your connection event cycle. They can be spread around, so you may not have that large time at the end to do scanning.

    This is mentioned a couple of times (in other tickets on the forum), but I'll copy one that I wrote not too long ago in a private ticket:

    The first thing you need to decide on is what you want your scan_window/scan_interval is going to be. This will decide how many % of the total time you will spend scanning, and hence, how big the probability of picking up an advertisement is. 

    The second thing you need to consider is that the softdevice can only schedule complete scan windows. If a scan window crashes with a planned advertising packet, it will have to pick one. This scheduler is dynamic, so if it has skipped many advertising packets earlier, advertisements will have higher priority. The same applies to scan windows. As you can see from the "SoftDevice timing-activities and priorities" from infocenter, you can see that connection related events have the highest priority, then comes scanning and advertising after that. 

    Back to your case. Every 70ms you want to maintain 4 connections. As a peripheral you have no control on where in this 70ms timeslot these connection events are placed. They can be placed nicely very close together, or they can be scattered out randomly:

    In addition, you will have the 1 - 2 advertisement events scattered around.

    So what you need to do is to make an educated worst case guess. As you can imagine, setting the scan window to 50ms will only work flawless if the connection events are stacked nicely together, which is very unlikely. In the "Worst case", you have 4 connection events and 2 advertisemen events scattered with equal distance, 70ms/(4+2) = 11ms.

    But even if you set your advertising and scan window to match 11ms, you they can still collide with the connection events. As you see, it starts to become very difficult to predict the best scan interval/window when you have advertisements and 4 connections at the same time. 

    It is likely that if you set the scan window to ~10ms you will be able to fit a couple of them into each connection interval. Setting it to ~50ms you are almost guaranteed that you will have many connection intervals without any scan windows. 

    But even if you set it to 10ms, there may be some connection intervals where you don't scan any of the 50ms advertisements, and there is also possible that you don't get to send out an advertisement every advertising interval, due to collisions with scan windows and connection events. 

    My suggestion to you is that you experiment with different scan intervals, scan windows, and advertising intervals. I think I would start with a scan interval of 70ms/4, and scan window of 10ms. If you still get too few packets, you can try to increase the advertising interval, but be aware that this will also cause more scan windows to not be prioritized. 

    I see that you wrote a new comment while I was writing this answer:
    P.S. Maybe it will be better to have 27 bytes packages instead of 251 but send a few packages within connection interval and have one confirmation. Is it good?

    It doesn't really matter. It is not really the length of the connection events, but the number of them that really matters when you try to fit scan windows in between. 

    I know that this is a lot of information, but hopefully it gave a bit more insight in how the softdevice handles scanning together with advertising and connections. 

  • Hi 

    As per my last entry: Increase Supported Links to Peripherals on a Central Device

    ... I took out NUS as it would not work in providing me a proper reference. I am now using direct connection handles and this is working better in that I always seem to get the correct reference to the connected peripheral sending me notification data.

    I am leaving the interrupt quickly and running my code on the main thread using a scheduler.  Here is my main loop:

     // Enter main loop.
      while (true)
      {
        // Proc USB events.
        while (app_usbd_event_queue_process()) { /* Nothing to do */  }
    
        // if(tempCnt++ >= 300000) { SEGGER_RTT_printf(0, "X\n"); tempCnt = 0;}
    
        // Handled scheduler actions.
        app_sched_execute();
    
        // Manage power.
        // nrf_pwr_mgmt_run(); 
      }

    By printing "x" I can see that my loop iterates < 10 uSec, so I am leaving the interrupt quickly and able to service the scheduler quickly on the main thread. I suspected that scheduling delay and handler execution time (ie. too long in a handler) may be the issue, but I am quite convinced it is related to the radio. More in my next reply below.

    IMPORTANTLY - I am not interested in scanning when transferring data. I am only scanning to setup connections. I scan, stop scanning, connect to my 10 peripherals and then I request that they notify me every 250 mSec. I have to setup a ble_gap_scan_params_t* to pass to sd_ble_gap_connect() - when connecting to each peripheral. I have been using the same scan interval and window within this ble_gap_scan_params_t object. Maybe that is my issue? If I want no scanning after connection, can I set this ble_gap_scan_params_t* to null or some other value that drastically or totally eliminates scanning after connections?

    Regards,

    Mark J 

  • Ok, so by browsing through your issue. Is the issue that you are lacking data from devices? Just as a test. If you don't send a lot of data, only a couple of bytes e.g. every 10 seconds. Do you receive the events from all devices?

    And when you crank it up, you are lacking data? If you are continuously queuing up data from all the devices. Does all of them return NRF_SUCCESS when you call the softdevice hvx calls from the peripherals?

Related