You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I am a student currently studying Bluetooth Low Energy (BLE), and I have a few questions regarding connection intervals and packet delays in BLE. I'm using Adafruit nrf52832!
Currently, I have implemented a system as follows (code attached below or you can copy in this link: https://forums.adafruit.com/viewtopic.php?t=213925 I uploaded same question). I have connected two clients to a single server. The server contains one service with two characteristics, and each client writes to these characteristics using the "Write without response" method. The server acts as the peripheral, while the clients act as central devices. Each client sends 24 bytes of data, and the connection interval is set to 10ms with an event length of 2ms for both clients.
I observed that the clients are alternately connecting, as shown in the table below, suggesting that the connection intervals do not overlap, and the process takes an average of 10ms + 10ms = 20ms. Additionally, there appears to be a packet delay (up to 40ms) at certain times when sending data.
Moreover, when one of the clients disconnects, the connection interval shortens from 20ms to 10ms.
Is there any way I can configure the system to allow the connection intervals to overlap, as shown in the initial image? Additionally, could you help me understand why packet delays are occurring?
I appreciate some guidance and look forward to response.
void setup()
{
Serial.begin(115200);
while ( !Serial ) delay(10); // for nrf52840 with native usb
Serial.println("Bluefruit52 Central client");
Serial.println("--------------------------------------\n");
// Initialize the Bluefruit module
Serial.println("Initialize the Bluefruit nRF52 module");
uint16_t requestedMtu = dataSize;
Bluefruit.configPrphConn(requestedMtu + 3, 2, BLE_GATTS_HVN_TX_QUEUE_SIZE_DEFAULT, BLE_GATTC_WRITE_CMD_TX_QUEUE_SIZE_DEFAULT); // MTU set to 247 bytes, BLE_GAP_EVENT_LENGTH_DEFAULT = 3
Bluefruit.begin(MAX_PRPH_CONNECTION, 0); // connections as Peripheral = 1, Central = 0 (default), I set 2, 0
Bluefruit.setTxPower(4); // Set transmission power
// Set the connect/disconnect callback handlers
Bluefruit.Periph.setConnInterval(packetTime, packetTime);
Bluefruit.Periph.setConnectCallback(connect_callback);
Bluefruit.Periph.setDisconnectCallback(disconnect_callback);
// Setup Characteristic
Serial.println("Configuring the Heart Rate Monitor Service");
setupHRM();
// Setup Advertising
Serial.println("Setting up the advertising payload(s)");
startAdv();
Serial.println("\nAdvertising");
}
void setupHRM(void)
{
// set up characteristic
hrms.begin();
// Include HRM Service UUID
Bluefruit.Advertising.addService(hrms);
// Include Name
Bluefruit.Advertising.addName();
Bluefruit.Advertising.restartOnDisconnect(true);
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
}
void connect_callback(uint16_t conn_handle)
{
// Get the reference to current connection
BLEConnection* connection = Bluefruit.Connection(conn_handle);
char central_name[32] = { 0 };
connection->getPeerName(central_name, sizeof(central_name));
uint16_t mtu;
mtu = connection->getMtu();
Serial.print("Connected to "); Serial.print(central_name); Serial.print(" with mtu size: "); Serial.print(mtu);
// set maximum connection
connection_count++;
Serial.print("Connection count: ");
Serial.println(connection_count);
// Keep advertising if not reaching max
if (connection_count < MAX_PRPH_CONNECTION){
Serial.println("Keep advertising");
Bluefruit.Advertising.start(0);
}
}
/**
Callback invoked when a connection is dropped
@param conn_handle connection where this event happens
@param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h
*/
void disconnect_callback(uint16_t conn_handle, uint8_t reason)
{
(void) conn_handle;
(void) reason;
// Increase Blink rate to different from PrPh advertising mode
Bluefruit.setConnLedInterval(250);
// Callbacks for Central
Bluefruit.Central.setConnInterval(packetTime, packetTime);
Bluefruit.Central.setConnectCallback(connect_callback);
Bluefruit.Central.setDisconnectCallback(disconnect_callback);
/* Start Central Scanning
Enable auto scan if disconnected
Interval = 160 ms, window = 80 ms
Don't use active scan
Filter only accept HRM service
Start(timeout) with timeout = 0 will scan forever (until connected)
*/
Bluefruit.Scanner.setRxCallback(scan_callback);
Bluefruit.Scanner.restartOnDisconnect(true);
Bluefruit.Scanner.setInterval(160, 80); // in unit of 0.625 ms
Bluefruit.Scanner.filterUuid(hrms.uuid);
Bluefruit.Scanner.useActiveScan(false);
Bluefruit.Scanner.start(0); // // 0 = Don't stop scanning after n seconds
Callback invoked when scanner pick up an advertising data
@param report Structural advertising data /
void scan_callback(ble_gap_evt_adv_report_t report)
{
// Since we configure the scanner with filterUuid()
// Scan callback only invoked for device with hrm service advertised
// Connect to device with HRM service in advertising
Bluefruit.Central.connect(report);
}
/**
Callback invoked when an connection is established
// If HRM is not found, disconnect and return
if ( !hrms.discover(conn_handle) )
{
Serial.println("Found NONE");
// disconnect since we couldn't find HRM service
Bluefruit.disconnect(conn_handle);
return;
}
// Once HRM service is found, we continue to discover its characteristic
Serial.println("Found it");
Serial.print("Discovering characteristic ... ");
if ( !hrmc.discover() )
{
// chr is mandatory, if it is not found (valid), then disconnect
Serial.println("not found !!!");
Serial.println("characteristic is mandatory but not found");
Bluefruit.disconnect(conn_handle);
return;
}
Serial.println("Found it");
// Get the reference to current connection
BLEConnection* connection = Bluefruit.Connection(conn_handle);
connection->requestPHY(BLE_GAP_PHY_2MBPS);
// Request MTU exchange for rx_client
if (connection) {
connection->requestMtuExchange(dataSize + 3); // Request MTU of 247 bytes
}
}
@param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h
*/
void disconnect_callback(uint16_t conn_handle, uint8_t reason)
{
(void) conn_handle;
(void) reason;
// Increase Blink rate to different from PrPh advertising mode
Bluefruit.setConnLedInterval(250);
// Callbacks for Central
Bluefruit.Central.setConnInterval(packetTime, packetTime);
Bluefruit.Central.setConnectCallback(connect_callback);
Bluefruit.Central.setDisconnectCallback(disconnect_callback);
/* Start Central Scanning
Enable auto scan if disconnected
Interval = 160 ms, window = 80 ms
Don't use active scan
Filter only accept HRM service
Start(timeout) with timeout = 0 will scan forever (until connected)
*/
Bluefruit.Scanner.setRxCallback(scan_callback);
Bluefruit.Scanner.restartOnDisconnect(true);
Bluefruit.Scanner.setInterval(160, 80); // in unit of 0.625 ms
Bluefruit.Scanner.filterUuid(hrms.uuid);
Bluefruit.Scanner.useActiveScan(false);
Bluefruit.Scanner.start(0); // // 0 = Don't stop scanning after n seconds
Callback invoked when scanner pick up an advertising data
@param report Structural advertising data /
void scan_callback(ble_gap_evt_adv_report_t report)
{
// Since we configure the scanner with filterUuid()
// Scan callback only invoked for device with hrm service advertised
// Connect to device with HRM service in advertising
Bluefruit.Central.connect(report);
}
/**
Callback invoked when an connection is established
// If HRM is not found, disconnect and return
if ( !hrms.discover(conn_handle) )
{
Serial.println("Found NONE");
// disconnect since we couldn't find HRM service
Bluefruit.disconnect(conn_handle);
return;
}
// Once HRM service is found, we continue to discover its characteristic
Serial.println("Found it");
Serial.print("Discovering characteristic ... ");
if ( !hrmc.discover() )
{
// chr is mandatory, if it is not found (valid), then disconnect
Serial.println("not found !!!");
Serial.println("characteristic is mandatory but not found");
Bluefruit.disconnect(conn_handle);
return;
}
Serial.println("Found it");
// Get the reference to current connection
BLEConnection* connection = Bluefruit.Connection(conn_handle);
connection->requestPHY(BLE_GAP_PHY_2MBPS);
// Request MTU exchange for rx_client
if (connection) {
connection->requestMtuExchange(dataSize + 3); // Request MTU of 247 bytes
}
}
@param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h
*/
void disconnect_callback(uint16_t conn_handle, uint8_t reason)
{
(void) conn_handle;
(void) reason;
Hello!
I am a student currently studying Bluetooth Low Energy (BLE), and I have a few questions regarding connection intervals and packet delays in BLE. I'm using Adafruit nrf52832!
I am curious about whether BLE connection intervals can overlap, as depicted in the image linked below, and I am also seeking clarity on potential packet delays: Link: https://docs.silabs.com/bluetooth/latest/bluetooth-fundamentals-connections/multi-peripheral-topology
Currently, I have implemented a system as follows (code attached below or you can copy in this link: https://forums.adafruit.com/viewtopic.php?t=213925 I uploaded same question). I have connected two clients to a single server. The server contains one service with two characteristics, and each client writes to these characteristics using the "Write without response" method. The server acts as the peripheral, while the clients act as central devices. Each client sends 24 bytes of data, and the connection interval is set to 10ms with an event length of 2ms for both clients.
I observed that the clients are alternately connecting, as shown in the table below, suggesting that the connection intervals do not overlap, and the process takes an average of 10ms + 10ms = 20ms. Additionally, there appears to be a packet delay (up to 40ms) at certain times when sending data.
Moreover, when one of the clients disconnects, the connection interval shortens from 20ms to 10ms.
Is there any way I can configure the system to allow the connection intervals to overlap, as shown in the initial image? Additionally, could you help me understand why packet delays are occurring?
I appreciate some guidance and look forward to response.
Thank you.
#############################################################################
peripheral_server *************************************************************************************
#############################################################################
#include <bluefruit.h>
#include <Adafruit_LittleFS.h>
#include <InternalFileSystem.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#define dataNum 3
#define dataSize dataNum*8 // default: 20, maximum: 224
#define packetTime 8 // * 1.25ms
#define MAX_PRPH_CONNECTION 2
BLEService hrms = BLEService(0x180D);
BLECharacteristic hrmc = BLECharacteristic(UUID16_CHR_HEART_RATE_MEASUREMENT);
BLECharacteristic hrmc_2 = BLECharacteristic(UUID16_CHR_BODY_SENSOR_LOCATION);
double receivedData[dataNum];
double receivedData_2[dataNum];
uint8_t buffer[dataNum * sizeof(double)];
uint8_t buffer_2[dataNum * sizeof(double)];
uint8_t buffersum[2 * dataNum * sizeof(double)];
uint8_t connection_count = 0;
void setup()
{
Serial.begin(115200);
while ( !Serial ) delay(10); // for nrf52840 with native usb
Serial.println("Bluefruit52 Central client");
Serial.println("--------------------------------------\n");
// Initialize the Bluefruit module
Serial.println("Initialize the Bluefruit nRF52 module");
uint16_t requestedMtu = dataSize;
Bluefruit.configPrphConn(requestedMtu + 3, 2, BLE_GATTS_HVN_TX_QUEUE_SIZE_DEFAULT, BLE_GATTC_WRITE_CMD_TX_QUEUE_SIZE_DEFAULT); // MTU set to 247 bytes, BLE_GAP_EVENT_LENGTH_DEFAULT = 3
Bluefruit.begin(MAX_PRPH_CONNECTION, 0); // connections as Peripheral = 1, Central = 0 (default), I set 2, 0
Bluefruit.setTxPower(4); // Set transmission power
// Set the connect/disconnect callback handlers
Bluefruit.Periph.setConnInterval(packetTime, packetTime);
Bluefruit.Periph.setConnectCallback(connect_callback);
Bluefruit.Periph.setDisconnectCallback(disconnect_callback);
// Setup Characteristic
Serial.println("Configuring the Heart Rate Monitor Service");
setupHRM();
// Setup Advertising
Serial.println("Setting up the advertising payload(s)");
startAdv();
Serial.println("\nAdvertising");
}
void setupHRM(void)
{
// set up characteristic
hrms.begin();
// 1
hrmc.setProperties(CHR_PROPS_WRITE_WO_RESP); // CHR_PROPS_WRITE
hrmc.setPermission(SECMODE_OPEN, SECMODE_OPEN); // SECMODE_OPEN or SECMODE_NO_ACCESS
hrmc.setFixedLen(dataSize);
hrmc.setWriteCallback(hrm_write_callback);
hrmc.begin();
// 2
hrmc_2.setProperties(CHR_PROPS_WRITE_WO_RESP); // CHR_PROPS_WRITE
hrmc_2.setPermission(SECMODE_OPEN, SECMODE_OPEN); // SECMODE_OPEN or SECMODE_NO_ACCESS
hrmc_2.setFixedLen(dataSize);
hrmc_2.setWriteCallback(hrm_write_callback_2);
hrmc_2.begin();
}
void startAdv(void)
{
// Advertising packet
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
Bluefruit.Advertising.addTxPower();
// Include HRM Service UUID
Bluefruit.Advertising.addService(hrms);
// Include Name
Bluefruit.Advertising.addName();
Bluefruit.Advertising.restartOnDisconnect(true);
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
}
void connect_callback(uint16_t conn_handle)
{
// Get the reference to current connection
BLEConnection* connection = Bluefruit.Connection(conn_handle);
char central_name[32] = { 0 };
connection->getPeerName(central_name, sizeof(central_name));
uint16_t mtu;
mtu = connection->getMtu();
Serial.print("Connected to "); Serial.print(central_name); Serial.print(" with mtu size: "); Serial.print(mtu);
// increase speed
connection->requestPHY(BLE_GAP_PHY_2MBPS);
// set maximum connection
connection_count++;
Serial.print("Connection count: ");
Serial.println(connection_count);
// Keep advertising if not reaching max
if (connection_count < MAX_PRPH_CONNECTION){
Serial.println("Keep advertising");
Bluefruit.Advertising.start(0);
}
}
/**
*/
void disconnect_callback(uint16_t conn_handle, uint8_t reason)
{
(void) conn_handle;
(void) reason;
Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX);
Serial.println("Advertising!");
connection_count--;
}
/**************************************************************************/
void loop() {
if ( Bluefruit.connected() ) {
updateIMUData();
}
}
void hrm_write_callback(uint16_t conn_handle, BLECharacteristic* chr, uint8_t* data, uint16_t len)
{
if (len == sizeof(double) * dataNum) {
memcpy(receivedData, data, sizeof(receivedData));
} else {
Serial.println("[RX]: wrong data size.");
}
}
void hrm_write_callback_2(uint16_t conn_handle, BLECharacteristic* chr, uint8_t* data, uint16_t len)
{
if (len == sizeof(double) * dataNum) {
memcpy(receivedData_2, data, sizeof(receivedData_2));
Serial.print("Timestamp: "); Serial.print(millis()); Serial.print(" >> ");
Serial.print(" from "); Serial.print(receivedData_2[0]);
Serial.print(" at "); Serial.print(receivedData_2[dataNum-1]);
Serial.println("");
} else {
Serial.println("[RX]: wrong data size.");
}
}
void updateIMUData() {
memcpy(buffer, receivedData, sizeof(buffer));
memcpy(buffer_2, receivedData_2, sizeof(buffer));
}
#############################################################################
central_client_1 *************************************************************************************
#############################################################################
#include <bluefruit.h>
#include <Adafruit_LittleFS.h>
#include <InternalFileSystem.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#define dataNum 3 // include timestampe
#define dataSize dataNum*8 // default: 20, maximum: 224
#define packetTime 8 // unit: 1.25ms
#define BNO055_SAMPLERATE_DELAY_MS (10) // unit: ms
BLEClientService hrms(0x180D);
BLEClientCharacteristic hrmc(UUID16_CHR_HEART_RATE_MEASUREMENT);
void setup()
{
Serial.begin(115200);
while ( !Serial ) delay(10); // for nrf52840 with native usb
Serial.println("Bluefruit52 Peripheral Server");
Serial.println("--------------------------------------\n");
Serial.println("Initialize the Bluefruit nRF52 module");
// Change MTU size
uint16_t requestedMtu = dataSize;
Bluefruit.configCentralConn(requestedMtu + 3, 2, BLE_GATTS_HVN_TX_QUEUE_SIZE_DEFAULT, BLE_GATTC_WRITE_CMD_TX_QUEUE_SIZE_DEFAULT); // BLE_GAP_EVENT_LENGTH_DEFAULT = 3
Bluefruit.begin(0, 1); // maximum connections as Peripheral = 0, Central = 1
Bluefruit.setTxPower(4);
Bluefruit.setName("Bluefruit52 Central");
// Initialize HRM client
hrms.begin();
hrmc.begin();
// Increase Blink rate to different from PrPh advertising mode
Bluefruit.setConnLedInterval(250);
// Callbacks for Central
Bluefruit.Central.setConnInterval(packetTime, packetTime);
Bluefruit.Central.setConnectCallback(connect_callback);
Bluefruit.Central.setDisconnectCallback(disconnect_callback);
/* Start Central Scanning
*/
Bluefruit.Scanner.setRxCallback(scan_callback);
Bluefruit.Scanner.restartOnDisconnect(true);
Bluefruit.Scanner.setInterval(160, 80); // in unit of 0.625 ms
Bluefruit.Scanner.filterUuid(hrms.uuid);
Bluefruit.Scanner.useActiveScan(false);
Bluefruit.Scanner.start(0); // // 0 = Don't stop scanning after n seconds
Serial.println("CLEARDATA");
Serial.println("LABEL,NAME,TIME");
}
/**************************************************************************/
void loop() {
double imuData[dataNum] = {1, 1, static_cast(millis())}; // data
if ( Bluefruit.connected() ) {
hrmc.write((uint8_t*)imuData, sizeof(imuData));
}
Serial.print("DATA,");
Serial.print(imuData[dataNum-3]);
Serial.print(",");
Serial.println(imuData[dataNum-1]);
}
/callback**/
/**
/
void scan_callback(ble_gap_evt_adv_report_t report)
{
// Since we configure the scanner with filterUuid()
// Scan callback only invoked for device with hrm service advertised
// Connect to device with HRM service in advertising
Bluefruit.Central.connect(report);
}
/**
*/
void connect_callback(uint16_t conn_handle)
{
Serial.println("Connected");
Serial.print("Discovering Service ... ");
// If HRM is not found, disconnect and return
if ( !hrms.discover(conn_handle) )
{
Serial.println("Found NONE");
}
// Once HRM service is found, we continue to discover its characteristic
Serial.println("Found it");
Serial.print("Discovering characteristic ... ");
if ( !hrmc.discover() )
{
// chr is mandatory, if it is not found (valid), then disconnect
Serial.println("not found !!!");
Serial.println("characteristic is mandatory but not found");
Bluefruit.disconnect(conn_handle);
return;
}
Serial.println("Found it");
// Get the reference to current connection
BLEConnection* connection = Bluefruit.Connection(conn_handle);
connection->requestPHY(BLE_GAP_PHY_2MBPS);
// Request MTU exchange for rx_client
if (connection) {
connection->requestMtuExchange(dataSize + 3); // Request MTU of 247 bytes
}
}
/**
*/
void disconnect_callback(uint16_t conn_handle, uint8_t reason)
{
(void) conn_handle;
(void) reason;
Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX);
}
#############################################################################
central_client_2 *************************************************************************************
#############################################################################
#include <bluefruit.h>
#include <Adafruit_LittleFS.h>
#include <InternalFileSystem.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#define dataNum 3 // include timestampe
#define dataSize dataNum*8 // default: 20, maximum: 224
#define packetTime 8 // unit: 1.25ms
#define BNO055_SAMPLERATE_DELAY_MS (10) // unit: ms
BLEClientService hrms(0x180D);
BLEClientCharacteristic hrmc(UUID16_CHR_BODY_SENSOR_LOCATION);
void setup()
{
Serial.begin(115200);
while ( !Serial ) delay(10); // for nrf52840 with native usb
Serial.println("Bluefruit52 Peripheral Server");
Serial.println("--------------------------------------\n");
Serial.println("Initialize the Bluefruit nRF52 module");
// Change MTU size
uint16_t requestedMtu = dataSize;
Bluefruit.configCentralConn(requestedMtu + 3, 1, BLE_GATTS_HVN_TX_QUEUE_SIZE_DEFAULT, BLE_GATTC_WRITE_CMD_TX_QUEUE_SIZE_DEFAULT); // BLE_GAP_EVENT_LENGTH_DEFAULT = 3
Bluefruit.begin(0, 1); // maximum connections as Peripheral = 0, Central = 1
Bluefruit.setTxPower(4);
Bluefruit.setName("Bluefruit52 Central");
// Initialize HRM client
hrms.begin();
hrmc.begin();
// Increase Blink rate to different from PrPh advertising mode
Bluefruit.setConnLedInterval(250);
// Callbacks for Central
Bluefruit.Central.setConnInterval(packetTime, packetTime);
Bluefruit.Central.setConnectCallback(connect_callback);
Bluefruit.Central.setDisconnectCallback(disconnect_callback);
/* Start Central Scanning
*/
Bluefruit.Scanner.setRxCallback(scan_callback);
Bluefruit.Scanner.restartOnDisconnect(true);
Bluefruit.Scanner.setInterval(160, 80); // in unit of 0.625 ms
Bluefruit.Scanner.filterUuid(hrms.uuid);
Bluefruit.Scanner.useActiveScan(false);
Bluefruit.Scanner.start(0); // // 0 = Don't stop scanning after n seconds
Serial.println("CLEARDATA");
Serial.println("LABEL,NAME,TIME");
}
/**************************************************************************/
void loop() {
double imuData[dataNum] = {2, 2, static_cast(millis())}; // data
if ( Bluefruit.connected() ) {
hrmc.write((uint8_t*)imuData, sizeof(imuData));
}
Serial.print("DATA,");
Serial.print(imuData[dataNum-3]);
Serial.print(",");
Serial.println(imuData[dataNum-1]);
}
/callback**/
/**
/
void scan_callback(ble_gap_evt_adv_report_t report)
{
// Since we configure the scanner with filterUuid()
// Scan callback only invoked for device with hrm service advertised
// Connect to device with HRM service in advertising
Bluefruit.Central.connect(report);
}
/**
*/
void connect_callback(uint16_t conn_handle)
{
Serial.println("Connected");
Serial.print("Discovering Service ... ");
// If HRM is not found, disconnect and return
if ( !hrms.discover(conn_handle) )
{
Serial.println("Found NONE");
}
// Once HRM service is found, we continue to discover its characteristic
Serial.println("Found it");
Serial.print("Discovering characteristic ... ");
if ( !hrmc.discover() )
{
// chr is mandatory, if it is not found (valid), then disconnect
Serial.println("not found !!!");
Serial.println("characteristic is mandatory but not found");
Bluefruit.disconnect(conn_handle);
return;
}
Serial.println("Found it");
// Get the reference to current connection
BLEConnection* connection = Bluefruit.Connection(conn_handle);
connection->requestPHY(BLE_GAP_PHY_2MBPS);
// Request MTU exchange for rx_client
if (connection) {
connection->requestMtuExchange(dataSize + 3); // Request MTU of 247 bytes
}
}
/**
*/
void disconnect_callback(uint16_t conn_handle, uint8_t reason)
{
(void) conn_handle;
(void) reason;
Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX);
}
The text was updated successfully, but these errors were encountered: