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

Max MTU for characteristic read not honoured in some cases

Hello, I have an nRF52 device with NRF_SDH_BLE_GATT_MAX_MTU_SIZE set to 512 and it accepts connections and the client sets the max mtu to 512. It is on SDK 15

When

  • an Android based central does a read characteristic, data of 100 or more bytes is returned i.e. working correctly
  • a Linux based central (bluez/pygatt) does the same read only 22 bytes are returned, as if the max mtu change is not recognized

The Linux based central can successfully do reads on the increased mtu size when communicating with a Raspberry Pi based peripheral

I have compared sniffer traces in Wireshark and one difference I see is that the Android app does a GATT Primary Service Declaration whereas the Linux one does not. I have no idea if this is a factor, just a difference that I noticed.

Any ideas on debugging or otherwise are appreciated and please let me know if there is more information I can provide.

Thank you,

Eric

  • Can you share the sniffer trace of the MTU exchanges for the two scenarios? 

  • Hi Haakon, thank you for your response. The response to the MTU request is "not supported" (I overlooked this previously). A screenshot is attached.

  • It has always been the case this is not a Nordic issue per se, but rather getting bluez/pygatt talking to the Nordic and I did make some progress with the MTU by setting it during as part of the initialization, rather than with the exchange MTU - I was able to read a characteristic of greater than 20 bytes. But then I attempted to write more than 20 bytes to a different characteristic but only 20 bytes were received. Any ideas of the top of your head are appreciated but as this is not a Nordic issue please do not spend a lot of time on it.

  • I've seen an issue with an MTU exchange with an android phone not yielding the requested amount when the peripheral GATT server initiated the MTU request instead of letting the Central GATT Client (Android phone) do it. 

    If you're using the GATT library I suggest you comment out the following lines starting at line 150 of nrf_ble_gatt.c in SDK 15:

     // Begin an ATT MTU exchange if necessary.
        if (p_link->att_mtu_desired > p_link->att_mtu_effective)
        {
            NRF_LOG_DEBUG("Requesting to update ATT MTU to %u bytes on connection 0x%x.",
                          p_link->att_mtu_desired, conn_handle);
    
            err_code = sd_ble_gattc_exchange_mtu_request(conn_handle, p_link->att_mtu_desired);
    
            if (err_code == NRF_SUCCESS)
            {
                p_link->att_mtu_exchange_requested = true;
            }
            else if (err_code == NRF_ERROR_BUSY)
            {
                p_link->att_mtu_exchange_pending = true;
                NRF_LOG_DEBUG("sd_ble_gattc_exchange_mtu_request()"
                              " on connection 0x%x returned busy, will retry.", conn_handle);
            }
            else
            {
                NRF_LOG_ERROR("sd_ble_gattc_exchange_mtu_request() returned %s.",
                              nrf_strerror_get(err_code));
            }
        }


    This solved the problem by letting the Central GATT Client issue the MTU request instead. 

    Also note that the code you're removing should be present when using the GATT library for a Client role. You should perhaps encapsulate the snippet in an
    if(p_ble_evt->evt.gap_evt.params.connected.role == BLE_GAP_ROLE_CENTRAL), or just move it into the switch-case above. 

  • Haakon - thank you, that worked!

    It does break the Android app but tomorrow I will try to have the Android app explicitly set the MTU.

    For the record, the mtu sent from the board to the gatttool/bluez is treated as unrecognized and ignored. I think if gatttool accepted that mtu then no other changes would be needed.

    I will work on this a bit more and hopefully be able to close this ticket soon.

Related