BLE peripheral with multiple connections

I'm struggling to get a peripheral device to work with two simultaneous connections. I have attached my configuration (for the application) and my connect/disconnect callbacks, with the advertizing data.

  1. I'm advertizingwith BT_LE_ADV_OPT_CONNECTABLE and not with ONE_TIME flag. I understand this should keep adv running until I manually stop it. This is my desired behaviour. Upon the first connection to the device, however, I already get a warning from bt_hci_core   <wrn> bt_hci_core: opcode 0x200a status 0x0d. Where 0x0d means CONNECTION REJECTED DUE TO LIMITED RESOURCES. Note that this is different from CONNECTION LIMIT EXCEEDED (0x09) that I read in other posts. I have the feeling that the controller is still somehow allocating only resources for one single peripheral, despite the BT_MA_CONN=2 configuration. 
    I read in some posts about the CONFIG_BT_CTLR_SDC_PERIPHERAL_COUNT config, which seems to address this, however this should be relevant only in the case where the device is also acting as Central device. I cannot select this config in my application. However, if I check the compiled .config in the hci_ipc application, indeed there I find this configured to 1 and with BT_CENTRAL enabled. I'm now confused on what I should do to get my application running. I don't think I'm expected to modify the hci_ipc sample manually
  2. On a different note, I'm also confused on the purpose of bt_conn_ref() and bt_conn_unref(). They are not always present in the ble samples, and I'm not sure I understand what they are used for (the examples seem to work without them).

Many thanks for the help!

CONFIG_BT=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_MAX_CONN=2
# CONFIG_BT_CTLR_SDC_PERIPHERAL_COUNT=2 # this is not selectable in the application?
CONFIG_BT_USER_DATA_LEN_UPDATE=y
CONFIG_BT_USER_PHY_UPDATE=y
CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=n

static void connected(struct bt_conn *conn, uint8_t code){

    if(code){
        LOG_ERR("Connection failed (code 0x%0x2)", code);
        // bt_conn_unref(conn);
        return;
    }

    conn_count++;
    bt_conn_ref(conn);

    __ASSERT(conn_count < CONFIG_BT_MAX_CONN, "Conn counting error");

    LOG_INF("Connected to Client (code 0x%0x2)", code);

    if(conn_count >= CONFIG_BT_MAX_CONN){
        int err = stop_advertising();
        if(err){
            LOG_ERR("Advertising failed to start (err %d)", err);
        }
    }

    post_event_async(BLE_EVT_CONNECTED);
}

static void disconnected(struct bt_conn *conn, uint8_t code){

    LOG_INF("Disconnected from Client (code 0x%0x2)", code);

    bt_conn_unref(conn);

    conn_count--;

    __ASSERT(conn_count <= CONFIG_BT_MAX_CONN, "Conn counting error");

    int err = start_advertising();
    if(err){
        LOG_ERR("Advertising failed to start (err %d)", err);
    }

    post_event_async(BLE_EVT_DISCONNECTED);
}

BT_CONN_CB_DEFINE(conn_callbacks) = {
	.connected = connected,
	.disconnected = disconnected,
};

static int start_advertising(void){
    struct bt_data ad[] = {
        BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
        BT_DATA_BYTES(BT_DATA_NAME_SHORTENED, CONFIG_BT_DEVICE_NAME),
    };
    return bt_le_adv_start(
        BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE,
            BT_GAP_ADV_FAST_INT_MIN_2,
            BT_GAP_ADV_FAST_INT_MAX_2,
            NULL), // undirected adv
        ad, ARRAY_SIZE(ad), NULL, 0);
}

