XIAO nRF52840 sense BLE.connected() studk True after disconnect

Hi everyone,

I’ve been troubleshooting a BLE issue with my XIAO nRF52840 sense boards using the ArduinoBLE library, and I’m hoping someone can help me confirm if this is a bug or suggest a workaround. I’ve got a client/server setup where one XIAO nRF52840 sense acts as a central (N33S) and another as a peripheral (N33C). The system works for a few connections, but then the peripheral gets stuck reporting BLE.connected() as true, even after the central disconnects, blocking further reliable cycles.

Setup:
Boards: Two XIAO nRF52840.

Library: ArduinoBLE (version [insert version from Library Manager, e.g., 1.3.6]).

IDE: Arduino IDE 2.3.2 (as of Feb 20, 2025).

Code: Full N33C (peripheral) and N33S (central) sketches below.

What Happens:
N33S connects to N33C, sends “Hello from N33S”, and disconnects successfully for multiple cycles (up to 13+ in one run).

After each disconnect, N33C’s bleDisconnectHandler fires (“Central disconnected”), and it restarts advertising.

However, N33C then reports “Still connected - waiting for disconnect” repeatedly because BLE.connected() stays true, even though N33S has disconnected.

I’ve tried BLE.stopAdvertise()/BLE.advertise() and even BLE.end()/BLE.begin() to reset the stack, but BLE.connected() remains stuck. Oddly, N33S can still connect and send messages despite this state.

This lag between connections (20-30s due to resets) is too slow for my application, which needs faster cycles.

Serial Output (N33C):
Here’s a trimmed log showing the pattern:

Restarted advertising
[… repeated …]
Message received from central: e1:07:2e:f2:f5:cf
Hello from N33S
Central disconnected
Advertising restarted after disconnect
Still connected - waiting for disconnect
[… repeated …]
Connection stuck too long - resetting BLE stack
BLE stack reset and advertising restarted
Still connected - waiting for disconnect
[… repeated …]
Message received from central: e1:07:2e:f2:f5:cf
Hello from N33S
Central disconnected
Advertising restarted after disconnect
Still connected - waiting for disconnect

Full output attached if needed.
Code:
N33C (Peripheral):
cpp

#include <ArduinoBLE.h>

void messageReceived(BLEDevice central, BLECharacteristic characteristic);
void bleDisconnectHandler(BLEDevice central);

BLEService messageService(“19B10000-E8F2-537E-4F6C-D104768A1214”);
BLECharacteristic messageCharacteristic(“19B10001-E8F2-537E-4F6C-D104768A1214”,
BLERead | BLEWrite,
20);

void setup() {
Serial.begin(115200);
if (!BLE.begin()) {
Serial.println(“Starting BLE failed!”);
while (1);
}
BLE.setLocalName(“N33C”);
BLE.setAdvertisedService(messageService);
messageService.addCharacteristic(messageCharacteristic);
BLE.addService(messageService);
messageCharacteristic.setEventHandler(BLEWritten, messageReceived);
BLE.setEventHandler(BLEDisconnected, bleDisconnectHandler);
BLE.setAdvertisingInterval(100);
BLE.advertise();
Serial.println(“BLE Peripheral - N33C ready”);
}

void messageReceived(BLEDevice central, BLECharacteristic characteristic) {
Serial.print("Message received from central: ");
Serial.println(central.address());
uint8_t buffer[20];
int length = messageCharacteristic.valueLength();
messageCharacteristic.readValue(buffer, length);
for (int i = 0; i < length; i++) {
Serial.write(buffer[i]);
}
Serial.println();
}

void bleDisconnectHandler(BLEDevice central) {
Serial.println(“Central disconnected”);
BLE.stopAdvertise();
BLE.advertise();
Serial.println(“Advertising restarted after disconnect”);
}

void loop() {
BLE.poll();
static unsigned long lastCheck = 0;
static unsigned long lastMessage = 0;
static bool wasConnected = false;
if (millis() - lastCheck > 5000) {
if (BLE.connected()) {
if (!wasConnected) {
Serial.println(“Still connected - waiting for disconnect”);
wasConnected = true;
}
} else {
if (wasConnected) {
Serial.println(“Connection cleared”);
wasConnected = false;
}
BLE.stopAdvertise();
BLE.advertise();
Serial.println(“Restarted advertising”);
}
if (lastMessage && (millis() - lastMessage > 60000)) {
Serial.println(“No messages for 60s - resetting BLE stack”);
BLE.end();
delay(1000);
if (!BLE.begin()) {
Serial.println(“BLE restart failed - halting”);
while (1);
}
BLE.setLocalName(“N33C”);
BLE.setAdvertisedService(messageService);
messageService.addCharacteristic(messageCharacteristic);
BLE.addService(messageService);
messageCharacteristic.setEventHandler(BLEWritten, messageReceived);
BLE.setEventHandler(BLEDisconnected, bleDisconnectHandler);
BLE.setAdvertisingInterval(100);
BLE.advertise();
Serial.println(“BLE stack reset and advertising restarted”);
lastMessage = 0;
}
lastCheck = millis();
}
if (messageCharacteristic.written()) {
lastMessage = millis();
}
}

