JayV
Published © CERN-OHL

Arduino Zero PDM Microphone

Example of the use of a Digital PDM microphone.

IntermediateWork in progress1 hour12,429
Arduino Zero PDM Microphone

Things used in this project

Hardware components

Arduino MKR WiFi 1010
Arduino MKR WiFi 1010
×1
STMicroelectronics STEVAL-MIC002V1
×1

Software apps and online services

Arduino Web Editor
Arduino Web Editor

Story

Read more

Custom parts and enclosures

3D Print File

3D STL file for pyramid microphone casing

Schematics

Schematic PDM connect

PDM connect via I2S to Arduino

MP34dt06j Datasheet

PDM Microphone - ST Micro

Code

PDMZero.zip

C/C++
Arduino Library for I2S / PDM
No preview (download only).

PDMZero_VolumeMeter.ino

C/C++
PDM example: Volume / VU Meter
/*************************************************************
PDM Microphone example
By JV March 2019 Version 1.00

running volume calculation for VU-Meter usage.
Use 128 decimation for PCM signal.
Auto Gain the volume (keep track of everge max/min volume)

Turn on PLOTTER !!

*************************************************************/
#include <PDMZero.h>
#define DBG 1  // Debug info

// Definitions for Audio PDM Microphone
#define SAMPLERATE_HZ 9375
#define DECIMATION    128
#define PCMTIME 15           // sample evaluatiuon time in milliseconds
#define PCMTRESHOLD 4000
uint16_t sincfilter[DECIMATION] = {0,  0,  1,  2,  4,  7,  10, 15, 19, 25, 31, 39, 47, 56, 66, 77, 89, 103,  118,  134,  151,  170,  189,  211,  233,  258,  282,  309,  337,  366,  396,  428,  460,  493,  527,  562,  598,  634,  670,  707,  743,  780,  816,  852,  888,  922,  956,  988,  1021, 1050, 1079, 1105, 1131, 1153, 1176, 1193, 1211, 1224, 1237, 1245, 1253, 1255, 1258, 1255, 1253, 1245, 1237, 1224, 1211, 1193, 1176, 1153, 1131, 1105, 1079, 1050, 1021, 988,  956,  922,  888,  852,  816,  780,  743,  707,  670,  634,  598,  562,  527,  493,  460,  428,  396,  366,  337,  309,  282,  258,  233,  211,  189,  170,  151,  134,  118,  103,  89, 77, 66, 56, 47, 39, 31, 25, 19, 15, 10, 7,  4,  3,  2,  1,  1,  0,  0,  0};
PDMZero Mypdm = PDMZero(2, A6);   // Create PDM receiver object, with Clock and Data pins used clock=> PA10 = ~2  data => PA07 = A6  MKR1000 / MKR1010
#define PDM_REPEAT_LOOP_16(X) X X X X X X X X X X X X X X X X // a manual loop-unroller!

uint16_t avgl= 0x8000,tavgl = 0x8000, avgr= 0x8000, tavgr = 0x8000,Acoustic_Counter=0; // Global Avarege rolling Audio signal level
uint32_t minvoll=0xffffffff,minvolr=0xffffffff,maxvoll=0,maxvolr=0,avgvolume=0x00001000; // lowest volume level... probably Noise level
uint32_t VolumeLeft = 0, VolumeRight = 0;


void setup()
{ 

/*********** Serial SETUP  **********/
int t=10;  //Initialize serial and wait for port to open, max 10 second waiting
  Serial.begin(921600UL);
  while (!Serial) {
    ; delay(1000);
    if ( (t--)== 0 ) break;
  }
/*********** PDM over I2S Setup ************/
if (!Mypdm.begin()) {
    Serial.println("Failed to initialize I2S/PDM!");
    while (1);
   }
if (!Mypdm.configure(SAMPLERATE_HZ * DECIMATION/16, true)) {
    Serial.println("Failed to configure PDM");
    while (1);
  }
while ( Mypdm.read() ==0) Serial.print("."); // read till first sample are avaialble
Serial.println("PDM Test starts");             
}



void loop()
{
uint16_t vu_left=0,vu_right=0;             // vuMeter Variable
Read_AudioVolume(&vu_left,&vu_right);
//Serial.println(vu_left);                   // turn on your plotter !!
}