PS: I'm using NCS 2.7.0 on nrf5340

  • Hi Yaxit,

    For the question regarding bt_conn_ref() and unref(), I recommend giving this thread a read:  Info about bt_conn_ref and bt_conn_unref?

    Onto the topic #1. First, we need to remember that you are using the nRF5340, so the BT Host and Controller each stays on a different application image. The Host resides on the Application Core image, while the Controller resides on the Network Core image.

    You are right in your identifying the two Kconfig that are relevant to changing the number of concurrent connections, CONFIG_BT_MAX_CONN and CONFIG_BT_CTLR_SDC_PERIPHERAL_COUNT.

    CONFIG_BT_MAX_CONN is relevant for both the BT Host and Controller and therefore must be set for both the Application and Network Core image.

    CONFIG_BT_CTLR_SDC_PERIPHERAL_COUNT is only relevant for the BT Controller.
    In particular, it is only relevant for the SoftDevice Controller, Nordic's proprietary BT Controller.
    It must be set for the Network Core image.

    That being said, I see that maybe you are having difficulty setting the configurations for the Network Core image.

    Since you have a child image named "hci_ipc," I believe you are building the image pair using the child and parent solution
    In this setup, the simplest way to add Kconfig to the network core is by creating an overlay file at <project dir>/child_image/hci_ipc.conf.

    Inside that file, you can simply set:

    CONFIG_BT_MAX_CONN=3
    CONFIG_BT_CTLR_SDC_PERIPHERAL_COUNT=2

    or, if you don't need the Central feature,

    CONFIG_BT_CENTRAL=n
    CONFIG_BT_MAX_CONN=2

    Hieu

  • Thanks for the reply. I'm not using parent-child image anymore, as this is marked to be deprecated. I'm using the suggested sysbuild approach. The two images are found in separate folders in my build directory.
    The HCI_IPC image is included thanks to the SB_CONFIG_NETCORE_HCI_IPC=y in my sysbuild.conf file.

    I'm not sure how I can configure the netcore image with sysbuild. The HCI_IPC sample is in the zephyr tree, isn't this different from Nordic's softdevice?

    I tried to make some sense of it from here but I'm more confused than before :D
    docs.nordicsemi.com/.../index.html

  • Yaxit said:
    I'm not using parent-child image anymore, as this is marked to be deprecated. I'm using the suggested sysbuild approach. The two images are found in separate folders in my build directory.

    Interesting that your setup defaulted to use HCI IPC. But no matters, the solution remains the same.

    Yaxit said:
    I'm not sure how I can configure the netcore image with sysbuild. The HCI_IPC sample is in the zephyr tree, isn't this different from Nordic's softdevice?

    The HCI IPC application can work with both the Zephyr Controller and the SoftDevice Controller. While working with NCS, the default controller would be the SoftDevice Controller.

    If you need to be extra sure, you can check the .config file in <build dir>/hci_ipc/zephyr to see if CONFIG_BT_LL_SOFTDEVICE or CONFIG_BT_LL_SW_SPLIT is set. If it's the _SOFTDEVICE config that is set, then the SoftDevice Controller is used.

    Yaxit said:
    I tried to make some sense of it from here but I'm more confused than before :D
    docs.nordicsemi.com/.../index.html

    You got very close. The method is described in this section: Zephyr application Kconfig fragment and devicetree overlay.

    So basically, you create <project dir>/sysbuild/hci_ipc.conf, and put in the configs mentioned in my last reply.

  • Sorry for the long wait.

    Thank you for the clarification, the sysbuild subfolder works as you described. Just a few conclusive questions.

    1. Is there any advantage in using softdevice instead of the open link layer? I assume nordic suggests softdevice for applications developed on nRFConnect?

    2. You seemed surprised that I'm using HCI_IPC core image. Why is that? I've seen there's a few other options like hci_rpmsg. Is there a better option?

    Thank you!

  • Yaxit said:
    1. Is there any advantage in using softdevice instead of the open link layer? I assume nordic suggests softdevice for applications developed on nRFConnect?

    The SoftDevice Controller (SDC) tailored for the nRF products, so they can provide better performance.

    There are also some features, such as multi-protocol support, which the SDC can do, but the Zephyr Controller couldn't.

    Nordic also have qualified the Bluetooth stack of each NCS release with the SDC, so you can refer to our qualification during your product's qualification process.

    We do recommend this controller when working with our product.

    Yaxit said:
    2. You seemed surprised that I'm using HCI_IPC core image. Why is that? I've seen there's a few other options like hci_rpmsg. Is there a better option?

    The ipc_radio image is new to me as well. I haven't really looked into whether there are any significant differences. My surprise comes purely from the fact that the samples are setup to use ipc_radio by default, not hci_ipc.

Related