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

NRF52DK - Samsung GATT errors

I am evaluating NRF for a commercial project. I am also new to this BLE business so trying to learn fast.

I am trying to run the supplied BLE UART example on the NRF52DK and connecting to a Samsung Note 4/Android 6.01.

Using S132 I can maintain a connection for only about 30 seconds then I get a GATT 133 Timeout error. This happens if I build the firmware and if I use the pre-compiled hexfile.

***If I use the precompiled hexfile built for S112 I do not get a gatt error and can remain connected for ever.***

I have not yet built firmware using S112 but will get around to it. I am using VGDB which does not allow building for the NRF58232 with S112. VGDB does allow building with S113 but this also produces gatt errors and disconnects.

I have spent a lot of time examaining the differences between the S132 and S112 builds and can find no differences that I understand would explain the difference in behaviour.

A lot, really lot, of net searching has revealed much discussion about this problem but NO solutions. The threads ask a lot of questions, provide a lot of guesses, but no answers. All I can determine is that Android developers screwed up their implementation and don't seem to have fixed it yet. The android forums are alive with this problem too, but no solutions.

From my perspective, unless there is a workaround I can forget a commercial application. It is not acceptable to expect customers to have one of a selected list of phones in order to use a product just because certain phone manufacturers are incapable of meeting their advertised specifications. I am better off finding another way to implement the product functionality.

The alternative is that there is a workaround at the peripheral end. It would seem this is the case since S112 works and S132 does not. Problem is I can't figure out what the difference is. Not enough experience yet. 

Has anyone got an explanation for this problem and a solution?

Parents
  • Well now it is confirmed. Using SES I built the examples ble_app_uart_pca10040_s132 and ble_app_uart_pca10040_s112.

    ble_app_uart_pca10040_s112 works flawlessly with Samsung Note 4/Android 6.01

    ble_app_uart_pca10040_s132 disconnects after 30 seconds with gatt error 133

    Why is this?

  • I know that the application for instance may call sd_ble_gattc_exchange_mtu_request() on BLE_GAP_EVT_CONNECTED event in on_connected_evt() in nrf_ble_gatt.c. I have seen in the past that some peers may not handle this exchange if it’s called early in the connection, can you try to add a nrf_delay_ms(100); before calling sd_ble_gattc_exchange_mtu_request() in on_connected_evt() to see if that affect the issue?

    Something like: 

    static void on_connected_evt(nrf_ble_gatt_t * p_gatt, ble_evt_t const * p_ble_evt)
    {
    …
        nrf_delay_ms(100); // #include "nrf_delay.h"
        err_code = sd_ble_gattc_exchange_mtu_request(conn_handle, p_link->att_mtu_desired);
    …
    }

  • Ok thanks for your reply. It did not work but it did give me a clue.

    In on_connected_evt(....) there are numerous conditional code segments reliant on S112 and S312 not being defined. I modified the conditions to also be reliant on SAMSUNG not being defined then I added a preprocessor define SAMSUNG.

    To my surprise the code compiled, loaded, and ran with NO disconnects. It runs forever.

    I do not see this as a solution, only a kludge, but it is a clue for those much more experienced than I am as to what is going on with the Samsung/Android6 phones (and others I have learnt).

    The uart works when using S112 but throws gatt 133 errors when using S113 or S132.

    Looking through on_connected_evt(....) the only code disabled with S112 but enabled with S113 and S132 is a request to update the data length. Maybe there is problem somewhere in here. I am not experienced enough yet to figure this out.

    This works if I define SAMSUNG

    static void on_connected_evt(nrf_ble_gatt_t * p_gatt, ble_evt_t const * p_ble_evt)
    {
        ret_code_t            err_code;
        uint16_t              conn_handle = p_ble_evt->evt.common_evt.conn_handle;
        nrf_ble_gatt_link_t * p_link      = &p_gatt->links[conn_handle];
    
        // Update the link desired settings to reflect the current global settings.
    #if !defined (S112) && !defined(S312)                                          && !defined (SAMSUNG)
        p_link->data_length_desired = p_gatt->data_length;
    #endif // !defined (S112) && !defined(S312)
    
        switch (p_ble_evt->evt.gap_evt.params.connected.role)
        {
            case BLE_GAP_ROLE_PERIPH:
                p_link->att_mtu_desired = p_gatt->att_mtu_desired_periph;
                break;
    
    #if !defined (S112) && !defined(S312) && !defined(S113)                        && !defined (SAMSUNG)
            case BLE_GAP_ROLE_CENTRAL:
                p_link->att_mtu_desired = p_gatt->att_mtu_desired_central;
                break;
    #endif // !defined (S112) && !defined(S312) && !defined(S113)
    
            default:
                // Ignore.
                break;
        }
    
        // 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));
            }
        }
    
    #if !defined (S112) && !defined(S312) &&                                          !defined (SAMSUNG)
        // Send a data length update request if necessary.
        if (p_link->data_length_desired > p_link->data_length_effective)
        {
            (void) data_length_update(conn_handle, p_link->data_length_desired);
        }
    #endif // !defined (S112) && !defined(S312)
    }
    

    There are lots of posts on forums about this problem and no answers. I hope someone can figure out what is really going wrong.

    +10 minutes

    Just confirmed that MTU change requests are not the problem - I restored the second conditional code segment and the uart runs fine with no gatt disconnects. Only requests to update the data length cause a problem

