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
|
Show 1 more comment
1 Answer
Reset to default 1The 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/
println
when data needs to be formatted. Use the binary write method. – Thomas Matthews Commented Nov 16, 2024 at 0:22