It's easy to use the Adafruit PDM microphone breakout with CircuitPython, using the built-in audiobusio
module and PDMIn
class. It allows you to record an input audio signal from the microphone using PDM.
This page will walk you through wiring up your PDM mic, and using it to print out sound levels to the serial console and show the values on the plotter in Mu.
CircuitPython Microcontroller Wiring
The following wiring diagrams show how to connect the PDM mic to a Feather M4 Express. If you're using another board, check out the Where's my PDMIn? section at the end for valid pin combinations for your board. Some boards, like the SAMD21 and SAMD51 have fixed pins that support PDM. Others like the nRF52840 can use any two pins.
The following is the header version of the PDM microphone breakout wired to a Feather M4 Express:
The following is the JST version of the PDM microphone breakout wired to a Feather M4 Express:
- Mic 3V (red wire) to Feather 3V
- Mic GND (black wire) to Feather Gnd
- Mic DAT (blue wire) to Feather D12
- Mic CLK (yellow wire) to Feather TX
If you're using Circuit Playground Express, there is a built in PDM microphone. There is a guide page dedicated to using Circuit Playground Express and the built-in microphone. If you're using a CPX, check that out instead!
CircuitPython Usage
As PDMIn
is built into CircuitPython, no separate libraries are necessary for this example!
Save the following as code.py on your microcontroller board:
# SPDX-FileCopyrightText: 2018 Kattni Rembor for Adafruit Industries # # SPDX-License-Identifier: MIT import time import array import math import board import audiobusio # Remove DC bias before computing RMS. def mean(values): return sum(values) / len(values) def normalized_rms(values): minbuf = int(mean(values)) samples_sum = sum( float(sample - minbuf) * (sample - minbuf) for sample in values ) return math.sqrt(samples_sum / len(values)) # Main program mic = audiobusio.PDMIn(board.TX, board.D12, sample_rate=16000, bit_depth=16) samples = array.array('H', [0] * 160) while True: mic.record(samples, len(samples)) magnitude = normalized_rms(samples) print((magnitude,)) time.sleep(0.1)
First you import time
, array
, math
, board
and audiobusio
.
Then you have two helper functions. The first one uses math to return a mean, or average. It is used in the second helper. The second one uses math to return a normalised RMS average. You use these functions to take multiple sound samples really quickly and average them to get a more accurate reading.
Next you set up the microphone object and your samples variable.
Then you use the mic object to start taking sound samples. You use the normalised RMS to find the average of a given set of samples, and you call that the magnitude
. Last, you print
the magnitude
to the serial console.
Note that the Mu plotter looks for tuple values to print. Tuples in Python come in parentheses ()
with comma separators. If you have two values, a tuple would look like (1.0, 3.14)
Since you have only one value, you need to have it print out likeĀ (1.0,)
note the parentheses around the number, and the comma after the number. Thus the extra parentheses and comma in print((magnitude,))
.
Once you have everything setup and running, try speaking towards the microphone, and watch the plotter immediately react! Move further away from the microphone to cause smaller changes in the plotter line. Move closer to the board to see bigger spikes!
Note that the way that the code works with averaging a given number of readings over time means that short sounds like claps can sometimes get missed. If you feel like your mic is not responding, try a longer sound like a hum or speaking words.
It's a really easy way to test your microphone and see how it reads sound changes!
Where's my PDMIn
?
Save the following as code.py on your board, and connect to the serial console to see a list of all the valid PDMIn
pin combinations. Note: the code will run immediately and only runs once - if you connect to the serial console and don't see anything, press ctrl+D to reload and run the code again.
# SPDX-FileCopyrightText: 2018 Kattni Rembor for Adafruit Industries # # SPDX-License-Identifier: MIT import board import audiobusio from microcontroller import Pin def is_hardware_PDM(clock, data): try: p = audiobusio.PDMIn(clock, data) p.deinit() return True except ValueError: return False except RuntimeError: return True def get_unique_pins(): exclude = ['NEOPIXEL', 'APA102_MOSI', 'APA102_SCK'] pins = [pin for pin in [ getattr(board, p) for p in dir(board) if p not in exclude] if isinstance(pin, Pin)] unique = [] for p in pins: if p not in unique: unique.append(p) return unique for clock_pin in get_unique_pins(): for data_pin in get_unique_pins(): if clock_pin is data_pin: continue if is_hardware_PDM(clock_pin, data_pin): print("Clock pin:", clock_pin, "\t Data pin:", data_pin) else: pass
Page last edited January 22, 2025
Text editor powered by tinymce.