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.

Parents
  • 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.

Reply
  • 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.

Children
Related