This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Multilink Central connection problems : 0x3e (BLE_HCI_CONN_FAILED_TO_BE_ESTABLISHED)

Hi. I'm developing central device for IoT system.

Everything is going well, but there are some problems on connection precedure.

I tried to conenct 7 pheriperal(nRF52832 based customboard), but some devices need much time to establish connections.

When central device try to connect device, the error code "0x3E"(BLE_HCI_CONN_FAILED_TO_BE_ESTABLISHED) is represended repeatably.

Few seconds later(About 6s ~ 30s), connection is finally established.

I want to reduce this error.

how can i do?

  • Hi,

    When trying to establish connection, what is the scan window and interval, and what is the connection interval?

    I suggest to set the scan window=interval=10ms, and the connection interval to for instance 100ms (or longer) if you want to connect several links at the same time.

    Best regards,
    Kenneth

  • /*
     *  Roverdyn BluetoothLE Library
     *
     *  Created on: 2020. 8. 23
     *  Author: Seonguk Jeong
     *  Company : Roverdyn Inc.
     *  Copyright(c) 2020. Roverdyn Inc. all right reserved
     *
     *  Version : 2.0
     *  Last updated : 2020. 9. 10.
     */
    
    #include "BluetoothLE.h"
    // Static member variable 珥덇린�솕
    uint16_t _BLE::h_connection = BLE_CONN_HANDLE_INVALID;
    uint32_t _BLE::err_code = 0;
    uint16_t _BLE::m_ble_nus_max_data_len = 247;
    uint8_t _BLE::device_num = 7;
    bool _BLE::isConnect = false;
    char _BLE::rx_buffer[256] = {0};
    char _BLE::tx_buffer[256] = {0};
    extern void BluetoothLE_Conn_Handler(bool isConnect);
    extern void BluetoothLE_RecvHandler(uint8_t *data, uint16_t length);
    
    static ble_uuid_t const uuids =
    {
        .uuid = BLE_UUID_NUS_SERVICE,
        .type = BLE_UUID_TYPE_VENDOR_BEGIN
    };
    
    void _BLE::initPheriperal(char *dev_name){
    	// App Timer 모듈 초기화
    	err_code = app_timer_init();
    	err_code = sd_power_dcdc_mode_set(NRF_POWER_DCDC_ENABLE);
    	APP_ERROR_CHECK(err_code);
    
        // Softdevice 및 BLE 스택 활성화
    	initBLEStack();
    
        // GAP, GATT 초기화
    	initGAP(dev_name);
    	initGATT(PHERIPERAL);
    
        // Nordic UART Service (NUS) 활성화
    	initService();
    
        // Adertising 모듈 초기화
    	APP_ERROR_CHECK(err_code);
        initAdv();
    
        // 연결 매개변수 초기화
        initConnParams();
        err_code = sd_ble_gap_tx_power_set (BLE_GAP_TX_POWER_ROLE_ADV , h_connection, 4);
        APP_ERROR_CHECK(err_code);
    
        // Advertising 시작
        err_code = ble_advertising_start(&advertising, BLE_ADV_MODE_FAST);
    }
    
    void _BLE::initCentral(){
    	// BLE Central 초기화 함수
    	// Softdevice 및 BLE 스택 활성화
    	SEGGER_RTT_printf(0, "TEST\n");
    	initBLEStack();
    
    	// DCDC 모드 설정
    	err_code = sd_power_dcdc_mode_set(NRF_POWER_DCDC_ENABLE);
    	APP_ERROR_CHECK(err_code);
    
    	// GATT 클라이언트 초기화
    	initGATT(CENTRAL);
    
    	// DB Discovery 모듈 활성화
    	initDiscovery();
    
    	// NUS Central 모듈 초기화
    	initNUSC();
    
    	// BLE connection state
    	ble_conn_state_init();
    
    	// Scan 모듈 초기화
    	initScan();
    
    	err_code = sd_ble_gap_tx_power_set (BLE_GAP_TX_POWER_ROLE_SCAN_INIT  , h_connection, 4);
    	APP_ERROR_CHECK(err_code);
    }
    
    void _BLE::startScan(){
    	ret_code_t ret;
    	ret = nrf_ble_scan_start(&m_scan);
    	APP_ERROR_CHECK(ret);
    }
    
    void _BLE::stopScan(){
    	nrf_ble_scan_stop();
    }
    
    void _BLE::initBLEStack(){
    	// BLE 스택 초기화 함수
        // Softdevice 활성화
        err_code = nrf_sdh_enable_request();
        APP_ERROR_CHECK(err_code);
    
        // BLE 스택 기본 설정
        uint32_t ram_start = 0;
        err_code = nrf_sdh_ble_default_cfg_set(CONN_CFG_TAG, &ram_start);
        APP_ERROR_CHECK(err_code);
    
        // BLE 스택 활성화
        err_code = nrf_sdh_ble_enable(&ram_start);
        APP_ERROR_CHECK(err_code);
    
        // BLE Observer 설정
        NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
    }
    
    void _BLE::initGAP(char *dev_name){
    	// 援ъ“泥� 珥덇린�솕
        ble_gap_conn_params_t gap_conn_params;	// GAP �뿰寃� �뙆�씪誘명꽣
        ble_gap_conn_sec_mode_t sec_mode;		// Security 紐⑤뱶 �꽕�젙
        memset(&gap_conn_params, 0, sizeof(gap_conn_params));
    
        // 蹂댁븞 紐⑤뱶 �꽕�젙(OPEN)
        sec_mode.sm = 1;
        sec_mode.lv = 1;
    
        // Softdevice�뿉 �뵒諛붿씠�뒪 �씠由� Update
        ble_gap_addr_t gap_addr;
        err_code = sd_ble_gap_addr_get(&gap_addr);
        sprintf(dev_name, "%s-%02X%02X", dev_name, gap_addr.addr[1], gap_addr.addr[0]);
        err_code = sd_ble_gap_device_name_set(&sec_mode, (const uint8_t *)dev_name, strlen(dev_name));
    
        // GAP �뿰寃� �뙆�씪誘명꽣 �꽕�젙
        gap_conn_params.min_conn_interval = 8;			// 7.5ms
        gap_conn_params.max_conn_interval = 16;			// 7.5ms
        gap_conn_params.slave_latency     = 0;			// No latency
        gap_conn_params.conn_sup_timeout  = 500;		// 5000ms
    
        // PPCP 파라미터 업데이트
        err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
    }
    
    void _BLE::initGATT(bool mode){
    	 // GATT 서버/클라이어트 초기화
    	err_code = nrf_ble_gatt_init(&gatt, gatt_evt_handler);
    	APP_ERROR_CHECK(err_code);
    
    	 // MTU Size 설정
    	 if(mode){
    		 err_code = nrf_ble_gatt_att_mtu_central_set(&gatt, 247);
    		 APP_ERROR_CHECK(err_code);
    	 }else{
    		 err_code = nrf_ble_gatt_att_mtu_periph_set(&gatt, NRF_SDH_BLE_GATT_MAX_MTU_SIZE);
    		 APP_ERROR_CHECK(err_code);
    	 }
    }
    
    void _BLE::initService(){
    	// Nordic UART 諛� QWR 紐⑤뱢 珥덇린�솕 �븿�닔
    	// 援ъ“泥� �꽑�뼵 諛� 珥덇린�솕
        ble_nus_init_t nus_init;
        nrf_ble_qwr_init_t qwr_init;
        memset(&nus_init, 0, sizeof(nus_init));
        memset(&qwr_init, 0, sizeof(qwr_init));
    
        // QWR紐⑤뱢 �삤瑜� �빖�뱾�윭 吏��젙
        // QWR 紐⑤뱢 珥덇린�솕
        qwr_init.error_handler = nrf_qwr_error_handler;
        err_code = nrf_ble_qwr_init(&qwr, &qwr_init);
    
        // Noridc UART �꽌鍮꾩뒪 珥덇린�솕
        // �뜲�씠�꽣 �빖�뱾�윭 吏��젙
        nus_init.data_handler = nus_data_handler;
        err_code = ble_nus_init(&nus, &nus_init);
    }
    
    void _BLE::initAdv(){
    	// Advertising 珥덇린�솕 �븿�닔
    	// 珥덇린�솕 援ъ“泥� �꽑�뼵
    	static ble_advertising_init_t adv_params;
        memset(&adv_params, 0, sizeof(adv_params));
    
        // Advertising Data Packet �꽕�젙
        int8_t tx_power = 4;
        adv_params.advdata.name_type = BLE_ADVDATA_FULL_NAME;
        adv_params.advdata.include_appearance = false;
        adv_params.advdata.p_tx_power_level = &tx_power;
        adv_params.advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
    
        // Scan Response Data �꽕�젙
        // UUID �꽕�젙
        adv_params.srdata.uuids_complete.uuid_cnt = 1;
        adv_params.srdata.uuids_complete.p_uuids = (ble_uuid_t *)&uuids;
    
        // �뿰寃곗뿉 愿��븳 Advertising �뙆�씪誘명꽣 �꽕�젙
        adv_params.config.ble_adv_fast_enabled = true;
        adv_params.config.ble_adv_fast_interval = 64;
        adv_params.config.ble_adv_fast_timeout = 0;
        adv_params.evt_handler = on_adv_evt;
    
        // Advertising 珥덇린�솕
        err_code = ble_advertising_init(&advertising, &adv_params);
    
        // �뿰寃� �꽕�젙 媛깆떊
        ble_advertising_conn_cfg_tag_set(&advertising, CONN_CFG_TAG);
    }
    
    void _BLE::initNUSC(){
    	// Nordic UART Service Client 초기화
    	ret_code_t       err_code;
    	ble_nus_c_init_t init;
    
    	init.evt_handler   = ble_nus_c_evt_handler;
    	init.error_handler = nus_error_handler;
    	init.p_gatt_queue  = &m_ble_gatt_queue;
    
    	for (uint8_t i = 0; i < NRF_SDH_BLE_CENTRAL_LINK_COUNT; i++){
    		err_code = ble_nus_c_init(&m_nus_c_multi[i], &init);
    		APP_ERROR_CHECK(err_code);
    	}
    }
    
    void _BLE::initScan(){
    	// BLE 스캐닝 모듈 초기화
    	ret_code_t err_code;
    
    	// 스캐닝 구조체
    	nrf_ble_scan_init_t init_scan;
    	memset(&init_scan, 0, sizeof(init_scan));
    
    	// 스캔 모듈 설정
    	init_scan.connect_if_match = true;				// 조건 만족 시 연결 기능 True
    	init_scan.conn_cfg_tag = CONN_CFG_TAG;	// Connection Tag
    
    	// Scan Initialization
    	err_code = nrf_ble_scan_init(&m_scan, &init_scan, scan_evt_handler);
    	APP_ERROR_CHECK(err_code);
    
    	// 필터 설정
    	err_code = nrf_ble_scan_filter_set(&m_scan, SCAN_UUID_FILTER, &uuids);
    	APP_ERROR_CHECK(err_code);
    
    	// 필터 활성화
    	err_code = nrf_ble_scan_filters_enable(&m_scan, NRF_BLE_SCAN_UUID_FILTER, false);
    	APP_ERROR_CHECK(err_code);
    }
    
    void _BLE::initDiscovery(){
    	// Database Discovery 초기화
    	// DB Discovery 구조체 선언
        ble_db_discovery_init_t db_init;
        memset(&db_init, 0, sizeof(ble_db_discovery_init_t));
    
        db_init.evt_handler  = db_disc_handler;
        db_init.p_gatt_queue = &m_ble_gatt_queue;
    
        ret_code_t err_code = ble_db_discovery_init(&db_init);
        APP_ERROR_CHECK(err_code);
    }
    
    void _BLE::initConnParams(){
    	// �뿰寃� �뙆�씪誘명꽣 �꽕�젙 �븿�닔
    	// �뙆�씪誘명꽣 援ъ“泥� �꽑�뼵
        ble_conn_params_init_t cp_init;
        memset(&cp_init, 0, sizeof(cp_init));
    
        // �뿰寃� �뙆�씪誘명꽣 �뜲�씠�꽣 �꽕�젙
        cp_init.p_conn_params = NULL;
        cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY;
        cp_init.next_conn_params_update_delay = NEXT_CONN_PARAMS_UPDATE_DELAY;
        cp_init.max_conn_params_update_count = MAX_CONN_PARAMS_UPDATE_COUNT;
        cp_init.start_on_notify_cccd_handle = BLE_GATT_HANDLE_INVALID;
        cp_init.disconnect_on_fail = false;
        cp_init.evt_handler = on_conn_params_evt;
        cp_init.error_handler = conn_params_error_handler;
    
        // �뿰寃� �뙆�씪誘명꽣 珥덇린�솕
        err_code = ble_conn_params_init(&cp_init);
    }
    
    uint8_t _BLE::getConnCount(){
    	return ble_conn_state_central_conn_count();
    }
    
    void _BLE::nrf_qwr_error_handler(uint32_t nrf_error){
    	// QWR 紐⑤뱢 �삤瑜� �빖�뱾�윭
    	SEGGER_RTT_printf(0, "ERROR! : %d \n", nrf_error);
    }
    
    void _BLE::nus_data_handler(ble_nus_evt_t *p_evt){
    	// Nordic UART 紐⑤뱢 �씠踰ㅽ듃 �빖�뱾�윭
    	char ch[200];
    
        if(p_evt->type == BLE_NUS_EVT_RX_DATA){
        	// BLE로부터 DATA 수신 시
        	uint16_t recv_len = p_evt->params.rx_data.length;
    
        	// �뜲�씠�꽣 �씫湲�
        	for(uint8_t i=0;i<recv_len;i++){
        		rx_buffer[i] = p_evt->params.rx_data.p_data[i];
        	}
        	BluetoothLE_RecvHandler((uint8_t *)rx_buffer, recv_len);
        }
    
        if(p_evt->type == BLE_NUS_EVT_TX_RDY){
        	// �뜲�씠�꽣瑜� 蹂대궪 以�鍮꾧� �릺�뿀�쓣 �븣
    
        }
    }
    
    void _BLE::send(uint8_t *message, uint16_t length, uint8_t deviceNo){
    	// Function for send data to Peripheral devices
    	err_code = ble_nus_data_send(&nus, (uint8_t *)message, &length, h_connection);
    	if ((err_code != NRF_ERROR_INVALID_STATE)
    			&& (err_code != NRF_ERROR_RESOURCES)
    			&& (err_code != NRF_ERROR_NOT_FOUND)){
    		APP_ERROR_CHECK(err_code);
    	}
    }
    
    void _BLE::send_c(uint8_t *message, uint16_t length){
    	for(uint8_t i=0;i<NRF_SDH_BLE_CENTRAL_LINK_COUNT;i++){
    		err_code = ble_nus_c_string_send(&m_nus_c_multi[i], message, length);
    	}
    	APP_ERROR_CHECK(err_code);
    }
    
    void _BLE::on_conn_params_evt(ble_conn_params_evt_t *p_evt){
    	// �뿰寃� �뙆�씪誘명꽣 �씠踰ㅽ듃 �빖�뱾�윭
    	SEGGER_RTT_printf(0, "%d\n", p_evt->evt_type);
        if(p_evt->evt_type == BLE_CONN_PARAMS_EVT_FAILED){
        	err_code = sd_ble_gap_disconnect(h_connection, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);
        }
    }
    
    void _BLE::conn_params_error_handler(uint32_t nrf_error){
    	// Connection Params Error
    }
    
    void _BLE::gatt_evt_handler(nrf_ble_gatt_t *p_gatt, nrf_ble_gatt_evt_t const *p_evt){
    	// GATT �씠踰ㅽ듃 �빖�뱾�윭
        if ((h_connection == p_evt->conn_handle) && (p_evt->evt_id == NRF_BLE_GATT_EVT_ATT_MTU_UPDATED)){
            m_ble_nus_max_data_len = p_evt->params.att_mtu_effective - OPCODE_LENGTH - HANDLE_LENGTH;
        }
    }
    
    void _BLE::on_adv_evt(ble_adv_evt_t ble_adv_evt){
    	// Advertising �씠踰ㅽ듃 �꽕�젙
        switch (ble_adv_evt){
            case BLE_ADV_EVT_FAST:
            	// Fast 紐⑤뱶濡� Advertising �븯怨� �엳�쓣 �븣�쓽 �룞�옉
                break;
            case BLE_ADV_EVT_IDLE:
            	// Idle �긽�깭�씪 �븣
                break;
            default:
                break;
        }
    }
    
    void _BLE::ble_evt_handler(ble_evt_t const *p_ble_evt, void *p_context){
    	// BluetoothLE Event Handler 함수
    	// GAP 이벤트 핸들러
    	ble_gap_evt_t const * p_gap_evt = &p_ble_evt->evt.gap_evt;
    
        switch (p_ble_evt->header.evt_id){
            case BLE_GAP_EVT_CONNECTED:
            	// 연결 되었을 때 이벤트 처리
            	err_code = ble_nus_c_handles_assign(&m_nus_c_multi[p_ble_evt->evt.gap_evt.conn_handle], p_ble_evt->evt.gap_evt.conn_handle, NULL);
            	APP_ERROR_CHECK(err_code);
                //h_connection = p_ble_evt->evt.gap_evt.conn_handle;
                isConnect = true;
                //err_code = nrf_ble_qwr_conn_handle_assign(&qwr, h_connection);
                err_code = ble_db_discovery_start(&m_db_disc, p_ble_evt->evt.gap_evt.conn_handle);
                //err_code = ble_db_discovery_start(&m_db_disc_multi[p_gap_evt->conn_handle], p_ble_evt->evt.gap_evt.conn_handle);
                APP_ERROR_CHECK(err_code);
    
                sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_CONN, p_ble_evt->evt.gap_evt.conn_handle, 4);
    
                //Change MTU
                BluetoothLE_Conn_Handler(true);
                SEGGER_RTT_printf(0, "NUS Connected\n");
                break;
    
            case BLE_GAP_EVT_DISCONNECTED:
            	// 연결 해제 되었을 때 이벤트 처리
                h_connection = BLE_CONN_HANDLE_INVALID;
                isConnect = false;
                BluetoothLE_Conn_Handler(false);
                SEGGER_RTT_printf(0, "NUS Disconnected. Reason : 0x%02X\n", p_gap_evt->params.disconnected.reason);
                if(ble_conn_state_central_conn_count()<device_num){
                	startScan();
                }
                break;
    
            case BLE_GAP_EVT_PHY_UPDATE_REQUEST:
                static ble_gap_phys_t phys;
                SEGGER_RTT_printf(0, "PHY Changed\n");
                phys.rx_phys = BLE_GAP_PHY_1MBPS;
                phys.tx_phys = BLE_GAP_PHY_1MBPS;
                err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys);
                APP_ERROR_CHECK(err_code);
                break;
    
            default:
                break;
        }
    }
    
    void _BLE::db_disc_handler(ble_db_discovery_evt_t * p_evt)
    {
        ble_nus_c_on_db_disc_evt(&m_nus_c_multi[p_evt->conn_handle], p_evt);
    }
    
    
    void _BLE::ble_nus_c_evt_handler(ble_nus_c_t *p_ble_nus_c, ble_nus_c_evt_t const *p_ble_nus_evt){
    	// NUS Client 이벤트 처리기
    	ret_code_t err_code;
    
    	// 이벤트 종류에 따라 처리
    	switch(p_ble_nus_evt->evt_type){
    	case BLE_NUS_C_EVT_DISCOVERY_COMPLETE:
    		SEGGER_RTT_printf(0, "Discovery complete.\n");
    		// 핸들 할당
    		err_code = ble_nus_c_handles_assign(p_ble_nus_c, p_ble_nus_evt->conn_handle, &p_ble_nus_evt->handles);		APP_ERROR_CHECK(err_code);
    		APP_ERROR_CHECK(err_code);
    
    		// 디바이스 개수가 적을 경우 다시 스캔
    		SEGGER_RTT_printf(0, "Connected to device with Nordic UART Service.\n");
    
    		// Notification 활성화
    		err_code = ble_nus_c_tx_notif_enable(p_ble_nus_c);
    		APP_ERROR_CHECK(err_code);
    		break;
    
    	case BLE_NUS_C_EVT_NUS_TX_EVT:
    		BluetoothLE_RecvHandler(p_ble_nus_evt->p_data, p_ble_nus_evt->data_len);
    		break;
    
    	case BLE_NUS_C_EVT_DISCONNECTED:
    		SEGGER_RTT_printf(0, "BLE_NUS_C_EVT_DISCONNECTED.\n");
    		break;
    	}
    }
    
    void _BLE::nus_error_handler(uint32_t nrf_error){
    	SEGGER_RTT_printf(0, "Error Error\n");
    }
    
    void _BLE::scan_evt_handler(scan_evt_t const *p_scan_evt){
        ret_code_t err_code;
    
        switch(p_scan_evt->scan_evt_id)
        {
             case NRF_BLE_SCAN_EVT_CONNECTING_ERROR:
             {
            	 SEGGER_RTT_printf(0, "Connecting Error\n");
                  err_code = p_scan_evt->params.connecting_err.err_code;
             } break;
    
             case NRF_BLE_SCAN_EVT_CONNECTED:
             {
                  ble_gap_evt_connected_t const * p_connected = p_scan_evt->params.connected.p_connected;
                 // Scan is automatically stopped by the connection.
                 SEGGER_RTT_printf(0, "Connecting to target %02x%02x%02x%02x%02x%02x\n",
                          p_connected->peer_addr.addr[0],
                          p_connected->peer_addr.addr[1],
                          p_connected->peer_addr.addr[2],
                          p_connected->peer_addr.addr[3],
                          p_connected->peer_addr.addr[4],
                          p_connected->peer_addr.addr[5]
                          );
                 isConnect = true;
             } break;
    
             case NRF_BLE_SCAN_EVT_SCAN_TIMEOUT:
             {
            	 SEGGER_RTT_printf(0, "Scan timed out.\n");
             } break;
    
             case NRF_BLE_SCAN_EVT_NOT_FOUND:
            	 SEGGER_RTT_printf(0, "Not Found.\n");
            	 break;
             default:
                 break;
        }
    }
    

    This is my source code for central role.

    is it any problems on source?

  • SOLVED!

    As your advice, I add connection paramters and scan paramters.

    Here is new code that can solve the problems.

    // 스캔 파라미터 설정
    	scan_params.interval = 1600;
    	scan_params.window = 320;
    	scan_params.timeout = 500;
    	scan_params.active = true;
    	scan_params.filter_policy = BLE_GAP_SCAN_FP_ACCEPT_ALL;
    
    	// 연결 파라미터 설정
    	conn_params.min_conn_interval = 16;			// 7.5ms
    	conn_params.max_conn_interval = 32;			// 7.5ms
    	conn_params.slave_latency     = 0;			// No latency
    	conn_params.conn_sup_timeout  = 500;		// 5000ms
    
    	init_scan.connect_if_match = true;				// 조건 만족 시 연결 기능 True
    	init_scan.p_scan_param = &scan_params;
    	init_scan.conn_cfg_tag = CONN_CFG_TAG;	// Connection Tag
    	init_scan.p_conn_param = &conn_params;

Related