最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c++ - Transfering data at fixed rate over bluetooth low energy with itsy bitsy nRF52840 - Stack Overflow

programmeradmin1浏览0评论

I am building a wireless ppg sensor as a module for my senior design project in engineering but I am struggling to get an adequate data transfer rate over bluetooth. Here you can see I attempt to save 10 seconds of data to a buffer (at 125Hz sampling freq.) Then I print each over bluetooth to my mobile device.

The bluetooth specs of the chip estimate around 2mbps data transfer rate and despite that It takes nearly 4 minutes to simply transfer all 1250 integers.

How can the print time be sped up such that my data transfer rate is 125Hz and I don't need to sit around waiting 4 minutes for each 10 seconds of data to come in?

I would much prefer that the data be printed in real-time but attempting to do that without collecting in a buffer was causing gaps in the signal. At least with the buffer I currently have the 10 seconds is contiguous but printing immediately after reading from my sensor is the goal. I already have an ios app setup that parses the data into 10 second chunks and feeds them into my neural-network so there is no need for it to be sent in 10 second chunks.

#include <bluefruit.h>
#include <Wire.h>
#include "MAX30105.h"

MAX30105 particleSensor;
BLEUart bleuart; // Add BLE UART service

void setup() 
{
  Serial.begin(230400);
  Serial.println("Initializing...");

  // Start I2C
  Wire.begin();
  
  // Initialize sensor
  if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) 
  {
    Serial.println("ERROR: MAX30102 not found.");
    while (1);
  }
  Serial.println("MAX30105 initialized.");

  // Configure sensor
  particleSensor.setup(0x1F, 8, 2, 3200, 69, 4096); // Configure with specific settings

  Bluefruit.begin();
  Bluefruit.setTxPower(4);
  Bluefruit.Periph.setConnInterval(9, 16);

  // Initialize BLE UART service
  bleuart.begin();

  // Start advertising
  startAdv();
}

void startAdv(void)
{
  Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
  Bluefruit.Advertising.addTxPower();
  Bluefruit.Advertising.addService(bleuart); // Include BLE UART service
  Bluefruit.Advertising.addName();
  Bluefruit.Advertising.restartOnDisconnect(true);
  Bluefruit.Advertising.setInterval(32, 244);
  Bluefruit.Advertising.setFastTimeout(30);
  Bluefruit.Advertising.start(0);
}

void loop() {
  static unsigned long lastSample = 0;
  unsigned long currentTime = micros();
  static unsigned int numSamples = 0;
  static unsigned long last1250 = 0;

  // Buffer for 1250 compressed values
  static uint16_t dataBuffer[1250] = {0}; // Using uint16_t since I'm only storing the middle 5 digits

  if (currentTime - lastSample >= 8000) {  
    // Get sensor data
    uint32_t irValue = particleSensor.getIR(); 

    // Compress the value
    uint16_t compressedValue = (irValue % 100000) / 10; // Keep only the middle 5 digits
    Serial.println(compressedValue);
    // Store the compressed value in the buffer
    if (numSamples < 1250) {
      dataBuffer[numSamples] = compressedValue;
      numSamples++;
    }

    lastSample = currentTime;
  }

  if (numSamples >= 1250) {
    // Print elapsed time for 1250 samples to Serial
    Serial.print("Starting Bluetooth Transfer (1250 samples collected), Time: ");
    Serial.println(micros() - last1250);
    last1250 = micros();

    // Transmit the buffer data
    for (int i = 0; i < 1250; i++) {
      bleuart.println(dataBuffer[i]);
    }
    Serial.println("Bluetooth Transfer Complete");

    // Reset counters
    numSamples = 0;
  }
}

I am building a wireless ppg sensor as a module for my senior design project in engineering but I am struggling to get an adequate data transfer rate over bluetooth. Here you can see I attempt to save 10 seconds of data to a buffer (at 125Hz sampling freq.) Then I print each over bluetooth to my mobile device.

The bluetooth specs of the chip estimate around 2mbps data transfer rate and despite that It takes nearly 4 minutes to simply transfer all 1250 integers.

How can the print time be sped up such that my data transfer rate is 125Hz and I don't need to sit around waiting 4 minutes for each 10 seconds of data to come in?

I would much prefer that the data be printed in real-time but attempting to do that without collecting in a buffer was causing gaps in the signal. At least with the buffer I currently have the 10 seconds is contiguous but printing immediately after reading from my sensor is the goal. I already have an ios app setup that parses the data into 10 second chunks and feeds them into my neural-network so there is no need for it to be sent in 10 second chunks.

#include <bluefruit.h>
#include <Wire.h>
#include "MAX30105.h"

MAX30105 particleSensor;
BLEUart bleuart; // Add BLE UART service

