Bluetooth connection cache processing

I attempted to use nRF52840 for multi-connection data interaction, but whenever I was debugging, I always encountered the problem of being unable to establish a connection. The return value of bt_conn_le_create was -12.

My communication has the following characteristics:
1. There is a high probability of concurrent operations. Since it involves communication among up to 16 peripherals and each communication session lasts for 1 minute, the central often attempts to connect to multiple devices simultaneously.
2. Because the peripherals use 2M PHY and Coded PHY, they switch PHYs at regular intervals.
3. Device communication is prone to termination. Since the peripherals are battery-powered devices, I had to incorporate timeout interrupt communication mechanisms in both the peripherals and the central, which led to abnormal interruptions in the connection sometimes.
The problems I encountered:
1. Sometimes it is impossible to search for any device. This situation usually occurs during the transition from Coded to 2M phy.
2. Due to some communication abnormalities, the device resources were not properly released, resulting in bt_conn_le_create returning -12.
3. If you have any other suggestions for code optimization, I would appreciate it if you could point them out.
My code has been provided, and the main part of the code is ble_server.c.

To facilitate the troubleshooting, I will briefly summarize the code structure:
1. Lines 0-195
Some structure definitions
2. Lines 196-210
The sending and receiving callbacks of nus
3. Lines 232-326
The relevant functions for device processing (I need a necessary data structure to manage my communication), including adding communication devices, etc..
4. Lines 326-546
!! Some callback functions of the Bluetooth API!!
I think the problem lies in these parts. Especially (connected) and (disconnected)
Lines 5.546 - 1186 I used a priority level of 9 (as far as I know, this priority level is lower than that of Bluetooth). A state machine is used to manage the real-time connection or disconnection of device communication.
And the problematic part here is the _SMF_FUNCTION_HEADER_(connecting_entry) function on line 870.
You can see that I explicitly attempted to shut down BLE and restart it, but it had no effect.

Other documents might also have had an impact.
main.c :
Use a state machine with a priority of 10 as the middleware for communication, to manage connection timeouts and release device model resources (note: these are not communication resources; the model resources and communication resources are bound through the device hardware ID).
2. Use a work queue with a priority level of 9 to implement the thread pool technology and simulate one-to-one device communication.
prj.conf:
Related configuration

ble_server.zip

