NRF52840: NCS 2.5.0 -> NCS 2.7.0 BLE advertising stops on disconnect

I have a custom board that is in production but is running NCS 2.5.0. I am interested in migrating to 2.7.0 however I am running into a few issues. When I pair to the device with our phone app then disconnect, the device stops advertising (See log snippet below). 

[00:03:44.102,996] <inf> ble_module: Disconnected: 53:E2:A3:BA:89:A8 (random) (reason 19)
[00:03:44.103,271] <wrn> bt_hci_core: opcode 0x2005 status 0x0c
[00:03:44.103,271] <wrn> bt_id: cmd disallowed
[00:03:44.103,271] <err> bt_adv: Controller cannot resume connectable advertising (-13)

Long story short, this is a relatively new error message that I tracked to this zephyr commit: Bluetooth: Host: Map HCI cmd disallowed to errno · zephyrproject-rtos/zephyr@76559f2 (github.com)

Here are my BLE related Kconfig options.

# Enable Bluetooth
CONFIG_BT=y
CONFIG_BT_OBSERVER=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_NUS=y
CONFIG_BT_DEVICE_NAME="CTT-NODE"
CONFIG_BT_DEVICE_NAME_DYNAMIC=y
CONFIG_BT_DEVICE_APPEARANCE=833
CONFIG_BT_MAX_CONN=1
CONFIG_BT_MAX_PAIRED=1
CONFIG_BT_RX_STACK_SIZE=4096
CONFIG_NCS_SAMPLE_MCUMGR_BT_OTA_DFU=y
CONFIG_NCS_SAMPLE_MCUMGR_BT_OTA_DFU_SPEEDUP=y

I'm guessing there is something not being configured properly due to the NCS upgrade. Any insights?

  • The disconnect probably is not complete if you do start to advertise in the disconnect callback with CONFIG_BT_MAX_CONN set to 1. This is because you cannot do a connectable advertising while the controller is not fully finished with the disconnect procedure. Which means, you cannot do another connectable advertising while in another connection with max_conn = 1;

    1. Either change CONFIG_BT_MAX_CONN to 2, to allow this overlap of roles or
    2. Create a worker thread to start the advertising after the disconnect callback has exited like below


      static K_WORK_DEFINE(start_advertising_worker, start_advertising_coded);
      
      static void start_advertising_coded(struct k_work *work)
      {
      	int err;
      
      	err = bt_le_ext_adv_start(adv, NULL);
      	if (err) {
      		printk("Failed to start advertising set (err %d)\n", err);
      		return;
      	}
      
      	printk("Advertiser %p set started\n", adv);
      }
      
      static void disconnected(struct bt_conn *conn, uint8_t reason)
      {
      	printk("Disconnected (reason 0x%02x)\n", reason);
      
      	k_work_submit(&start_advertising_worker);
      
      }

    Where disconnected() is the callback for disconnected which is configured as below

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

  • I decided to set CONFIG_BT_MAX_CONN to 2 and it worked as you described. I might try the work approach later, but for now I don't want to deal with any potential race conditions between the disconnection and work.

Related