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

What is the difference between "data length" and MTU?

I want to use BLE 4.2 Data length extension to stuff more data into one packet. I am looking at the "ble_app_att_mtu_throughput" example and am getting confused because there is both a NRF_BLE_GATT_EVT_ATT_MTU_UPDATED event and a NRF_BLE_GATT_EVT_DATA_LENGTH_UPDATED event.

/**@brief Function for handling events from the GATT library. */
static void gatt_evt_handler(nrf_ble_gatt_t * p_gatt, nrf_ble_gatt_evt_t const * p_evt)
{
    switch (p_evt->evt_id)
    {
        case NRF_BLE_GATT_EVT_ATT_MTU_UPDATED:
        {
            m_mtu_exchanged = true;
            NRF_LOG_INFO("ATT MTU exchange completed. MTU set to %u bytes.",
                         p_evt->params.att_mtu_effective);
        } break;

        case NRF_BLE_GATT_EVT_DATA_LENGTH_UPDATED:
        {
            m_data_length_updated = true;
            NRF_LOG_INFO("Data length updated to %u bytes.", p_evt->params.data_length);
        } break;
    }

    nrf_ble_amts_on_gatt_evt(&m_amts, p_evt);
}

I thought "data length" = MTU - 3. If so, then why are there two event types, and why is there a voided function "nrf_ble_gatt_data_length_set" here? 

void data_len_ext_set(bool status)
{
    m_test_params.data_len_ext_enabled = status;

    uint8_t data_length = status ? (247 + L2CAP_HDR_LEN) : (23 + L2CAP_HDR_LEN);
    (void) nrf_ble_gatt_data_length_set(&m_gatt, BLE_CONN_HANDLE_INVALID, data_length);
}

Especially confusing is this line in amts.c, which suggests data length = MTU - 3

void nrf_ble_amts_on_gatt_evt(nrf_ble_amts_t * p_ctx, nrf_ble_gatt_evt_t const * p_gatt_evt)
{
    if (p_gatt_evt->evt_id == NRF_BLE_GATT_EVT_ATT_MTU_UPDATED)
    {
        p_ctx->max_payload_len =
            p_gatt_evt->params.att_mtu_effective - OPCODE_LENGTH - HANDLE_LENGTH;
    }
}

My current project outputs this. MTU = 140. Does that mean I can assume my data length is 140 - 3  = 137? 

<debug> ble_gatt: Data length updated to 27 on connection 0x0.
<debug> ble_gatt: max_rx_octets: 27
<debug> ble_gatt: max_tx_octets: 27
<debug> ble_gatt: max_rx_time: 328
<debug> ble_gatt: max_tx_time: 328
<info> app: Data length updated to 27 bytes.
<info> app: Bonding...
<info> app: Connection secured: role: 1, conn_handle: 0x0, procedure: 0.
<debug> ble_gatt: ATT MTU updated to 140 bytes on connection 0x0 (response).
<info> app: ATT MTU exchange completed. MTU set to 140 bytes.

SDK 14.0.0

Softdevice S132 5.0.0

Parents
  • Hi Andrew, 

    the ATT MTU is the maximum transmission unit for the the ATT protocol which encapsulated inside the Data Channel PDU and the data length is the the size of the Data Channel PDU, see this illustration. 

    So if the ATT MTU is increased to 140, but the Data length is 27, then the ATT data will be segmented into 27byte chunks. Hence, if you want to fit the entire ATT MTU within the Data Channel PDU(i.e. one BLE data packet), then the Data length must be set higher than the ATT MTU size. 

    From the log output it still appers that the Data length is 27 bytes. 

    What have you set the following macros to in sdk_config?

    NRF_SDH_BLE_GAP_DATA_LENGTH

    NRF_SDH_BLE_GATT_MAX_MTU_SIZE

  • So the "data length" is the lower level number. Wow. What's the point of having an ATT MTU AND a data length? Why not just have a "data length"? 

    This must be why BLE 4.2 has the feature called "Data length extension" 

    My defines are set like this:

    #define NRF_SDH_BLE_GATT_MAX_MTU_SIZE 140
    NRF_SDH_BLE_GAP_DATA_LENGTH is nowhere in my project. Was that introduced in SDK 15.0.0? Since that is not defined, do I change the data length with nrf_ble_gatt_data_length_set()? For some reason, that function has a (void) prepended to it in the example. Why? 