Parents
  • Hi, 

    1. Sometimes it is impossible to search for any device. This situation usually occurs during the transition from Coded to 2M phy.

    It seems resource exhaustion or stack instability due to improper cleanup after disconnects or failed connections.

    2. Due to some communication abnormalities, the device resources were not properly released, resulting in bt_conn_le_create returning -12.

    bt_conn_le_create returning -12 , which typically maps to -ENOMEM means out of memory/resources. 

    In your disconnect callback, I suggest always calling bt_conn_unref() on the connection object. If you store connection pointers elsewhere, ensure you manage their reference counts correctly. For multilink, you also need to ensure that the CONFIG_BT_MAX_CONN and CONFIG_BT_CTLR_SDC_PERIPHERAL_COUNT are the number of concurrent connections you need, and increase CONFIG_HEAP_MEM_POOL_SIZE accordingly. See my colleague's explanation in this post

    Regards,
    Amanda H.

  • Here are my connection parameters:

    peripherals:

    _API_(int)
    _LIB_NAME_(init)()
    {
        int err;
    
        err = bt_enable(NULL);
        if (err)
        {
            return err;
        }
    
    #if defined(CONFIG_BT_CTLR_PHY_CODED)
    
        struct bt_le_adv_param param =
            BT_LE_ADV_PARAM_INIT(BT_LE_ADV_OPT_CONNECTABLE |
                                     BT_LE_ADV_OPT_EXT_ADV |
                                     BT_LE_ADV_OPT_CODED,
                                 BT_GAP_ADV_FAST_INT_MIN_1,
                                 BT_GAP_ADV_FAST_INT_MAX_1,
                                 NULL);
    
    #elif defined(CONFIG_BT_EXT_ADV)
    
        struct bt_le_adv_param param =
            BT_LE_ADV_PARAM_INIT(BT_LE_ADV_OPT_CONNECTABLE |
                                     BT_LE_ADV_OPT_EXT_ADV,_LIB_NAME_(inst
                                 BT_GAP_ADV_FAST_INT_MIN_1,
                                 BT_GAP_ADV_FAST_INT_MAX_1,
                                 NULL);
    
    #endif
    
        err = bt_le_ext_adv_create(&param, NULL, &_LIB_NAME_(inst).adv);
    
        if (err)
        {
            printk("Failed to create Coded PHY extended advertising set (err %d)\n", err);
            return err;
        }
    
        err = bt_le_ext_adv_set_data(_LIB_NAME_(inst).adv, ad, ARRAY_SIZE(ad), NULL, 0);
        if (err)
        {
            printk("Failed to set extended advertising data (err %d)\n", err);
            return err;
        }
    
        err = bt_le_ext_adv_start(_LIB_NAME_(inst).adv, BT_LE_EXT_ADV_START_DEFAULT);
        if (err)
        {
            printk("Failed to start advertising set (err %d)\n", err);
            return err;
        }
    
        return 0;
    }

    At the same time, after the connection, change the PHY to CODED:

    static void connected(struct bt_conn *conn, uint8_t conn_err)
    {
        int err;
    
        if (conn_err)
        {
            printk("Connection failed, err 0x%02x \n", conn_err);
            _LIB_NAME_(inst).conn = NULL;
            return;
        }
    
    #if defined(CONFIG_BT_CTLR_PHY_CODED)
    
        const struct bt_conn_le_phy_param preferred_phy = {
            .options = BT_CONN_LE_PHY_OPT_CODED_S8,
            .pref_rx_phy = BT_GAP_LE_PHY_CODED,
            .pref_tx_phy = BT_GAP_LE_PHY_CODED,
        };
        err = bt_conn_le_phy_update(conn, &preferred_phy);
        if (err)
        {
            printk("bt_conn_le_phy_update() returned %d", err);
        }
    
    #endif
    
        _LIB_NAME_(inst).conn = conn;
    }
    
    static void disconnected(struct bt_conn *conn, uint8_t reason)
    {
        // if (_LIB_NAME_(inst).config != NULL && _LIB_NAME_(inst).config->callback.connected != NULL)
        // {
        //     _LIB_NAME_(inst).config->callback.connected(false);
        // }
    }

    central:

      #define INTERVAL_MIN 10
    #define INTERVAL_MAX 10
    static struct bt_le_conn_param *conn_param = BT_LE_CONN_PARAM(INTERVAL_MIN, INTERVAL_MAX, 0, 400);
      
      struct bt_conn_le_create_param *conn_create_params = BT_CONN_LE_CREATE_PARAM(
            BT_CONN_LE_OPT_NONE,
            BT_GAP_SCAN_FAST_INTERVAL,
            BT_GAP_SCAN_FAST_WINDOW);
    
        struct bt_le_conn_param *conn_params = BT_LE_CONN_PARAM(
            BT_GAP_INIT_CONN_INT_MIN,
            BT_GAP_INIT_CONN_INT_MAX,
            0,
            100);

Reply
  • Here are my connection parameters:

    peripherals:

    _API_(int)
    _LIB_NAME_(init)()
    {
        int err;
    
        err = bt_enable(NULL);
        if (err)
        {
            return err;
        }
    
    #if defined(CONFIG_BT_CTLR_PHY_CODED)
    
        struct bt_le_adv_param param =
            BT_LE_ADV_PARAM_INIT(BT_LE_ADV_OPT_CONNECTABLE |
                                     BT_LE_ADV_OPT_EXT_ADV |
                                     BT_LE_ADV_OPT_CODED,
                                 BT_GAP_ADV_FAST_INT_MIN_1,
                                 BT_GAP_ADV_FAST_INT_MAX_1,
                                 NULL);
    
    #elif defined(CONFIG_BT_EXT_ADV)
    
        struct bt_le_adv_param param =
            BT_LE_ADV_PARAM_INIT(BT_LE_ADV_OPT_CONNECTABLE |
                                     BT_LE_ADV_OPT_EXT_ADV,_LIB_NAME_(inst
                                 BT_GAP_ADV_FAST_INT_MIN_1,
                                 BT_GAP_ADV_FAST_INT_MAX_1,
                                 NULL);
    
    #endif
    
        err = bt_le_ext_adv_create(&param, NULL, &_LIB_NAME_(inst).adv);
    
        if (err)
        {
            printk("Failed to create Coded PHY extended advertising set (err %d)\n", err);
            return err;
        }
    
        err = bt_le_ext_adv_set_data(_LIB_NAME_(inst).adv, ad, ARRAY_SIZE(ad), NULL, 0);
        if (err)
        {
            printk("Failed to set extended advertising data (err %d)\n", err);
            return err;
        }
    
        err = bt_le_ext_adv_start(_LIB_NAME_(inst).adv, BT_LE_EXT_ADV_START_DEFAULT);
        if (err)
        {
            printk("Failed to start advertising set (err %d)\n", err);
            return err;
        }
    
        return 0;
    }

    At the same time, after the connection, change the PHY to CODED:

    static void connected(struct bt_conn *conn, uint8_t conn_err)
    {
        int err;
    
        if (conn_err)
        {
            printk("Connection failed, err 0x%02x \n", conn_err);
            _LIB_NAME_(inst).conn = NULL;
            return;
        }
    
    #if defined(CONFIG_BT_CTLR_PHY_CODED)
    
        const struct bt_conn_le_phy_param preferred_phy = {
            .options = BT_CONN_LE_PHY_OPT_CODED_S8,
            .pref_rx_phy = BT_GAP_LE_PHY_CODED,
            .pref_tx_phy = BT_GAP_LE_PHY_CODED,
        };
        err = bt_conn_le_phy_update(conn, &preferred_phy);
        if (err)
        {
            printk("bt_conn_le_phy_update() returned %d", err);
        }
    
    #endif
    
        _LIB_NAME_(inst).conn = conn;
    }
    
    static void disconnected(struct bt_conn *conn, uint8_t reason)
    {
        // if (_LIB_NAME_(inst).config != NULL && _LIB_NAME_(inst).config->callback.connected != NULL)
        // {
        //     _LIB_NAME_(inst).config->callback.connected(false);
        // }
    }

    central:

      #define INTERVAL_MIN 10
    #define INTERVAL_MAX 10
    static struct bt_le_conn_param *conn_param = BT_LE_CONN_PARAM(INTERVAL_MIN, INTERVAL_MAX, 0, 400);
      
      struct bt_conn_le_create_param *conn_create_params = BT_CONN_LE_CREATE_PARAM(
            BT_CONN_LE_OPT_NONE,
            BT_GAP_SCAN_FAST_INTERVAL,
            BT_GAP_SCAN_FAST_WINDOW);
    
        struct bt_le_conn_param *conn_params = BT_LE_CONN_PARAM(
            BT_GAP_INIT_CONN_INT_MIN,
            BT_GAP_INIT_CONN_INT_MAX,
            0,
            100);

Children
No Data
Related