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

What event to wait for to know when mtu has been successfully negotiated with a central device?

I am trying to detect when mtu has been successfully negotiated through the ble_evt_handler function, which is passed into NRF_SDH_BLE_OBSERVER as shown below:

// Register a handler for BLE events.
NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);

I am currently checking for the event BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST, and associating that with a new mtu being set successfully. I use this event to trigger a message being sent from the nRF52840 to my central device (an Android phone, a Google Pixel 2).

The logic is that whenever the nRF52840 and Android phone connect, they always negotiate an mtu of the largest characteristic value size (512 bytes), and so I don't want the device to transmit anything until after this mtu has been negotiated.

This seems to work most of the time, but sometimes I will get an error on the central side when it tries to reply to the message from the nRf52840 where it will still think that the mtu of the connection is 20 bytes.

This makes me think that the BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST is the wrong event to check for on the device side (even the name seems to imply that it does not really mean that mtu was changed successfully yet, just that there was a request to change it).

My question is, is there any event like "BLE_GATTS_EVT_MTU_CHANGED_SUCCESSFULLY", or something along those lines, where when this event occurs I know for sure that the mtu of the connection has been set successfully for both the device and the central? I tried to look through the events and didn't see anything that looked like this.

Thank you. (And happy holidays)

  • This question is interesting. I am writing a Central GATT client test application and realized that I was not setting the MTU. Since I came across your question I thought I would debug into it for my own education. I have my debug log output, which prints all Nordic events, to help and here is what I found:

    On the *Central* side I have the following debug output. All items with *'Nordic BLE event'* are of interest. The first column is the time, in seconds, since reset.

    When the Central connects (see *BLE_GAP_EVT_CONNECTED*), the Central makes the following calls to the softdevice (S132, v6.1.0):

    sd_ble_gap_conn_param_update(); // interval min:80, max: 160, ... as seen in the log below GAP connection params update request:
    sd_ble_gattc_exchange_mtu_request(); // MTU size: 240, (not logged)

    However, my observation is that I always receive a BLE_GATTC_EVT_EXCHANGE_MTU_RSP event which would be what you are looking for - correct?

         8.185 debug: name: 'periph'
         8.186 debug: ble_gap_scanning::connect:
         8.290 debug: Nordic BLE event: 0x10 BLE_GAP_EVT_CONNECTED
         8.291 debug: GAP connect: h: 0x0000, role: 2, peer:
         8.291 2e:ae:f6:d4:25:c7, peer_id: 0, type: 1 'random static'
         8.291 debug: gap::connect: 0x0000
         8.292 debug: Nordic BLE event: 0x1f BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST
         8.293 debug: GAP connection params update request: h: 0x0000, interval: (80, 160), latency: 0, sup_timeout: 400
         8.691 debug: Nordic BLE event: 0x3a BLE_GATTC_EVT_EXCHANGE_MTU_RSP
         9.691 debug: Nordic BLE event: 0x12 BLE_GAP_EVT_CONN_PARAM_UPDATE
         9.692 debug: GAP connection params update: h: 0x0000, interval: (160, 160), latency: 0, sup_timeout: 400
         9.693 debug: gap::connection_parameter_update: h: 0x0000, interval: (160, 160), latency: 0, sup_timeout: 400

    The GATT server (peripheral) is also a test application on a Nordic nrf52 device (both are nrf52 devices). I'm only working with the softdevice and not the SDK (for the most part).

  • Ah I see. Thank you for the very detailed and educational answer.

Related