Reply
  • So the "data length" is the lower level number. Wow. What's the point of having an ATT MTU AND a data length? Why not just have a "data length"? 

    This must be why BLE 4.2 has the feature called "Data length extension" 

    My defines are set like this:

    #define NRF_SDH_BLE_GATT_MAX_MTU_SIZE 140
    NRF_SDH_BLE_GAP_DATA_LENGTH is nowhere in my project. Was that introduced in SDK 15.0.0? Since that is not defined, do I change the data length with nrf_ble_gatt_data_length_set()? For some reason, that function has a (void) prepended to it in the example. Why? 
Children
  • This is defined in the BLE v4.2 specification, 

    Which SDK version are you using, SDK v14.2 ? It looks like NRF_SDH_BLE_GAP_DATA_LENGTH was added in SDK v15.0.0. 

    Looking at the ble_app_througput example in SDK v14.2.0  it seems that the data length is set to 247 + L2CAP_HDR_LEN if data_len_ext_enabled is true

    // function seting the data length to be used in connections. 
    void data_len_ext_set(bool status)
    {
        m_test_params.data_len_ext_enabled = status;
    
        uint8_t data_length = status ? (247 + L2CAP_HDR_LEN) : (23 + L2CAP_HDR_LEN);
        (void) nrf_ble_gatt_data_length_set(&m_gatt, BLE_CONN_HANDLE_INVALID, data_length);
    }
    
    // data_len_ext_set is called from main()
    data_len_ext_set(m_test_params.data_len_ext_enabled);
    
    // m_test_params is defined in main.c
    static test_params_t m_test_params =
    {
        .att_mtu                  = NRF_SDH_BLE_GATT_MAX_MTU_SIZE,
        .conn_interval            = CONN_INTERVAL_DEFAULT,
        .data_len_ext_enabled     = true,
        .conn_evt_len_ext_enabled = true,
        // Only symmetric PHYs are supported.
    #if defined(S140)
        .phys.tx_phys             = BLE_GAP_PHY_2MBPS | BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_CODED,
        .phys.rx_phys             = BLE_GAP_PHY_2MBPS | BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_CODED,
    #else
        .phys.tx_phys             = BLE_GAP_PHY_2MBPS | BLE_GAP_PHY_1MBPS,
        .phys.rx_phys             = BLE_GAP_PHY_2MBPS | BLE_GAP_PHY_1MBPS,
    #endif
    };

    I think its a artifact as its been fixed in SDK v15.x.x

    void data_len_set(uint8_t value)
    {
        ret_code_t err_code;
        err_code = nrf_ble_gatt_data_length_set(&m_gatt, BLE_CONN_HANDLE_INVALID, value);
        APP_ERROR_CHECK(err_code);
    
        m_test_params.data_len = value;
    }

  • I am using SDK 14.0.0 with Softdevice S132 5.0.0. 

    I tried using the function data_len_set(DATA_LEN_MAX) right before advertising_start() as demonstrated in the SDK 15.0.0 example, but the call seems to be ignored. My data length remains at 27 no matter where I place data_len_set(DATA_LEN_MAX). 

  • What is DATA_LEN_MAX set to? Does nrf_ble_gatt_data_length_set return a non-zero error code?

  • #define DATA_LEN_MAX 251

    i run APP_ERROR_CHECK on nrf_ble_gatt_data_length_set and it never complains. I'm assuming this means no errors. 

  • Hmm, that is weird. Do you see the data length increasing if you set to a value below NRF_SDH_BLE_GATT_MAX_MTU_SIZE, i.e. 140? If not could you capture a sniffer trace with a BLE protocol analyzer or the nRF Sniffer? It would help to see if a request to increase the data length is sent or not. 

Related