Reply
  • Ok thanks for your reply. It did not work but it did give me a clue.

    In on_connected_evt(....) there are numerous conditional code segments reliant on S112 and S312 not being defined. I modified the conditions to also be reliant on SAMSUNG not being defined then I added a preprocessor define SAMSUNG.

    To my surprise the code compiled, loaded, and ran with NO disconnects. It runs forever.

    I do not see this as a solution, only a kludge, but it is a clue for those much more experienced than I am as to what is going on with the Samsung/Android6 phones (and others I have learnt).

    The uart works when using S112 but throws gatt 133 errors when using S113 or S132.

    Looking through on_connected_evt(....) the only code disabled with S112 but enabled with S113 and S132 is a request to update the data length. Maybe there is problem somewhere in here. I am not experienced enough yet to figure this out.

    This works if I define SAMSUNG

    static void on_connected_evt(nrf_ble_gatt_t * p_gatt, ble_evt_t const * p_ble_evt)
    {
        ret_code_t            err_code;
        uint16_t              conn_handle = p_ble_evt->evt.common_evt.conn_handle;
        nrf_ble_gatt_link_t * p_link      = &p_gatt->links[conn_handle];
    
        // Update the link desired settings to reflect the current global settings.
    #if !defined (S112) && !defined(S312)                                          && !defined (SAMSUNG)
        p_link->data_length_desired = p_gatt->data_length;
    #endif // !defined (S112) && !defined(S312)
    
        switch (p_ble_evt->evt.gap_evt.params.connected.role)
        {
            case BLE_GAP_ROLE_PERIPH:
                p_link->att_mtu_desired = p_gatt->att_mtu_desired_periph;
                break;
    
    #if !defined (S112) && !defined(S312) && !defined(S113)                        && !defined (SAMSUNG)
            case BLE_GAP_ROLE_CENTRAL:
                p_link->att_mtu_desired = p_gatt->att_mtu_desired_central;
                break;
    #endif // !defined (S112) && !defined(S312) && !defined(S113)
    
            default:
                // Ignore.
                break;
        }
    
        // 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));
            }
        }
    
    #if !defined (S112) && !defined(S312) &&                                          !defined (SAMSUNG)
        // Send a data length update request if necessary.
        if (p_link->data_length_desired > p_link->data_length_effective)
        {
            (void) data_length_update(conn_handle, p_link->data_length_desired);
        }
    #endif // !defined (S112) && !defined(S312)
    }
    

    There are lots of posts on forums about this problem and no answers. I hope someone can figure out what is really going wrong.

    +10 minutes

    Just confirmed that MTU change requests are not the problem - I restored the second conditional code segment and the uart runs fine with no gatt disconnects. Only requests to update the data length cause a problem