N33S (Central):
cpp

#include <ArduinoBLE.h>

bool connectAndSendMessage();

void setup() {
Serial.begin(115200);
if (!BLE.begin()) {
Serial.println(“Starting BLE failed!”);
while (1);
}
Serial.println(“BLE Central - N33S ready”);
}

bool connectAndSendMessage() {
Serial.println(“Preparing to scan for N33C…”);
delay(2000);
Serial.println(“Scanning for N33C…”);
BLE.stopScan();
BLE.scanForName(“N33C”, true);
BLEDevice peripheral;
unsigned long startTime = millis();
while (!peripheral && (millis() - startTime < 15000)) {
peripheral = BLE.available();
delay(200);
}
if (!peripheral) {
Serial.println(“Failed to find N33C peripheral after 15 seconds”);
BLE.stopScan();
return false;
}
Serial.print("Peripheral address: ");
Serial.println(peripheral.address());
BLE.stopScan();
int connectAttempts = 0;
while (!peripheral.connect() && connectAttempts < 3) {
Serial.println(“Connection attempt failed. Retrying…”);
delay(1000);
connectAttempts++;
}
if (!peripheral.connected()) {
Serial.println(“Failed to connect to N33C after 3 attempts”);
return false;
}
Serial.println(“Connected to N33C”);
if (!peripheral.discoverAttributes()) {
Serial.println(“Attribute discovery failed”);
peripheral.disconnect();
return false;
}
Serial.println(“Attributes discovered”);
BLECharacteristic messageChar = peripheral.characteristic(“19B10001-E8F2-537E-4F6C-D104768A1214”);
if (!messageChar) {
Serial.println(“Failed to find message characteristic”);
peripheral.disconnect();
return false;
}
Serial.println(“Message characteristic found”);
if (!messageChar.canWrite()) {
Serial.println(“Characteristic not writable”);
peripheral.disconnect();
return false;
}
Serial.println(“Characteristic is writable”);
const char* message = “Hello from N33S”;
if (!messageChar.writeValue(message, strlen(message))) {
Serial.println(“Failed to send message”);
peripheral.disconnect();
return false;
}
Serial.println(“Message sent successfully”);
peripheral.disconnect();
unsigned long disconnectStart = millis();
while (peripheral.connected() && (millis() - disconnectStart < 5000)) {
delay(100);
}
if (peripheral.connected()) {
Serial.println(“Warning: Disconnect timed out”);
BLE.stopScan();
} else {
Serial.println(“Disconnected from N33C”);
}
return true;
}

void loop() {
if (connectAndSendMessage()) {
Serial.println(“Communication successful”);
} else {
Serial.println(“Communication failed”);
}
BLE.stopScan();
delay(20000);
}

Questions:
Is this a known bug with BLE.connected() in the ArduinoBLE library on Nano 33 BLE?

Could it be an nRF52840 firmware issue? How can I check the firmware version on my boards?

Any workarounds to ensure reliable disconnects and faster reconnection cycles (my app needs <20s intervals)?

Has anyone else seen this behavior with repeated BLE connect/disconnect cycles?

I’m happy to share more logs or test suggestions. Thanks in advance for any insights—this has been a tough one to crack!

Hi there,

and Welcome here…

So for starts, If you edit your post and just paste your code into the code tags above " </> " it will make it very readable and easy for us to try it and read it.,
No 2 is the " Quotes " often from code from the internet has NON-ansi compatible (they look like upside-down commas) quote marks so if someone try’s a cut and paste job it will be full of errors for each Print statement.

I’ll set this up and Wonder if you have try’d the central ast he PC using the Nordic Dongle ($9) very good for testing multiple connections. :+1:

I give it a go here shortly.

HTH
GL :slight_smile: PJ :v:

So much of the BLE stuff is timing so Lots of smart folks on here to comment. :ok_hand:

Hi there,

SO i’m seeing the same delay in disconnect every 5 - 6 after about 10 successful, I’m using the Peripheral code on the Xiao and the central code I’m emulating on the PC see the picture.(if I connect to the peripheral and disconnect after it does.) after 10 good cycles its fine but the code on the disconnect or the Reset is blocking something?

here you can see it in the serial output as well it thinks it’s still connected, I believe the Peripherals code logic is incorrect for what you want.
What is you goal with this(big picture) you may need a different approach that’s less cyclical.

HTH
GL :slight_smile: PJ :v:

