nRF5340 LE disconnection Issue.

Hi,

We are using nRF5340 DK and the nRF Connect SDK Version 2.6.1.

We are experiencing an issue with disconnections. We use bt_conn_ref() when receiving the connected event and bt_conn_unref() when receiving the disconnection event.

However, sometimes after a disconnection, when we retry, we encounter the error: "bt_conn: bt_conn_exists_le: Found valid connection (0x20001a18) with address FF:F5:55:5A:D6:6A (random) in disconnected state".

Why does this issue occur even after the disconnection event has been processed?

If we call bt_conn_unref() twice during the disconnection event as shown in the below code (essentially incrementing once upon connection and decrementing twice upon disconnection), the issue does not occur.

void connected(struct bt_conn *conn, uint8_t conn_err){
	bt_conn_ref(conn);
}
void disconnected(struct bt_conn *conn, uint8_t reason){
 	bt_conn_unref(conn);
 	bt_conn_unref(conn);	
}

Could this behavior be due to an internal counter issue?

Parents
  • Hi,

    I'm not aware of any known issues where the Bluetooth host fails to release its own reference. Are you developing a peripheral or central application?

    Thanks,

    Vidar

  • Hi, 

    Thanks for the response.

    We are developing a mesh network. Our requirement is the one device can connect to three other devices. Using one connection as a peripheral and up to two connections as a central for mesh connections.

  • Hi,

    Thanks for the additional information, In your application, are you calling the bt_gatt_exchange_mtu() to initiate the MTU exchange? This should only be called if there was no connection error. 

    Could you post code code snippets to show how your connected and disconnected callbacks are implemented?

    Best regards,

    Vidar

  • Hi 

    Thanks for the response.

    Please find the attached connection make, connected event and disconnected event code portion

    int ConnectToPeripheral(bt_addr_le_t *addr, uint16_t nodeId){
    
    	int err;
    	static struct bt_le_conn_param *param;
    	static struct bt_conn_le_create_param *create_conn_param;
    	bt_addr_le_t *deviceAddr = addr;
    	param = BT_LE_CONN_PARAM_DEFAULT; 
    	param->interval_max = CONN_INTERVAL_MAX;
    	param->interval_min = CONN_INTERVAL_MIN;
    	param->timeout = SUPERVISION_TIMEOUT;
    	create_conn_param = BT_CONN_LE_CREATE_CONN;
    	create_conn_param->timeout = 150;
    
        err = bt_le_scan_stop();
        if (err) {
            LOGT(ERROR,"Stop LE scan failed before connection (err %d)", err);				
        }else{
    		scanActive=false;
    	}
    
    	err = bt_conn_le_create(deviceAddr, create_conn_param, param, &pending_central_conn);
    	return err;
    }
    
    static void connected(struct bt_conn *conn, uint8_t conn_err)
    {
    	struct bt_conn_info info;
    	char ConnectedAddr[BT_ADDR_LE_STR_LEN];
    	int ret=0;
    
    	bt_addr_le_to_str(bt_conn_get_dst(conn), ConnectedAddr, sizeof(ConnectedAddr));
    
    	if (conn_err) {
    		LOGT(ERROR,"Failed to connect to %s (%u)", ConnectedAddr, conn_err);
    		bt_conn_unref(conn);		
    
    		if(!scanActive){			 
            	discovery_State_Manage(SCANNING,FAST);    		
    		}
    		return;
    	}	
    
    	if (info.role == BT_CONN_ROLE_CENTRAL) {		
    		update_le_parame(conn);		
    	}
    
    	if(info.role == BT_CONN_ROLE_PERIPHERAL){
    		bt_conn_ref(conn);
    	}  
    
    }
    
    static void disconnected(struct bt_conn *conn, uint8_t reason)
    {	
    	LOGT(CONN,"####### DISCONNECTED Reason: %d #######",reason);	
    
    	if(conn){          
            bt_conn_unref(conn);
        }
    	
    }
    
    static void update_le_parame(struct bt_conn *conn){
    
    	int err;
    
    	exchange_params.func = exchange_func;
    	err = bt_gatt_exchange_mtu(conn, &exchange_params);
    	if (err) {
    		LOGT(ERROR,"MTU exchange failed (err %d)", err);
    	}	
    
    	err = bt_conn_le_phy_update(conn, conn_phy);
    	if (err) {
    		LOGT(ERROR,"PHY update failed: %d", err);
    	}
    
    }
    
    
    
    

  • Hi,

    Thanks for the code. In the connected callback, it seems that you are using the 'info' variable without initializing it. I would have expected to see a call to the bt_conn_get_info() function to assign the connection information to the variable.

  • Hi,

    Thanks for the response. 

    The bt_conn_get_info() function is I'm already using. It was accidentally removed when I sent you my reply.

    static void connected(struct bt_conn *conn, uint8_t conn_err)
    {
    	struct bt_conn_info info;
    	char ConnectedAddr[BT_ADDR_LE_STR_LEN];
    	int ret=0;
    
    	bt_addr_le_to_str(bt_conn_get_dst(conn), ConnectedAddr, sizeof(ConnectedAddr));
    
    	if (conn_err) {
    		LOGT(ERROR,"Failed to connect to %s (%u)", ConnectedAddr, conn_err);
    		bt_conn_unref(conn);		
    
    		if(!scanActive){			 
            	discovery_State_Manage(SCANNING,FAST);    		
    		}
    		return;
    	}	
    
        bt_conn_get_info(conn, &info);
        
    	if (info.role == BT_CONN_ROLE_CENTRAL) {		
    		update_le_parame(conn);		
    	}
    
    	if(info.role == BT_CONN_ROLE_PERIPHERAL){
    		bt_conn_ref(conn);
    	}  
    
    }
    

  • Hi,

    We encountered another critical disconnection issue during testing with just two devices.

    Device A and device B are both in use. If device B is turned off, device A does not receive any disconnection event, even though device B is no longer on. we have notice that device A still shows device B as connected, even though device B is actually off. I verified this by removing the battery from device B to confirm that it was indeed powered down.

    Could this be happening because a disconnection event is not being sent to the app core from net core?