Children
  • So it is the data_length_update() that is the problematic one? Then try to add a delay of 100ms before data_length_update()?

    Best regards,
    Kenneth

  • Does not work. Any attempt to update data length results in a disconnect regardless of what length is requested or what time delay I use.

    I have done a lot more reading of this problem now and have found it to be a consequence of an incomplete implementation of ble4.2 on certain phones, including Samsung Notes. Seems that updating data length is an optional feature, so Samsung have elected to produce their $1K product as a toy and ignore the optional part.

    That a disconnect results from requesting an unimplemented feature puts this protocol into the flakey category - certainly not robust. I find this hard to believe. Other than hacking a core component of the sdk, I can find no other way to keep the connection alive. Others have asked if there is a way to determine in software if the phone supports dle update and no answers are forthcoming. Maybe it's not possible.

    How can a professional/commercial product be created if it is not possible for customers to know if it will function with their phones? Even late model phones are having this issue, such as Samsung S7 and there is plenty of discussion about it on forums - but no solutions. I would like to be proven wrong.

  • This is getting confusing. I am awaiting a sniffer and will look at this more closely when I get it.

    Meanwhile, here is a debug output of a connection. In nrf_ble_gatt.c data_length_update(...) I conditionally disabled all of the code and replaced it with a debug message to indicate the code was being ignored.

    The code worked fine and there was no GATT 133 error.

    00> <info> app_timer: RTC: initialized.
    00> <info> app: Debug logging for UART over RTT started.
    00> <debug> nrf_ble_gatt: Requesting to update ATT MTU to 247 bytes on connection 0x0.
    00> <debug> nrf_ble_gatt: Ignoring data length update to 251 on connection 0x0.
    00> <info> app: Connected
    00> <debug> nrf_ble_gatt: ATT MTU updated to 247 bytes on connection 0x0 (response).
    00> <info> app: Data len is set to 0xF4(244)
    00> <debug> app: ATT MTU exchange completed. central 0xF7 peripheral 0xF7
    00> <debug> nrf_ble_gatt: Peer on connection 0x0 requested an ATT MTU of 260 bytes.
    00> <debug> nrf_ble_gatt: Updating ATT MTU to 247 bytes (desired: 247) on connection 0x0.
    00> <info> app: Data len is set to 0xF4(244)
    00> <debug> app: ATT MTU exchange completed. central 0xF7 peripheral 0xF7
    00> <debug> app: Received data from BLE NUS. Writing data on UART.
    00> <debug> app:  68 65 6C 6C 6F         |hello   
    00> <debug> app: Ready to send data over BLE NUS
    00> <debug> app:  68 69 0A               |hi.     
    00> <info> app: Disconnected
    00> <info> app_timer: RTC: initialized.
    00> <info> app: Debug logging for UART over RTT started.
    

    It is clear in the log where the attempt to change the data length would occur. If this is allowed to occur then soon after there is a gatt error and disconnect - every time.

    The mtu is updated without consequence.

    The data length is reported as 244 - happy with that, and mtu-3 as expected.

    So it seems that any attempt to update the data length causes a disconnect - Samsung Note 4/Android 6.01

    ??????

  • I am not sure what workarounds that is possible here, other than in some way control not to execute the data length update. Can you on the disconnect event print out the disconnect reason?

    Should be passed with the BLE_GAP_EVT_DISCONNECT event in p_ble_evt->evt.gap_evt.params.disconnected.reason, I expect reason to be one of the Bluetooth status codes as listed in ble_hci.h.

    I suspect the reason is BLE_HCI_STATUS_CODE_LMP_RESPONSE_TIMEOUT, so it could for instance be possible to re-connect if that error code occurs and then skip the data length update on next connection. Totally understand it's not ideal, but at least you avoid repeatedly disconnect.

    Best regards,
    Kenneth

  • Thanks for your help. I just ran the test and indeed the reason code is 0x22 as you suspected. Your advice for a work-around is sound and would work now that I know what is happening, but it really does not solve the problem or add to my understanding of BLE.

    Time to hit the books and learn about LMP response Timeout Slight smile

Related