Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Use NUS Service on bonded devices without discovery

Hi,

I am developing a system with 2 nrf52840 devices, communicating via the NUS Service. I am programming both the central and peripheral project. I am using the NRF5 SDK with S140 Softdevice on both sides.

I am trying to speed up the connection procedure as far as possible. Therefore, I bond both devices. I know that characteristics, that are notified on bonded devices, stay notified the next time they connect. It seems to work, since I can skip "ble_nus_c_tx_notif_enable()" for bonded device and still receive value notifications on the TX characteristic. However, the NUS event handler is not called before I call "ble_nus_c_on_db_disc_evt()".

The problem is that characteristic discovery takes to long for my application. Thus, I would like to directly start communicating with bonded devices, without discovery. Is there a way to do that? Do I have to call  ble_nus_c_on_db_disc_evt with the parameters read from the peer manager (e.g. by using pm_peer_data_remote_db_load()).

Thank you and best regards

Bjoern

  • Hi Bjoern

    This has been discussed in length in this thread, even though it is rather old it should still be relevant.  It should be fairly simple, seeing as if you know the handles you can just utilize these directly. It might be that some SDK functions are tied together and make some trouble, but I think you should be fine if you remove the discovery module from your project altogether.

    Best regards,

    Simon

  • Hi Simon,

    thanks for the quick response. This helps a lot. My solution is to store handles, when bonding the devices, and reusing this handles for all later connections. And this actually does speed up the connection process, since I can skip discovery. It doesn't help as much as I hoped it would, though. 

    Currently, I can establish a connection within less than 50 ms after advertising was started on peripheral side. Since I reuse the handles, and both devices are bonded (thus pairing process should also be skipped), I would expect the device to directly be able to communicate via NUS. However, even though I start transmitting value notifications from the peripheral side, as soon as the connection is established, it takes another 100 ms (more or less) until the first notification reaches the central. It seems that the notifications are queued somewhere. Then 100 ms after the connection was established, I receive all notifications, which I did send in the meantime.

    Do you have an idea how to speed that up, or what could cause the initial delay? Min and max connection interval are already at 7.5 ms, so that shouldn't be the problem. After the initial delay, latency from peripheral to central side is constantly below 20 ms. So this problem seems to exist only directly after connecting.

    My aim is to transmit data from peripheral to central side, via NUS value notifications, within 100 ms (counted from start of advertising to the reception of the value notification in the NUS event handler on central side). Do you think that is possible? Currently, I managed to transfer data within 150 ms, so I need a way to save at least another 50 ms, within the connection process.  

    Best regards

    Bjoern

  • Hi

    In order to maximize throughput for your application, I suggest you check out this blog post, which is very thorough on throughput. Please check out that to see if you have missed anything there. Next, I'm not able to say what is causing this delay with the information you've provided. Are you able to capture a sniffer trace so we can see what event causes this delay?

    Best regards,

    Simon

  • Hi, did you forget to add a link to your comment?

    I finally found the problem. I still don't know exactly how to fix this, though. It seems that sending data is blocked by an ongoing ATT_MTU exchange. I attached the trace log from my peripheral device:

     

    <info> app: Fast advertising.<\r><\r><\n>
    <info> app: Advertising started<\r><\r><\n>
    <info> peer_manager_handler: Peer data updated in flash: peer_id: 0, data_id: Peer rank, action: Update, no change<\r><\r><\n>
    <info> app: BLE_NUS_EVT_COMM_STARTED, start sending data<\r><\r><\n>
    <info> app: Data Sent Result = 8<\r><\r><\n>
    <info> app: BLE_GAP_EVT_CONNECTED: min_int: 6 max_int: 6, latency: 0, timeout: 400<\r><\r><\n>
    <info> app: Data Sent Result = 8<\r><\r><\n>
    <info> app: Data Sent Result = 8<\r><\r><\n>
    <info> peer_manager_handler: Connection secured: role: Peripheral, conn_handle: 0, procedure: Encryption<\r><\r><\n>
    <info> peer_manager_handler: Peer data updated in flash: peer_id: 0, data_id: Peer rank, action: Update, no change<\r><\r><\n>
    <info> app: Data Sent Result = 8<\r><\r><\n>
    <info> app: GATT ATT MTU on connection 0x0 changed to 247.<\r><\r><\n>
    <info> app: Data Sent Result = 0<\r><\r><\n>
    <info> app: BLE_NUS_EVT_TX_RDY<\r><\r><\n>
    <info> app: Data Sent Result = 0<\r><\r><\n>
    <info> app: BLE_NUS_EVT_TX_RDY<\r><\r><\n>
    <info> app: Data Sent Result = 0<\r><\r><\n>
    

    What I do, is starting to send data as soon as I receive the BLE_NUS_EVT_COMM_STARTED event from the NUS module. Data is sent in 20 ms Interval.

    I would expect to receive a BLE_NUS_EVT_TX_RDY event right after sending that first data package. However, this event is received more than 100 ms after my first attempt to send data. I also logged the answer I receive from ble_nus_data_send. The function always returns 8, which is "NRF_ERROR_INVALID_STATE", for my firsts attempts.  

    It seems that shortly after receiving the GATT event NRF_BLE_GATT_EVT_ATT_MTU_UPDATED,  ble_nus_data_send returns 0 and data is transferred.

    I looked deeper in the code of ble_nus_data_send and I can say for sure, that the following if statement never evaluates to true. 

        if (!p_client->is_notification_enabled)
        {
            return NRF_ERROR_INVALID_STATE;
        }

    Thus, "return NRF_ERROR_INVALID_STATE" is skipped from the first time, I call the function. Instead, sd_ble_gatts_hvx, which is called at the end of ble_nus_data_send, seems to return the error code 8. I looked to the API reference of sd_ble_gatts_hvx, which may return NRF_ERROR_INVALID_STATE, if "An ATT_MTU exchange is ongoing". 

    To make sure that this really is the problem, I did set NRF_SDH_BLE_GATT_MAX_MTU_SIZE to the default value of 23 on peripheral and central side. Before it was 247. This did speed up the connection process massively. Now ble_nus_data_send directly returns 0 after the characteristic has been notified, and I do not receive "NRF_BLE_GATT_EVT_ATT_MTU_UPDATED" anymore. I can now connect, encrypt and send data from peripheral to host within about 70 to 80 ms. This would satisfy my needs in theory but skipping the MTU update is not really an option, since I want to maximize throughput, which is hard with an MTU size of 23. Is there a way store the MTU size for bonded devices, so that both devices do not need to negotiate the MTU size on each connection?

    Best regards

    Björn 

  • Yes, I did. Very sorry about that. I have updated my previous reply to include the link to the blog post I mentioned now. 

    Is the MTU size set to 247 in both devices by default? You might have to increase the NRF_SDH_BLE_GAP_EVENT_LENGTH for the devices to have enough time to transfer packets with an MTU size of 247, what is this set to in your application?

    Best regards,

    Simon

Related