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

Reduced throughput

We have a connection between our nRF52832 (server) and a tablet (client). We're trying to transmit some data at a rather high throughput. The connection parameters are as follows:

Connection interval: 60ms

Slave latency: 0

Connection supervision timeout: 1000ms

The data we try to transmit is as follows (in the priority we try to transmit):

Characteristic 1: 20 bytes, 5 packages / s

Characteristic 2: 20 bytes, 2 packages / s

Characteristic 3: 12 bytes, 2 packages / s

This works out to 9 packages / s. With a connection interval of 60ms, I figured we should have a max throughput of 1000ms / 60ms ≈ 16 packages / s. The way we transmit is essential as follows:

// Run once every 5ms
void HandleIndications(void) {
    for (uint8_t i_char = 0; i_char < 3; i_char++) {
        Char* p_char = chars[i_char];
        if(p_char->HasIndication()) {
            ble_gatts_hvx_params_t params;
            params.handle = p_char->Handle();
            params.type = BLE_GATT_HVX_INDICATION);
            params.offset = 0U;
            params.p_len = &len;
            params.p_data = nullptr;  // Use characteristics data buffer
            
            // This will often return 0x08 or 0x11.
            // If so, there will be no HVC event, and p_char->HasIndication()
            // will still return true.
            // Characteristic does not modify its data until it has received
            // IndicationCallback (see HandleHavEvent()).
            sd_ble_gatts_hvx(conn_handle, &params);
            break;
        }
    }
}

// SoftDevice event handler (for HVC)
void HandleHvcEvent(const ble_gatts_evt_hvc_t& hvc) {
    if (p_char->Handle() == hvc.handle) {
        const Codes::Result char_res =
        p_char->IndicationCallback(Codes::Result::kOK);
        if ((f_res == Codes::Result::kOK) &&
            (char_res != Codes::Result::kOK)) {
            f_res = char_res;
        }
    }
    
    // Handle pending indications
    HandleIndications();
}

If we compare the number of HVX's with HVC's they match.

If we compare the number of HVX's with the expected number of transfers only 3/4 of Characteristic 2 are transfered and only 1/3 of Characteristic 3. Due to the prioritisation, they don't transfer equally. Its also confirmed that the data being pushed to the characteristics will fill their internal buffers and data is discarded.

As far as I can tell, the application is responding to the HVC event promptly and there is little delay on the application side to send new HVX requests to the SoftDevice.

Using nRF Connect I have tried changing the connection interval to 7.5ms and then all works as intended. But that is not possible on the tablet (where 60ms is the minimum connection interval).

What are likely culprits in the reduced throughput in this scenario and what steps can be taken to improve the situation?

nRF52832

SoftDevice 132 v3.0.0

No SDK

Parents Reply Children
  • Hi, thanks for the quick reply!

    ATT MTU size is set to 23 bytes.

    DLE is not enabled. This might be completely wrong, but I believe it was once enabled (because we had some characteristics that were >20 bytes), but it caused some issues because the tablet had to make an active read on each indication to receive all bytes.

    Indications are used. We need confirmation that it reached the tablet. Reading the linked post however, I'll consider switching as notifications were acknowledged by the link layer anyway. This post was very helpful in describe the consequences of the notifications vs indications.


    Edit: I wasn't aware of Connection Event Length Extension (and consequently it was not enabled). I will test some with it.

  • obbe said:
    I'll consider switching as notifications were acknowledged by the link layer anyway

    Yes, I think that is the best option if you want to increase the throughput.

Related