I'm trying to use Arduino nano 33 BLE sense to transmit mic data over BLE. For some reason after starting PDM, the code never comes back from the function BLE.begin(). This doesn't happen when removing the PDM part. Why does this happen?
#include <PDM.h>
#include <ArduinoBLE.h>
#define BUFF_SZ 100
short sampleBuffer[BUFF_SZ];
const char* deviceServiceUuid = "19b10000-e8f2-537e-4f6d-d104768a1215";
const char* deviceServiceCharacteristicUuid = "19b10001-e8fd-537e-4f6c-d104768a1215";
volatile int samplesRead = 0;
BLEService gestureService(deviceServiceUuid);
BLECharacteristic gestureCharacteristic(deviceServiceCharacteristicUuid, BLERead | BLEWrite | BLENotify, BUFF_SZ);
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
while (!Serial);
PDM.onReceive(onPDMdata);
if (!PDM.begin(1, 16000)) {
Serial.println("Failed to start PDM!");
while (1);
}
Serial.println("Mic started");
if (!BLE.begin()) {
Serial.println("Starting Bluetooth Low Energy module failed!");
while (1);
}
Serial.println("BLE LED Peripheral");
BLE.setLocalName("Arduino Nano 33 BLE (Peripheral)");
BLE.setAdvertisedService(gestureService);
gestureService.addCharacteristic(gestureCharacteristic);
BLE.addService(gestureService);
BLE.advertise();
}
BLE is designed and intended for very infrequent transmissions of very small amounts of data.
It does not make sense, and is probably impossible to use it for transmitting 16000 microphone sound samples every second.
Edit: I checked, and if you use the very latest BLE libraries on both ends, with very carefully chosen parameters, it is just barely possible to transmit data at that rate of 256 kbps. See A Practical Guide to BLE Throughput | Interrupt
Here is the entirety of the code. I didn't include it because the thing get's stuck before it even gets to that part of the code
#include <PDM.h>
#include <ArduinoBLE.h>
#define BUFF_SZ 100
short sampleBuffer[BUFF_SZ];
const char* deviceServiceUuid = "19b10000-e8f2-537e-4f6d-d104768a1215";
const char* deviceServiceCharacteristicUuid = "19b10001-e8fd-537e-4f6c-d104768a1215";
volatile int samplesRead = 0;
BLEService gestureService(deviceServiceUuid);
BLECharacteristic gestureCharacteristic(deviceServiceCharacteristicUuid, BLERead | BLEWrite | BLENotify, BUFF_SZ);
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
while (!Serial);
if (!BLE.begin()) {
Serial.println("Starting Bluetooth Low Energy module failed!");
while (1);
}
BLE.setLocalName("Arduino Nano 33 BLE (Peripheral)");
BLE.setAdvertisedService(gestureService);
gestureService.addCharacteristic(gestureCharacteristic);
BLE.addService(gestureService);
BLE.advertise();
Serial.println("BLE LED Peripheral");
//PDM.onReceive(onPDMdata);
if (!PDM.begin(1, 16000)) {
Serial.println("Failed to start PDM!");
while (1);
}
Serial.println("Mic started");
}
void loop() {
// put your main code here, to run repeatedly:
/* BLEDevice central = BLE.central();
if (central) {
Serial.print("Connected to central: ");
// print the central's MAC address:
Serial.println(central.address());
while (central.connected()) {
if (samplesRead) {
gestureCharacteristic.writeValue(sampleBuffer,samplesRead);
samplesRead = 0;
}
}
} */
}
void onPDMdata() {
// query the number of bytes available
int bytesAvailable = PDM.available();
// read into the sample buffer
PDM.read(sampleBuffer, bytesAvailable);
// 16-bit, 2 bytes per sample
samplesRead = bytesAvailable;
}
Try what I suggested: remove the BLE stuff and just print out the microphone data.
BTW are you SURE that the samples are bytes? They certainly aren't on my NRF52840 setup. You may be wiping out memory by writing past buffer boundaries.
// 16-bit, 2 bytes per sample
samplesRead = bytesAvailable;
Here is the code that I use to write 16 bit PDM microphone data to a file on QSPI flash, developed for the Adafruit Clue NRF52840, running at 48 MHz.
It turns out that flash memory is too slow for 256 sample (512 byte) audio buffers, and audio samples were dropped at regular intervals.
The sample buffer size had to be increased to 1024 to overcome that limitation, so, I am completely confident that BLE cannot handle the task you have in mind.
//working 4/2024
// upped gain to 42 (default was 20, too quiet)
// large sample buffer is required to overcome slow write speed to flash
/*
This example reads audio data from the on-board PDM microphone
and saves to a QSPI flash file audio.dat
// 2Mb flash = 2097152 bytes, 4096 512 byte blocks
*/
#include <Adafruit_Arcada.h>
Adafruit_Arcada arcada;
#include <PDM.h>
// buffer to read samples into, each sample is 16-bits
// setting a larger buffer avoids dropping audio samples
// write to flash are slow!
int16_t sampleBuffer[1024];
// number of samples read
volatile int samplesRead;
File file;
void setup() {
Serial.begin(115200);
while (!Serial) yield();
// configure the data receive callback
PDM.onReceive(onPDMdata);
if (!arcada.arcadaBegin()) {
while (1);
}
//Arcada_FilesystemType
arcada.filesysBegin(ARCADA_FILESYS_QSPI);
file = arcada.open("/audio.dat", O_CREAT | O_WRITE);
if (!file) {
Serial.println("\r output file open failure");
while (1) yield();
}
PDM.setBufferSize(2048); //bytes!
// initialize PDM with:
// - one channel (mono mode)
// - a 16 kHz sample rate
if (!PDM.begin(1, 16000)) {
Serial.println("Failed to start PDM!");
while (1) yield();
}
// optionally set the gain, defaults to 20
PDM.setGain(42);
Serial.println("recording");
}
int nframes = 250;
void loop() {
// wait for samples to be read
if (samplesRead) {
file.write((char *)sampleBuffer, 2048);
// Serial.println(nframes);
nframes--;
if (nframes == 0) {
file.close();
Serial.println("stopped");
arcada.filesysListFiles();
Serial.flush();
while (1) yield();
}
samplesRead = 0;
}
}
void onPDMdata() { //callback
// query the number of bytes available
int bytesAvailable = PDM.available();
// read into the sample buffer
PDM.read(sampleBuffer, bytesAvailable);
// 16-bit, 2 bytes per sample
samplesRead = bytesAvailable / 2;
}