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!