Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs

Confused about how to set data length

During my development, I found NRF5 SDK only supports symmetric RX/TX data length settings.

Here is the on_data_length_update_request_evt in nrf_ble_gatt.c file.

static void on_data_length_update_request_evt(nrf_ble_gatt_t * p_gatt, ble_evt_t const * p_ble_evt)
{
ble_gap_evt_t const * p_gap_evt = &p_ble_evt->evt.gap_evt;
nrf_ble_gatt_link_t * p_link = &p_gatt->links[p_gap_evt->conn_handle];

// The SoftDevice only supports symmetric RX/TX data length settings.
uint8_t const data_length_requested =
p_gap_evt->params.data_length_update_request.peer_params.max_tx_octets;

NRF_LOG_DEBUG("Peer on connection 0x%x requested a data length of %u bytes.",
p_gap_evt->conn_handle, data_length_requested);

uint8_t const data_length_effective = MIN(p_link->data_length_desired, data_length_requested);
(void) data_length_update(p_gap_evt->conn_handle, data_length_effective);
}

It clearly indicates SDK only supports symmetric RX/TX data length settings.

When other Bluetooth devices send LL LENGTH RSQ, NRF will only take a minimum value to reply with the same RX TX.

This is also verified in wireshark.

But, I can still manually set an unsymmetric parameter and reply via sd_ble_gap_data_length_update.

case BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST:
{
ble_gap_data_length_params_t params =
{
.max_rx_octets = 251,
.max_tx_octets = 132,
.max_rx_time_us = 2120,
.max_tx_time_us = 2120,
};
err_code = sd_ble_gap_data_length_update(conn_handle,&params,NULL);
APP_ERROR_CHECK(err_code);
}

It also can works and verified in wireshark.

So I'm wondering if it's a wrong behavior that I manually reply the unsymmetric parameters? 

Does it take effect inside the Bluetooth stack? Does the data transfer really follow this unsymmetric parameter?

 Any reply will be appreciated.

Parents
  • Hello,

    I was not able to find anything in the Softdevice documentation confirming this statement. However, I would still recommend setting the RX/TX values the same way as in the GATT module to avoid potential interoperability issues or bugs with other devices.

    Best regards,

    Vidar

  • Hi Vidar,

    Thank you for getting back to me. I’m not completely sure which part of my previous note you were referring to. Could you clarify whether:

    1. you couldn’t find the specific API I mentioned in the SoftDevice documentation, or

    2. you couldn’t find anything that confirms whether a manually supplied asymmetric RX/TX data-length response is actually applied by the stack?

    The challenge I’m facing is that the third-party app I need to support sends an LL-length update with different RX and TX values (e.g. RX = 251 bytes, TX = 27 bytes). If I let the SDK handle the request automatically, it forces both directions down to 27 bytes, its unacceptable.

    Best regards,
    Harry

  • Hi Harry,

    Sorry for the delayed response. The latest nRF5 SDK releases included an option named NRF_BLE_GATT_MTU_EXCHANGE_INITIATION_ENABLED, which allowed you to disable automatic MTU exchange initiation. I'm not sure which SDK version you're using, but could you try not initiating the MTU exchange yourself and instead let the phone handle it to see if that prevents the phone from selecting asymmetric data lengths?

    Best regards,

    Vidar

  • Hi Vidar,

    Thank you for your previous guidance—your suggestions were partially helpful. I’d like to share an observation regarding MTU exchange behavior:

    1. With NRF_BLE_GATT_MTU_EXCHANGE_INITIATION_ENABLED enabled:

      • My device (as a BLE peripheral) actively initiates MTU exchange in the role of GATTC when connecting to both Android and iOS phones.
      • This is unexpected, as I understand the Bluetooth specification requires the central (phone) to act as GATTC and initiate MTU negotiation.
    2. With the option disabled:

      • iOS: The phone (central) correctly initiates MTU exchange as GATTC, and communication works normally.
      • Android: The phone does not initiate MTU exchange, forcing communication at MTU=23. This causes significant data loss. Additionally, the phone sends inconsistent RX/TX length requests.
      • Workaround: Manually triggering "Request MTU" in the nRF Connect app resolves the issue—MTU increases to 247, and RX/TX lengths align at 251.

    Given this, disabling the option isn’t viable due to Android’s failure to initiate MTU exchange. The MTU=23 limitation leads to critical data loss, so I must keep NRF_BLE_GATT_MTU_EXCHANGE_INITIATION_ENABLED enabled for now. However, your insight pinpoints the root issue: the MTU exchange process.

    I appreciate your troubleshooting direction—this clarifies where to focus further efforts. If you have additional suggestions for resolving the non-standard initiation behavior, I’d be grateful for your input.

    Best regards,
    Harry

Reply
  • Hi Vidar,

    Thank you for your previous guidance—your suggestions were partially helpful. I’d like to share an observation regarding MTU exchange behavior:

    1. With NRF_BLE_GATT_MTU_EXCHANGE_INITIATION_ENABLED enabled:

      • My device (as a BLE peripheral) actively initiates MTU exchange in the role of GATTC when connecting to both Android and iOS phones.
      • This is unexpected, as I understand the Bluetooth specification requires the central (phone) to act as GATTC and initiate MTU negotiation.
    2. With the option disabled:

      • iOS: The phone (central) correctly initiates MTU exchange as GATTC, and communication works normally.
      • Android: The phone does not initiate MTU exchange, forcing communication at MTU=23. This causes significant data loss. Additionally, the phone sends inconsistent RX/TX length requests.
      • Workaround: Manually triggering "Request MTU" in the nRF Connect app resolves the issue—MTU increases to 247, and RX/TX lengths align at 251.

    Given this, disabling the option isn’t viable due to Android’s failure to initiate MTU exchange. The MTU=23 limitation leads to critical data loss, so I must keep NRF_BLE_GATT_MTU_EXCHANGE_INITIATION_ENABLED enabled for now. However, your insight pinpoints the root issue: the MTU exchange process.

    I appreciate your troubleshooting direction—this clarifies where to focus further efforts. If you have additional suggestions for resolving the non-standard initiation behavior, I’d be grateful for your input.

    Best regards,
    Harry

Children
  • Hi Harry,

    Thanks for confirming. So it seems to be a timing problem. That is, the particular phone(s) you are testing with don't like that the MTU exchange is initiated immediately from the connection callback. I think a workaround would be if you could delay the MTU initiation. For example, if the phone does not initate the MTU exchange, wait x seconds and call sd_ble_gattc_exchange_mtu_request() in your app.

    The GATT Client role is separate from the GAP central/peripheral roles. A device can act as a GATT Client regardless of whether it's a GAP central or peripheral.

    Best regards,

    Vidar

Related