Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can BLE connection invtervals ovelap? #832

Open
75snow75 opened this issue Oct 2, 2024 · 0 comments
Open

Can BLE connection invtervals ovelap? #832

75snow75 opened this issue Oct 2, 2024 · 0 comments
Labels

Comments

@75snow75
Copy link

75snow75 commented Oct 2, 2024

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
image

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.
image

Moreover, when one of the clients disconnects, the connection interval shortens from 20ms to 10ms.
image

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);
}
}

/**

  • 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;

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));

Serial.print("Timestamp: "); Serial.print(millis()); Serial.print(" >> ");
Serial.print(" from "); Serial.print(receivedData[0]);
Serial.print(" at "); Serial.print(receivedData[dataNum-1]);
Serial.println("");

} 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

    • 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

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**/
/**

  • 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
  • @param conn_handle
    */
    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");

// 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
}
}

/**

  • Callback invoked when a connection is dropped
  • @param conn_handle
  • @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;

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

    • 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

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**/
/**

  • 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
  • @param conn_handle
    */
    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");

// 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
}
}

/**

  • Callback invoked when a connection is dropped
  • @param conn_handle
  • @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;

Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant