Connection MTU update fails on ncs v3.2.0

Hello,

I hope you are well.

I have a code inside the connection connected callback that sets the MTU to the maximum, which is working fine on ncs v3.0.2 but generates the following error on v3.2.0:

ASSERTION FAIL [err == 0] @ WEST_TOPDIR/zephyr/subsys/bluetooth/host/hci_core.c:504
        Controller unresponsive, command opcode 0x2022 timeout with err -11

I am using:

static void on_connect(struct bt_conn *p_conn, uint8_t p_err) {
    ...

    struct bt_conn_le_data_len_param data_len = {
        .tx_max_len  = BT_GAP_DATA_LEN_MAX,
        .tx_max_time = BT_GAP_DATA_TIME_MAX,
    };
    if (bt_conn_le_data_len_update(p_conn, &data_len) != 0) {
        LOG_ERR("Data Length update failed");
    }
}

With the configuration:

CONFIG_BT=y
CONFIG_BT_LL_SOFTDEVICE=y
CONFIG_BT_SMP=y
CONFIG_BT_HCI=y
CONFIG_BT_REMOTE_VERSION=n
CONFIG_BT_SETTINGS=n
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_GATT_CLIENT=y
CONFIG_BT_MAX_CONN=1

CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=y
CONFIG_BT_USER_PHY_UPDATE=y
CONFIG_BT_USER_DATA_LEN_UPDATE=y
CONFIG_BT_CTLR_DATA_LENGTH_MAX=251
CONFIG_BT_BUF_ACL_RX_SIZE=251
CONFIG_BT_BUF_ACL_TX_SIZE=251
CONFIG_BT_L2CAP_TX_MTU=247

And can't figure out why the assertion happens on v3.2.0.

  • Hi,

    I am a little bit out of ideas, do you have any example project I can run here to recreate this on a DK? Do calling bt_conn_le_data_len_update() from a deferred work queue work?

    Kenneth

  • Hello Kenneth,

    Thank you for your reply.

    I initialise the BLE peripheral from the main thread and run bt_conn_le_data_len_update() in the connected callback as follows (bt_conn_le_data_len_update() also produces the same error):

    #include <errno.h>
    #include <string.h>
    
    #include <zephyr/kernel.h>
    #include <zephyr/bluetooth/bluetooth.h>
    #include <zephyr/bluetooth/conn.h>
    #include <zephyr/bluetooth/gatt.h>
    #include <zephyr/settings/settings.h>
    
    #include <zephyr/logging/log.h>
    
    #define DEVICE_NAME     "tPeripheral"
    #define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)
    
    static struct bt_conn_cb              conn_callbacks;
    static struct bt_conn   *             conn;
    static uint8_t                        mtu;
    static struct bt_gatt_exchange_params exchange_params;
    
    static const struct bt_le_adv_param *c_adv_param = BT_LE_ADV_PARAM(
        BT_LE_ADV_OPT_CONN | BT_LE_ADV_OPT_ANONYMOUS, BT_GAP_ADV_SLOW_INT_MIN, BT_GAP_ADV_SLOW_INT_MAX, NULL);
    
    static const struct bt_data c_adv_data[] = {
        BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
        BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
    };
    
    static void exchange_func(struct bt_conn *p_conn, uint8_t p_err, struct bt_gatt_exchange_params *p_params) {
        if (p_err) {
            printk("MTU exhange failed, err: 0x%x\n", p_err);
        } else {
            mtu = bt_gatt_get_mtu(p_conn);
            printk("MTU updated, conn: %p, mtu: %u\n", (void *)p_conn, mtu);
        }
    }
    
    static void on_connect(struct bt_conn *p_conn, uint8_t p_err) {
        if (p_err) {
            printk("Connection failed, err: 0x%x\n", p_err);
            return;
        }
    
        if (bt_le_adv_stop() != 0) {
            printk("Advertising stop failed\n");
        }
    
        conn = p_conn;
        mtu  = bt_gatt_get_mtu(p_conn);
    
        printk("Connection, conn: %p, mtu: %u\n", (void *)p_conn, mtu);
    
        const struct bt_conn_le_phy_param preferred_phy = {
            .options     = BT_CONN_LE_PHY_OPT_NONE,
            .pref_rx_phy = BT_GAP_LE_PHY_2M,
            .pref_tx_phy = BT_GAP_LE_PHY_2M,
        };
        if (bt_conn_le_phy_update(conn, &preferred_phy) != 0) {
            printk("PHY update failed\n");
        }
    
        struct bt_conn_le_data_len_param data_len = {
            .tx_max_len  = BT_GAP_DATA_LEN_MAX,
            .tx_max_time = BT_GAP_DATA_TIME_MAX,
        };
        if (bt_conn_le_data_len_update(conn, &data_len) != 0) {
            printk("Data Length update failed\n");
        }
    
        exchange_params.func = exchange_func;
        if (bt_gatt_exchange_mtu(conn, &exchange_params) != 0) {
            printk("MTU update failed\n");
        }
    }
    
    static void on_disconnect(struct bt_conn *p_conn, uint8_t p_reason) {
        printk("Disconnection, conn: %p, reason: 0x%x\n", (void *)p_conn, p_reason);
        conn = NULL;
        mtu  = 23;
    }
    
    static void on_recycled(void) {
        int err = bt_le_adv_start(c_adv_param, c_adv_data, ARRAY_SIZE(c_adv_data), NULL, 0);
        if (err != 0) {
            printk("Advertising start failed %d\n", err);
        }
    }
    
    int main(void) {
        int err;
    
        conn = NULL;
        mtu  = 23;
    
        conn_callbacks.connected    = on_connect;
        conn_callbacks.disconnected = on_disconnect;
        conn_callbacks.recycled     = on_recycled;
    
        err = bt_conn_cb_register(&conn_callbacks);
        if (err != 0) {
            printk("Connection manager: failed to register callbacks %d\n", err);
            return err;
        }
    
        err = bt_enable(NULL);
        if (err != 0) {
            printk("Connection manager: failed to enable bluetooth %d\n", err);
            return err;
        }
    
        if (IS_ENABLED(CONFIG_SETTINGS)) {
            settings_load();
        }
    
        /* err = drv_bles_init(void); my service */
        if (err != 0) {
            printk("Connection manager: failed to Initialize bles driver %d\n", err);
            return err;
        }
    
        err = bt_le_adv_start(c_adv_param, c_adv_data, ARRAY_SIZE(c_adv_data), NULL, 0);
        if (err != 0) {
            printk("Connection manager: failed to start advertising %d\n", err);
            return err;
        }
    
        for (;;) {
            k_sleep(K_MSEC(500));
        }
    
        return 0;
    }
    

    And the error happens when I connect using my custom app or nRF Connect app.

  • Hi,

    I have forwarded internally, due to holidays many key personnel is away, so maybe there will no feedback until beginning of January.

    Something you can try for now is to move the call to bt_conn_le_data_len_update() in a work queue or in main. For instance call k_work_submit() from connected callback.

    Kenneth

Related