Reply
  • Hi,

    We encountered another critical disconnection issue during testing with just two devices.

    Device A and device B are both in use. If device B is turned off, device A does not receive any disconnection event, even though device B is no longer on. we have notice that device A still shows device B as connected, even though device B is actually off. I verified this by removing the battery from device B to confirm that it was indeed powered down.

    Could this be happening because a disconnection event is not being sent to the app core from net core?

Children
  • Hi,

    I'm not able to spot any obvious problems in the code snippets you posted. Are you able to provide a minimal version of your project here or in a private that would allow me to reproduce the issue on a nRF5340 DK?

  • Hi,

    We have observed an issue related to the missing disconnection event. We were able to reproduce the issue with nRF5340DK.

    We're currently using an Event Length (EL) of 2.5 ms and the MTU is set to 247 bytes. During a Data Length Extension (DLE) event, with an EL of 2.5 ms, we can send a maximum of 208 bytes within 894 µs in a single packet.

    When we transmit packets smaller than 208 bytes, the issue doesn't occur. However, when the packet size exceeds 208 bytes, the problem happens more frequently. It appears that the issue arises when the link layer splits the packet for transmission.

    Here i have attached the sniffer trace.

    nrf5340DK_disconnection_event_missing.pcapng

  • Hi,

    The sniffer trace shows that the peripheral is not responding to the last write command. Do you have logs from the peripheral device when this happens?

  • Hi,

    On the peripheral side, there is no disconnection event, and we are transmitting from both sides.

    However, after the other device turns off, the peripheral side indicates that the stack buffer is full and is unable to send packets, yet the disconnection event is not detected. The stack buffer size is set to 30. 

    [DISCOVERY]: Discovery Mode Fast Scanning
    [DISCOVERY]: Discovery Mode Fast Advertising
    [CONN]: ####### CONNECTED as PERIPHERAL,  #######
    [CONN]: CONN_COUNT:1, ConnDataIndex:0, conn_handle:99, k_uptime_get_32():59021
    [DISCOVERY]: Discovery Mode Slow Scanning
    [CONN]: LE data len updated: TX (len: 208 time: 894) RX (len: 208 time: 894)
    
    TX[0] BufferFull:1, ConnHandle:99, InIndex:45, OutIndex:35, StackBufferUserd:10
    TX[0] BufferFull:1, ConnHandle:99, InIndex:46, OutIndex:35, StackBufferUserd:11
    TX[0] BufferFull:1, ConnHandle:99, InIndex:47, OutIndex:35, StackBufferUserd:12
    TX[0] BufferFull:1, ConnHandle:99, InIndex:48, OutIndex:35, StackBufferUserd:13
    TX[0] BufferFull:1, ConnHandle:99, InIndex:49, OutIndex:35, StackBufferUserd:14
    TX[0] BufferFull:1, ConnHandle:99, InIndex:50, OutIndex:35, StackBufferUserd:15
    TX[0] BufferFull:1, ConnHandle:99, InIndex:51, OutIndex:35, StackBufferUserd:16
    TX[0] BufferFull:1, ConnHandle:99, InIndex:52, OutIndex:35, StackBufferUserd:17
    TX[0] BufferFull:1, ConnHandle:99, InIndex:53, OutIndex:35, StackBufferUserd:18
    TX[0] BufferFull:1, ConnHandle:99, InIndex:54, OutIndex:35, StackBufferUserd:19
    TX[0] BufferFull:1, ConnHandle:99, InIndex:55, OutIndex:35, StackBufferUserd:20
    TX[0] BufferFull:1, ConnHandle:99, InIndex:56, OutIndex:35, StackBufferUserd:21
    TX[0] BufferFull:1, ConnHandle:99, InIndex:57, OutIndex:35, StackBufferUserd:22
    TX[0] BufferFull:1, ConnHandle:99, InIndex:58, OutIndex:35, StackBufferUserd:23
    TX[0] BufferFull:1, ConnHandle:99, InIndex:59, OutIndex:35, StackBufferUserd:24
    TX[0] BufferFull:1, ConnHandle:99, InIndex:60, OutIndex:35, StackBufferUserd:25
    TX[0] BufferFull:1, ConnHandle:99, InIndex:61, OutIndex:35, StackBufferUserd:26
    TX[0] BufferFull:1, ConnHandle:99, InIndex:62, OutIndex:35, StackBufferUserd:27
    TX[0] BufferFull:1, ConnHandle:99, InIndex:63, OutIndex:35, StackBufferUserd:28
    TX[0] BufferFull:1, ConnHandle:99, InIndex:64, OutIndex:35, StackBufferUserd:29
    TX[0] BufferFull:1, ConnHandle:99, InIndex:65, OutIndex:35, StackBufferUserd:30

  • Hi,

    If you turn off the central device, the peripheral will wait for the supervision timeout timer to expire (was set to 3 seconds the sniffer capture) before it considers the link lost. So, did you wait for the supervision timer to expire? I would also recommend you debug your application to see if any of your threads become blocking/blocked in this scenario.

Related