void setup() 
{
  Serial.begin(230400);
  Serial.println("Initializing...");

  // Start I2C
  Wire.begin();
  
  // Initialize sensor
  if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) 
  {
    Serial.println("ERROR: MAX30102 not found.");
    while (1);
  }
  Serial.println("MAX30105 initialized.");

  // Configure sensor
  particleSensor.setup(0x1F, 8, 2, 3200, 69, 4096); // Configure with specific settings

  Bluefruit.begin();
  Bluefruit.setTxPower(4);
  Bluefruit.Periph.setConnInterval(9, 16);

  // Initialize BLE UART service
  bleuart.begin();

  // Start advertising
  startAdv();
}

void startAdv(void)
{
  Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
  Bluefruit.Advertising.addTxPower();
  Bluefruit.Advertising.addService(bleuart); // Include BLE UART service
  Bluefruit.Advertising.addName();
  Bluefruit.Advertising.restartOnDisconnect(true);
  Bluefruit.Advertising.setInterval(32, 244);
  Bluefruit.Advertising.setFastTimeout(30);
  Bluefruit.Advertising.start(0);
}

void loop() {
  static unsigned long lastSample = 0;
  unsigned long currentTime = micros();
  static unsigned int numSamples = 0;
  static unsigned long last1250 = 0;

  // Buffer for 1250 compressed values
  static uint16_t dataBuffer[1250] = {0}; // Using uint16_t since I'm only storing the middle 5 digits

  if (currentTime - lastSample >= 8000) {  
    // Get sensor data
    uint32_t irValue = particleSensor.getIR(); 

    // Compress the value
    uint16_t compressedValue = (irValue % 100000) / 10; // Keep only the middle 5 digits
    Serial.println(compressedValue);
    // Store the compressed value in the buffer
    if (numSamples < 1250) {
      dataBuffer[numSamples] = compressedValue;
      numSamples++;
    }

    lastSample = currentTime;
  }

  if (numSamples >= 1250) {
    // Print elapsed time for 1250 samples to Serial
    Serial.print("Starting Bluetooth Transfer (1250 samples collected), Time: ");
    Serial.println(micros() - last1250);
    last1250 = micros();

    // Transmit the buffer data
    for (int i = 0; i < 1250; i++) {
      bleuart.println(dataBuffer[i]);
    }
    Serial.println("Bluetooth Transfer Complete");

    // Reset counters
    numSamples = 0;
  }
}
Share Improve this question asked Nov 15, 2024 at 23:57 AceKijaniAceKijani 336 bronze badges 6
  • 3 This is not C language. Very few C language projects are written like C++. – Thomas Matthews Commented Nov 16, 2024 at 0:17
  • 1 Only use println when data needs to be formatted. Use the binary write method. – Thomas Matthews Commented Nov 16, 2024 at 0:22
  • 1 You should profile or benchmark your code to find out where most of the time is spent. Optimize those sections. – Thomas Matthews Commented Nov 16, 2024 at 0:23
  • Choose a naming convention where types and variable names differ by more than case. – Thomas Matthews Commented Nov 16, 2024 at 0:25
  • You're waiting to transmit the data until the buffer is 1250 full. Then, trying to burst it out. That waiting time is wasted (when it could have been used to transmit). And, once the buffer is full, you're not servicing any incoming data from the bluetooth device. During that time period, it could drop data. You should use two buffers (i.e. double buffering) so that you always pull in data as soon as available. And, you should send out data byte-by-byte as soon as you get it to prevent large idle periods on the UART. – Craig Estey Commented Nov 16, 2024 at 4:07
 |  Show 1 more comment

1 Answer 1

Reset to default 1

The Bluetooth that you are using is Bluetooth Low Energy (BLE). BLE allows devices to leave their transmitters off most of the time and this is what makes it “Low Energy”.

This means when you do a bleuart.println(dataBuffer[i]);, under the hood it turns on the radio, establishes connection, sends (by default) 20 bytes, and then turns the radio off. So if you were to send a value of 125, as you are using println, it will convert it to ASCII so will be three bytes resulting in a payload of: 3532310000000000000000000000000000000000 An inefficient payload for each turning on and off of the radio.

It would be more efficient to write the value (e.g. 125) as a single byte value of 7d. This means that you could send 20 values for the same payload with the overhead of the radio being turn on and off.

You could also get your app to negotiate a bigger payload (MTU) and that would allow even greater throughput for the same radio overhead.

Using a "UART" service over BLE might not be the most efficient option for your project. If it is heart rate that you are using, then it might be worth using the Bluetooth standard for transmitting such information. This would allow you to leverage a lot of the examples that are already out there or use an app that follows the standard.

https://www.bluetooth/specifications/specs/heart-rate-service-1-0/

发布评论

评论列表(0)

  1. 暂无评论