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

iOS 26 Bluetooth disconnect issues

I have discovered a serious issue with Bluetooth connectivity on iOS 26.

My device use nrf52832 and sdk15.3, it consistently disconnects just a few seconds after a successful connection, then automatically reconnects in a continuous loop.

By using a Bluetooth packet sniffer and printing Bluetooth event logs, I found that iOS 26 sends a command to update connection parameters

" Control Opcode: LL_CONNECTION_UPDATE_IND" to Bluetooth slave devices (especially HID devices) every 120ms.

Moreover, the connection parameters it requests are also quite extreme.

The Bluetooth stack of the slave device cannot handle such a high frequency of update requests, ultimately leading to disconnection. Bluetooth stack shows a disconnection error code of 0x28, which corresponds to "Instant Passed."

I will attach my packet sniffer log images. I even suspect this is a very simple and stupid bug—the apple programmer mistakenly placed the Bluetooth parameter update procedure in the Bluetooth central callback event, causing a dead loop. The correct approach should be to request updates by a timer.

Our users are urging me to update the firmware to be compatible with iOS 26 every day. However, after trying some methods, I found that the problem could not be solved at all. Apple support also did not reply to my messages. Now I have no idea how to deal with this problem. Maybe someone in the community has encountered the same problem and solved it?

Parents Reply Children
  • iOS26.pcapng

    Yes,this problem only occurs on iOS 26 and not on Android or earlier iOS versions.

    Also, I copied my log and related code for you to take a look.

    00> <info> app: Connection with link 0x1 established.
    00>
    00> <info> app: periph_link_cnt = 1
    00>
    00> <info> peer_manager_handler: Connection secured: role: Peripheral, conn_handle: 1, procedure: Encryption
    00>
    00> <info> app: Role:PERIPH, Data length set to 251
    00>
    00> <info> app: ATT MTU exchange completed.
    00>
    00> <info> app: Role:PERIPH, MTU set to 247
    00>
    00> <info> app: Conn params UPDATED: min=6, max=6, latency=0, timeout=200
    00>
    00> <info> app: Role:PERIPH, Data length set to 130
    00>
    00> <info> app: Conn params UPDATED: min=12, max=12, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=6, max=6, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=12, max=12, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=6, max=6, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=12, max=12, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=6, max=6, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=12, max=12, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=6, max=6, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=12, max=12, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=6, max=6, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=12, max=12, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=6, max=6, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=12, max=12, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=6, max=6, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=12, max=12, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=6, max=6, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=12, max=12, latency=0, timeout=200
    00>
    00> <info> app: Connection 0x1 has been disconnected. Reason: 0x28
    00>
    00> <info> app: periph_link_cnt = 0

    static void ble_peripheral_evt_handler(ble_evt_t const * p_ble_evt)
    {

    case BLE_GAP_EVT_DISCONNECTED:
    {

    NRF_LOG_INFO("Connection 0x%x has been disconnected. Reason: 0x%X",
    p_gap_evt->conn_handle,
    p_gap_evt->params.disconnected.reason);
    NRF_LOG_INFO("periph_link_cnt = %x", periph_link_cnt);

    }

    case BLE_GAP_EVT_CONN_PARAM_UPDATE:
    {
    ble_gap_evt_t const * p_gap_evt = &p_ble_evt->evt.gap_evt;
    ble_gap_conn_params_t const * cur = &p_gap_evt->params.conn_param_update.conn_params;

    NRF_LOG_INFO("Conn params UPDATED: min=%u, max=%u, latency=%u, timeout=%u",
    cur->min_conn_interval, cur->max_conn_interval,
    cur->slave_latency, cur->conn_sup_timeout);
    }break;

    }

Related