Restarted advertising
Restarted advertising
Still connected - waiting for disconnect
Central disconnected
Advertising restarted after disconnect
Connection cleared
Restarted advertising
Restarted advertising
Central disconnected
Advertising restarted after disconnect
Restarted advertising
Central disconnected
Advertising restarted after disconnect
Restarted advertising
Central disconnected
Advertising restarted after disconnect
Restarted advertising
Restarted advertising
Still connected - waiting for disconnect
Central disconnected
Advertising restarted after disconnect
Central disconnected
Advertising restarted after disconnect
Connection cleared
Restarted advertising
Restarted advertising
Central disconnected
Advertising restarted after disconnect
Restarted advertising
Central disconnected
Advertising restarted after disconnect
Restarted advertising
Central disconnected
Advertising restarted after disconnect
Restarted advertising
Restarted advertising
Still connected - waiting for disconnect
Central disconnected
Advertising restarted after disconnect
Central disconnected
Advertising restarted after disconnect
Connection cleared
Restarted advertising
Central disconnected
Advertising restarted after disconnect
Still connected - waiting for disconnect
Central disconnected
Advertising restarted after disconnect
Central disconnected
Advertising restarted after disconnect
Central disconnected
Advertising restarted after disconnect
Connection cleared
Restarted advertising
Still connected - waiting for disconnect
Central disconnected
Advertising restarted after disconnect
Connection cleared
Restarted advertising
Central disconnected
Advertising restarted after disconnect
Restarted advertising
Central disconnected
Advertising restarted after disconnect
Restarted advertising
Central disconnected
Advertising restarted after disconnect
Restarted advertising
Restarted advertising
Restarted advertising
Restarted advertising

Your Peripheral code Rudux!


#include <Arduino.h>
#include <ArduinoBLE.h>

void messageReceived(BLEDevice central, BLECharacteristic characteristic);
void bleDisconnectHandler(BLEDevice central);

BLEService messageService("19B10000-E8F2-537E-4F6C-D104768A1214");
BLECharacteristic messageCharacteristic("19B10001-E8F2-537E-4F6C-D104768A1214",
                                        BLERead | BLEWrite,
                                        20);

void setup() {
  Serial.begin(9600);
  if (!BLE.begin()) {
    Serial.println("Starting BLE failed!");
    while (1)
      ;
  }
  BLE.setLocalName("N33C");
  BLE.setAdvertisedService(messageService);
  messageService.addCharacteristic(messageCharacteristic);
  BLE.addService(messageService);
  messageCharacteristic.setEventHandler(BLEWritten, messageReceived);
  BLE.setEventHandler(BLEDisconnected, bleDisconnectHandler);
  BLE.setAdvertisingInterval(100);
  BLE.advertise();
  Serial.println("BLE Peripheral - N33C ready");
}

void messageReceived(BLEDevice central, BLECharacteristic characteristic) {
  Serial.print("Message received from central: ");
  Serial.println(central.address());
  uint8_t buffer[20];
  int length = messageCharacteristic.valueLength();
  messageCharacteristic.readValue(buffer, length);
  for (int i = 0; i < length; i++) {
    Serial.write(buffer[i]);
  }
  Serial.println();
}

void bleDisconnectHandler(BLEDevice central) {
  Serial.println("Central disconnected");
  BLE.stopAdvertise();
  BLE.advertise();
  Serial.println("Advertising restarted after disconnect");
}

void loop() {
  BLE.poll();
  static unsigned long lastCheck = 0;
  static unsigned long lastMessage = 0;
  static bool wasConnected = false;
  if (millis() - lastCheck > 5000) {
    if (BLE.connected()) {
      if (!wasConnected) {
        Serial.println("Still connected - waiting for disconnect");
        wasConnected = true;
      }
    } else {
      if (wasConnected) {
        Serial.println("Connection cleared");
        wasConnected = false;
      }
      BLE.stopAdvertise();
      BLE.advertise();
      Serial.println("Restarted advertising");
    }
    if (lastMessage && (millis() - lastMessage > 60000)) {
      Serial.println("No messages for 60s - resetting BLE stack");
      BLE.end();
      delay(1000);
      if (!BLE.begin()) {
        Serial.println("BLE restart failed - halting");
        while (1)
          ;
      }
      BLE.setLocalName("N33C");
      BLE.setAdvertisedService(messageService);
      messageService.addCharacteristic(messageCharacteristic);
      BLE.addService(messageService);
      messageCharacteristic.setEventHandler(BLEWritten, messageReceived);
      BLE.setEventHandler(BLEDisconnected, bleDisconnectHandler);
      BLE.setAdvertisingInterval(100);
      BLE.advertise();
      Serial.println("BLE stack reset and advertising restarted");
      lastMessage = 0;
    }
    lastCheck = millis();
  }
  if (messageCharacteristic.written()) {
    lastMessage = millis();
  }
}

Hi there so here they are side by side, I can do it faster manually , code isn’t optimised at all, I did a reset in the middle.
Why do you scan after the first successful connection to N33C, just connect after disconnect , WAY faster.


the blue is the reset’s in the middle of each peripheral and central to test if it changed , unfortunately not. they do seem to survive a reset and come back. Are you raw/dog-in it or do you have them in a Dev expansion board?

Trying not to LOL at what’s on the IDIOT box tonight! :clown_face:
:rofl: :clown_face: :point_right: :clown_face:

HTH
GL :slight_smile: PJ :v:

Sometimes a simple workaround will suffice. In this case I stopped using the device name and instead switched to the UUID to identify the devices. Not sure why, but this resolved my connection/disconnection problem.

Thanks for your response. Much appreciated.

1 Like