I am still new in Arduino sketching and hardware. I have the portenta h7 and vision shield board. I am using this code to try its microphone. However the PDM plotter is not changing. Anyone know what is the problem?
The code:
#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;
}
I have the PDM MICs working (but not on an Arduino sketch, instead as native STM32 project, with HAL drivers).
Important to know is:
PDM is not PCM!
The PDM signal from MICs are Pulse Dense Modulated: it means: the gap (their length) in between the pulses are the audio signals.
PCM is Pulse Code Modulation: so, you get the audio signal values (amplitude sampled).
A PDM signal must be filtered and converted into a PCM signal. There are library function to do so. When you take the PDM signal and you try to display the "values": they are just 0 or 1. A PDM signal printed as amplitudes samples does not show you any reasonable audio waveform.
If you need help - I can share my STM32 IDE code for PDM MICs.
It needs a LIB which will do the PDM filter and conversion to PCM values. The filter is a real "analog" filter, done in SW. I guess, you have to enable also to use the HW Floating Point Unit (FPU).
Here my PDM MIC for Portenta H7 VisionShield: VisionShield.zip (17.0 KB)
The source code file should be "self contained" (all what you need), except:
The clock config is done in my system_clock.c (but see the comment in audio.c).
I enable it via:
PDM_MIC_Init(dBAmplifier);
0 stops it, otherwise 1..51 as dB for amplification factor.
I do not know if there is a dependency in code for USB Audio, e.g. a buffer: I send this MIC Audio as USB Audio device to a host PC (via USB-A on breakout board).
See the LIB file in ZIP: you have to add it as LIB to the project (it is for the PDM filter).
I am sorry - I send the PDM MIC audio via network (ETH).
I use "VB-Audio Voicemeeter": VB-Audio, Voicemeeter
I send as UDP, with the right protocol (VBAN). I can receive on PC with a "virtual network" sound card driver. I am not using USB, even I have it up and running in my project (not part of this shared code, but you see the UDP transmission as VBAN).