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

Parents
  • 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?

  • 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 

Reply
  • 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 

Children
  • 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?

  • Yes. The issue appears to be that I am lacking data from devices. I have sent the same data slower and I receive all data. For example, If I send 160 bytes every second, I get all data.

    When I go faster, notification data only comes in from 1 of 2 connected peripherals. As I am using notifications, I am not making hvx calls.

    I had suspected that the issue related to a scan window interrupting my connection events, but if I am NOT CURRENTLY SCANNING, I think that the scan window will not affect connection event servicing. Is this true?

    If I setup a connection scan window (say 100 mSec) and a connection interval of 120 mSec and I am not scanning, will there be any effect on connection event servicing and the ability for peripherals to notify me of data changes?

    I do not need to scan when getting notification data from peripherals. I will scan, connect, then get data.

    Mark J

  • BLE is a lossless protocol (ensured by ACKing and retransmission), so scanning shouldn't affect this. As long as you are not disconnected, all packet should arrive eventually, and in the same order as you send them.

    Perhaps you can show me how you are sending the data where you see the loss?

    You are still using SDK15.3.0, right? The reason I ask is that from SDK16.0.0 they did something to the ble_nus_c_string_send() which in my opinion makes it unreliable. The 15.3.0 implementation of this should be good.

  • Was off until today.

    If scanning interrupts connection events  and these events back up, eventually there must be losses at the app level. This Nordic page (and others) are pretty clear about how connection events can be affected by scanning: Suggested intervals and windows.

    Since sending my last comment, I have tried setting very small scanning windows and this has not improved throughput.

    As stated in our last post and this post, we are not using NUS anymore. We are now able to use the underlying api support to get connection handles and reference connections using these handles. NUS did not give us access to handles. This is all described in the last post. This code is working fine if we have slow data updates (2 peripherals notifying us every 500 mSec with 160 bytes of data). The issue is if these peripherals notify at 250 mSec freq (160 bytes), we can miss data from 1 of the 2 peripherals (all notifications from that peripheral). 

    Please re-read the top of this post as it clarifies how we are sending data. 

    Yes, still using SDK 15.3.0, but as stated not NUS.

    Could the be related to the code servicing BLE notifications not getting enough bandwidth? My main loop is in an earlier post in this thread. Empirical testing shows that loop time is < 10 uSec, so I would expect that this is fast enough.

    Would it be faster to poll peripherals instead of their using notifications to send the central data? This seems counter-intuitive, but we need to get a solution quickly. We have customers waiting for our device firmware with support for 10 peripherals and this is the last hurdle to completion.

    Mark J

  • Mark J said:
    As stated in our last post and this post, we are not using NUS anymore. We are now able to use the underlying api support to get connection handles and reference connections using these handles.

     I am sorry for mixing up. Please remember that we handle many cases every day, so when there are days between looking at a ticket, I sometimes forget details.

    Mark J said:
    As stated in our last post and this post, we are not using NUS anymore. We are now able to use the underlying api support to get connection handles and reference connections using these handles.

    The ble_nus_c.c file doesn't forward the connection handle to the event handler. This can easily be fixed by adding:

    ble_nus_c_evt.conn_handle = p_ble_evt->evt.gattc_evt.conn_handle;

    in on_hvx() in ble_nus_c.c. But I'll stop nagging about this now. Just in case you wondered why. 

    Can you check that the peripherals that are sending this data is calling  sd_ble_gatts_hvx(), and that this returns NRF_SUCCESS on the data you claim to be missing?

    Note that if the peripheral is never actually getting the data through, then the continuous calls to sd_ble_gatts_hvx() will eventually return NRF_ERROR_RESOURCES, before disconnecting.

    Have you tried to sniff the connections? Can you see the data from both devices over the air? The nRF Sniffer should be sufficient for this sniffer trace. You can only sniff one connection at the time, so try to sniff the connection that you don't see the data from.

    Best regards,

    Edvin

Related