PDM problem with NANO 33 BLE SENSE

Hi there,
I'm working on project where I want to log some PDM data, I have started with the standard PDMSerialPlotter example (code below) and I've noticed that first data written in to serial window looks weird (playing 500Hz tone from my phone, tested with two different boards an PCs):


After some time it normalizes:

I did some testing and figured out that for example, if using sampleBuffer[16000], after PDM is started, only when the 3rd consequent sampleBuffer is filled, sample data becomes normalized and that there is nothing wrong with the data in upcoming buffers.

Does somebody have an idea of what is going on here?

I've also tried the EdgeImpulse's firmware and recorded some audio, couldn't spo anything wrong there.

/*
  This example reads audio data from the on-board PDM microphones, and prints
  out the samples to the Serial console. The Serial Plotter built into the
  Arduino IDE can be used to plot the audio data (Tools -> Serial Plotter)

  Circuit:
  - Arduino Nano 33 BLE board or
  - Arduino Portenta H7 board plus Portenta Vision Shield

  This example code is in the public domain.
*/

#include <PDM.h>

// default number of output channels
static const char channels = 1;

// default PCM output frequency
static const int frequency = 16000;

// Buffer to read samples into, each sample is 16-bits
short sampleBuffer[512];

// Number of audio samples read
volatile int samplesRead;

void setup() {
  Serial.begin(9600);
  while (!Serial);

  // Configure the data receive callback
  PDM.onReceive(onPDMdata);

  // Optionally set the gain
  // Defaults to 20 on the BLE Sense and -10 on the Portenta Vision Shield
  // PDM.setGain(30);

  // Initialize PDM with:
  // - one channel (mono mode)
  // - a 16 kHz sample rate for the Arduino Nano 33 BLE Sense
  // - a 32 kHz or 64 kHz sample rate for the Arduino Portenta Vision Shield
  if (!PDM.begin(channels, frequency)) {
    Serial.println("Failed to start PDM!");
    while (1);
  }
}

void loop() {
  // Wait for samples to be read
  if (samplesRead) {

    // Print samples to the serial monitor or plotter
    for (int i = 0; i < samplesRead; i++) {
      if(channels == 2) {
        Serial.print("L:");
        Serial.print(sampleBuffer[i]);
        Serial.print(" R:");
        i++;
      }
      Serial.println(sampleBuffer[i]);
    }

    // Clear the read count
    samplesRead = 0;
  }
}

/**
 * Callback function to process the data from the PDM microphone.
 * NOTE: This callback is executed as part of an ISR.
 * Therefore using `Serial` to print messages inside this function isn't supported.
 * */
void onPDMdata() {
  // Query the number of available bytes
  int bytesAvailable = PDM.available();

  // Read into the sample buffer
  PDM.read(sampleBuffer, bytesAvailable);

  // 16-bit, 2 bytes per sample
  samplesRead = bytesAvailable / 2;
}

Welcome to the forum.

I do not know this for sure but here is my educated guess. PDM requires a low pass filter to turn the modulated signal back into the analog signal. Digital filters have an inherent delay. Therefore, I suspect that what you are seeing is the delay of the filter.

1 Like

Thank you @Klaus_K , you are right.