k_sem_take error -11 when I call the bt_le_adv_start() functions.

Hi, I'm developing ble applications.

But there are problems on calling Ble APIs.

If I call the functions that conatins bt_le_adv_start() in main loop(Maybe main thread?), It start advertising well.

But If I call same function on GPIOTE Interrupt handler, I got the "ASSETION FAIL" message like this :

ASSERTION FAIL [err == 0] @ WEST_TOPDIR/zephyr/subsys/bluetooth/host/hci_core.c:430
  Controller unresponsive, command opcode 0x2005 timeout with err -11

The purpose of this interrupt is making button for starting or stopping advertisement of BLE.

If I press the button once, It is starting to advertising and If I press it again, advertising stops.

But I cannot make it because of that error.

Here is my entire code for BLE

BLE configuration structure : 

struct BLE_CONFIG_PERIPHERAL{
    char adv_name[20];
    uint16_t mtu;
    int8_t tx_pwr;
};

BLE Peripheral initialization : 

	static char temp_adv_name[50];
	uint8_t *addr = getAddress();
	sprintf(temp_adv_name, "%s-%02X%02X", config.adv_name, addr[4], addr[5]);
	sd = BT_DATA(BT_DATA_NAME_COMPLETE, (const uint8_t *)temp_adv_name, (uint8_t)strlen(temp_adv_name));
	int32_t err = 0;

	if(IS_ENABLED(CONFIG_BT_NUS_SECURITY_ENABLED)) {
		err = bt_conn_auth_cb_register(&conn_auth_callbacks);
		if (err) {
			printk("Failed to register authorization callbacks.\n");
			return;
		}

		err = bt_conn_auth_info_cb_register(&conn_auth_info_callbacks);
		if (err) {
			printk("Failed to register authorization info callbacks.\n");
			return;
		}
	}

	err = bt_enable(NULL);
	bt_set_name(temp_adv_name);
	k_sem_give(&ble_init_ok);

	// Load settings
	if (IS_ENABLED(CONFIG_SETTINGS)) {
		settings_load();
	}

	err = bt_nus_init(&nus_cb);
	if (err) {
		return;
	}

start advertising fucntion : 

	static struct bt_le_adv_param params;
	params.options = BT_LE_ADV_OPT_CONNECTABLE;
	params.interval_min = 32;
	params.interval_max = 64;
	params.peer = NULL;
	params.options |= BT_LE_ADV_OPT_USE_TX_POWER;
	uint32_t err = bt_le_adv_start(&params, ad, ARRAY_SIZE(ad), &sd, 1);
	if (err) {
		return;
	}else{
		BleEventListener(BLE_EVT_ADV_STARTED);
	}

Why this function can run at void main() functions?

And how can I implement these functions at interrupt functions?

  • Hi!

    Could you post a stripped-down sample that reproduces this ?

  • void main(){
        // Initialize BLE Module
        BLE_CONFIG_PERIPHERAL ble_config = {
                .adv_name = "ARA",
                .mtu = 247,
                .tx_pwr = 4
        };
        ble.Init(ble_config);
        k_sem_give(&test);
        ble.startAdv();
        while(true){
            ...
        }
    }
    
    
    // GPIOTE Interrupt Handler for Adv. Button
    void GPIOTE_IRQHandler(){
            // GPIO Task & Event Event Handler
            static bool isStarted = false;
            if(NRF_GPIOTE->EVENTS_IN[0] == 1){
                    NRF_GPIOTE->EVENTS_IN[0] = 0;
                    if(!isStarted){
                            // Advertising 시작
                            printk("Start Adv\r\n");
                            k_sem_take(&test, K_FOREVER);
                            ble.startAdv();
                            isStarted = true;
                    }else{
                            // Advertising 중단
                            printk("Stop Adv\r\n");
                            ble.stopAdv();
                            isStarted = false;
                    }
            }
    }
    
    void BLE_PERIPHERAL::Init(BLE_CONFIG_PERIPHERAL config){
    	// BluetoothLE initializing functions
    	static char temp_adv_name[50];
    	uint8_t *addr = getAddress();
    	sprintf(temp_adv_name, "%s-%02X%02X", config.adv_name, addr[4], addr[5]);
    	sd = BT_DATA(BT_DATA_NAME_COMPLETE, (const uint8_t *)temp_adv_name, (uint8_t)strlen(temp_adv_name));
    	int32_t err = 0;
    
    	if(IS_ENABLED(CONFIG_BT_NUS_SECURITY_ENABLED)) {
    		err = bt_conn_auth_cb_register(&conn_auth_callbacks);
    		if (err) {
    			printk("Failed to register authorization callbacks.\n");
    			return;
    		}
    
    		err = bt_conn_auth_info_cb_register(&conn_auth_info_callbacks);
    		if (err) {
    			printk("Failed to register authorization info callbacks.\n");
    			return;
    		}
    	}
    
    	err = bt_enable(NULL);
    	bt_set_name(temp_adv_name);
    	k_sem_give(&ble_init_ok);
    
    	// Load settings
    	if (IS_ENABLED(CONFIG_SETTINGS)) {
    		settings_load();
    	}
    
    	err = bt_nus_init(&nus_cb);
    	if (err) {
    		return;
    	}
    }
    
    
    void BLE_PERIPHERAL::startAdv(){
    	// Advertising Start Function
    	static struct bt_le_adv_param params;
    	params.options = BT_LE_ADV_OPT_CONNECTABLE;
    	params.interval_min = 32;
    	params.interval_max = 64;
    	params.peer = NULL;
    	params.options |= BT_LE_ADV_OPT_USE_TX_POWER;
    	uint32_t err = bt_le_adv_start(&params, ad, ARRAY_SIZE(ad), &sd, 1);
    	if (err) {
    		return;
    	}else{
    		BleEventListener(BLE_EVT_ADV_STARTED);
    	}
    }

  • Hi,

    Looks like you are calling k_sem_take(&test, K_FOREVER); in the GPIOTE interrupt handler. The ISR(Interrupt Service Routine) will then wait indefinitely until the semaphore becomes available... but since you are doing this in the ISR, you are blocking other ISR from being handled. ISR must not attempt to wait if the semaphore is unavailable.

Related