// Read audio levels and convert to running Volume
// Rease I2S Samples, Reduce them by Decimator, calcualte volume over Ms Samples read
void Read_AudioVolume(uint16_t* leftchannel,uint16_t* rightchannel) {
uint16_t  t,peakl,peakr;
uint16_t runningsuml, runningsumr;

VolumeLeft=0;VolumeRight=0; // Relative volume per Sampled Time slot PCMTIME

  for (t = 0; t < (SAMPLERATE_HZ * PCMTIME) / 1000; ++t)
  {
    runningsuml=0; runningsumr=0; 
    uint16_t *sinc_ptr = sincfilter; // pointer to 64bit FIR-filer cooeficients

    for (uint8_t samplenum = 0; samplenum < (DECIMATION / 16) ; samplenum++) {
      uint32_t sampler = Mypdm.read();    // we read 32 bits at a time, high and low 16bit stereo
      uint32_t samplel = 0xFFFF & (sampler >> 16);
      samplel = samplel & 0xFFFF;

      PDM_REPEAT_LOOP_16(      // manually unroll loop: for (int8_t b=0; b<16; b++)
      {
        if (samplel & 0x1) {            // start at the LSB which is the 'first' bit to come down the line, chronologically
          runningsuml += *sinc_ptr;     // do the convolution Left channel
        }
        if (sampler & 0x1) {            // start at the LSB which is the 'first' bit to come down the line, chronologically
          runningsumr += *sinc_ptr;     // do the convolution Right channel
        }
        sinc_ptr++;
        samplel >>= 1;                  // right shift :  I2S_SERCTRL_BITREV ,last input bit is at MSB 
        sampler >>= 1;                  // right shift :  I2S_SERCTRL_BITREV last input bit is at MSB 
      }
      )
      
    } // end decimation loop
    // we are only interested in the volume part: summarize the  Sample offset - average
   if ( runningsuml!=0 && runningsumr!=0 ) {
    avgl = (avgl * t + runningsuml) / (t + 1); // calculate running average
    avgr = (avgr * t + runningsumr) / (t + 1);
    peakl = abs(runningsuml - avgl);           // calcualte peak vs average
    peakr = abs(runningsumr - avgr);
       VolumeLeft += peakl;                     // summarize volume by adding all peaks
       VolumeRight += peakr;
    
    } // end sample process !=0
   
  } // end Sample For loop
  
  // process abs volume to relative volume
  if (VolumeLeft!=0 &&  VolumeRight!=0 ){
  avgvolume = (avgvolume*126 +VolumeLeft+VolumeRight)/128;               // average over 32 last samples = 32* 20ms = 1 seconde (uncontinous!)

      if ( maxvoll <= (2*avgvolume) ) maxvoll = 2*avgvolume;           // keep gap high enough : 100% vs Avg
      else  maxvoll = (255*maxvoll)/256;
      maxvolr = maxvoll;
      minvoll = (256*minvoll)/255;  // 1% increase
      minvolr= minvoll;
 
    // housekeeping min max and average
    if (VolumeLeft < minvoll ) minvoll = VolumeLeft;
    if (VolumeRight < minvolr ) minvolr = VolumeRight;
    if (VolumeLeft > maxvoll ) maxvoll = VolumeLeft;
    if (VolumeRight > maxvolr ) maxvolr = VolumeRight;  
    if(VolumeLeft>=PCMTRESHOLD ){*leftchannel =  (uint8_t) ( (100*(VolumeLeft-minvoll)) / (maxvoll-minvoll) ) ;  }
    else{ *leftchannel =  0x00; }
    if(VolumeRight>=PCMTRESHOLD ){ *rightchannel = (uint8_t) ( (100*(VolumeRight-minvolr)) / (maxvolr-minvolr) ) ; }
    else{ *rightchannel = 0x00 ; }
  }
//Serial.print(VolumeLeft);Serial.print(","); 
Serial.print(minvoll);Serial.print(",");
Serial.print(maxvoll);Serial.print(",");
Serial.print(avgvolume);Serial.print(",");
Serial.print((*leftchannel)*32);Serial.print(",");
Serial.print((*rightchannel)*32);Serial.println(",");
}

Credits

JayV

JayV

28 projects • 33 followers
Silicon crazy for profession, silicon do-it-yourselves at Home.

Comments