Project Overview & Difficulty Rating

The Raspberry Pi lacks an onboard analog-to-digital converter (ADC) for audio input. To record audio on a Raspberry Pi, you must bypass this limitation by using an external ADC. The most reliable, low-noise method is an I2S MEMS microphone like the Adafruit SPH0645LM4H, configured via ALSA and Python's sounddevice library. Unlike USB microphones that introduce latency and polling overhead, I2S microphones stream digital audio directly into the Pi's hardware PCM block, yielding studio-grade timing for DIY acoustic sensors, voice assistants, or wildlife monitoring rigs.

Difficulty Rating: Intermediate (Requires editing boot config files and basic Linux audio routing)
Estimated Time: 45 minutes
Target Board: Raspberry Pi 5 (8GB variant) running Raspberry Pi OS (Bookworm/Trixie 64-bit)

Required Parts List

Component Exact Variant / Model Estimated Price (2026)
Microcontroller Raspberry Pi 5 (8GB RAM) $80.00
Microphone Adafruit I2S MEMS Mic Breakout (SPH0645LM4H) $7.95
Cooling Raspberry Pi 5 Active Cooler $5.00
Wiring Silicone Female-to-Female Jumper Wires (26 AWG) $4.50

Note: The Pi 5 Active Cooler is mandatory here. The Pi 5 SoC will aggressively thermal-throttle under load, which alters the internal PLL clock dividers and introduces severe jitter into the I2S bit-clock, resulting in corrupted audio.

Hardware Wiring & Pin Mapping

The SPH0645LM4H communicates via the I2S (Inter-IC Sound) protocol. We must connect it to the Raspberry Pi's dedicated hardware PCM pins. Do not attempt to bit-bang I2S on arbitrary GPIO pins; the Linux kernel's ALSA driver relies on the hardware PCM peripheral for precise timing.

Pi 5 Physical Pin BCM GPIO Number Pi 5 Function SPH0645 Breakout Pin
Pin 1 N/A (Power) 3.3V Power VIN
Pin 6 N/A (Ground) Ground GND
Pin 12 GPIO 18 PCM_CLK (Bit Clock) BCLK
Pin 35 GPIO 19 PCM_FS (Frame Sync / LRCLK) LRCL
Pin 38 GPIO 20 PCM_DIN (Data In) DOUT
Callout Tip: The SPH0645 has a SEL pin. Leave it unconnected (floating) to default to the left channel, or tie it to GND to force the right channel. For this mono build, leave it floating.

Software Setup & Compilable Recording Script

Before writing code, we must instruct the Pi 5's bootloader to load the I2S device tree overlay and configure ALSA to recognize the microphone as the default input device.

Step 1: Enable the I2S Device Tree Overlay

Open the Pi 5 boot configuration file. Note that on Bookworm and newer 64-bit OS versions, the path is /boot/firmware/config.txt (not /boot/config.txt).

sudo nano /boot/firmware/config.txt

Add the following lines at the bottom of the file to enable the hardware I2S block and the memory-mapped audio overlay (which fixes static noise issues common with MEMS mics):

dtparam=i2s=on
dtoverlay=i2s-mmap

Reboot the Pi: sudo reboot.

Step 2: Configure ALSA Defaults

Create a system-wide ALSA configuration file so Python doesn't accidentally try to open the HDMI audio output as a microphone.

sudo nano /etc/asound.conf

Paste the following configuration to map the I2S card to a virtual mono device:

pcm.i2s_mic {
    type plug
    slave {
        pcm "hw:0,0"
        channels 1
        rate 44100
        format S32_LE
    }
}

pcm.default {
    type plug
    slave.pcm "i2s_mic"
}

Step 3: Install Python Dependencies

sudo apt update
sudo apt install libportaudio2 python3-pip
pip3 install sounddevice numpy scipy --break-system-packages

Step 4: The Python Recording Script

This script targets the Raspberry Pi 5 hardware index, records 5 seconds of audio, and includes robust error handling for common ALSA/PortAudio failures.

import sounddevice as sd
from scipy.io import wavfile
import numpy as np
import sys
import time

# =========================================================
# Target Board: Raspberry Pi 5 (8GB) / Bookworm 64-bit
# Hardware: Adafruit SPH0645LM4H I2S MEMS Mic
# Pins: BCLK=GPIO18, LRCL=GPIO19, DOUT=GPIO20
# =========================================================

DURATION = 5  # seconds
SAMPLE_RATE = 44100
OUTPUT_FILE = "pi5_i2s_recording.wav"

def find_i2s_device():
    """Queries ALSA to find the I2S hardware index."""
    devices = sd.query_devices()
    for i, dev in enumerate(devices):
        # Look for the standard Raspberry Pi I2S ALSA card name
        if 'i2s' in dev['name'].lower() or 'snd_rpi' in dev['name'].lower():
            if dev['max_input_channels'] > 0:
                return i
    return None

def main():
    device_index = find_i2s_device()
    
    if device_index is None:
        print("[FATAL] No I2S input device found. Check 'arecord -l' and config.txt.")
        sys.exit(1)

    print(f"[INFO] Recording {DURATION}s from device {device_index} ({sd.query_devices(device_index)['name']})...")
    
    try:
        # The SPH0645 outputs 24-bit audio padded to 32-bit (S32_LE)
        # We force 1 channel as defined in our /etc/asound.conf plug
        audio_data = sd.rec(
            int(DURATION * SAMPLE_RATE),
            samplerate=SAMPLE_RATE,
            channels=1,
            dtype='int32',
            device=device_index
        )
        
        # Block until recording is complete
        sd.wait()
        
        # Normalize and save as 16-bit WAV for broad compatibility
        audio_normalized = np.int16((audio_data / np.max(np.abs(audio_data))) * 32767)
        wavfile.write(OUTPUT_FILE, SAMPLE_RATE, audio_normalized)
        print(f"[SUCCESS] Audio saved to {OUTPUT_FILE}")
        
    except sd.PortAudioError as e:
        print(f"[PORTAUDIO ERROR] {e}")
        print("Fix: Ensure /etc/asound.conf forces channels=1 and format=S32_LE.")
        sys.exit(1)
    except Exception as e:
        print(f"[UNEXPECTED ERROR] {e}")
        sys.exit(1)

if __name__ == "__main__":
    main()

Debugging: ALSA Errors and First Checks

Audio routing on Linux is notoriously fragile. If your script fails, do not guess. Look at the exact traceback and cross-reference it with the ranked causes below.

Exact Error: sounddevice.PortAudioError: Error opening InputStream: Invalid number of channels [PaErrorCode -9998]

  • Cause 1 (Most Likely): ALSA is attempting to open a stereo stream, but the SPH0645 is strictly mono. PortAudio rejects the channel count mismatch.
  • Cause 2: Your /etc/asound.conf is missing or the channels 1 directive was omitted from the plug slave definition.
  • Fix: Verify the asound.conf file provided in Step 2. Ensure your Python sd.rec() call explicitly sets channels=1.

Exact Error: ALSA lib pcm_hw.c:1829:(_snd_pcm_hw_open) Invalid value for card

  • Cause 1: The I2S device tree overlay failed to load at boot, meaning the kernel never created the snd_rpi_i2s_card hardware node.
  • Cause 2: You are editing /boot/config.txt instead of /boot/firmware/config.txt on a modern Pi 5 Bookworm image.
  • Fix: Check the correct config path, ensure dtparam=i2s=on is not commented out, and reboot.
The First 3 Things to Check When It Fails:
  1. Verify Boot Config: Run cat /boot/firmware/config.txt | grep i2s to confirm dtparam=i2s=on is active.
  2. Verify Hardware Detection: Run arecord -l in the terminal. You must see card 0: sndrpihifiberry [snd_rpi_hifiberry_dac] or a similar I2S card listed. If it says "no soundcards found", the overlay failed.
  3. Verify Physical Wiring: BCLK (GPIO 18) and LRCL (GPIO 19) are frequently swapped on breadboards. Double-check against the pin mapping table above.

Extending and Simplifying the Build

Depending on your project constraints, you may need to pivot from the I2S MEMS approach.

How to Simplify: The USB Audio Route

If editing ALSA configs and wiring I2S clocks feels like overkill, simplify the build by purchasing a Sabrent USB External Stereo Sound Adapter (~$8). Plug it into a Pi 5 USB 3.0 port, connect a standard 3.5mm electret microphone, and use the same Python script (it will auto-detect the USB card as the default ALSA input). The trade-off is higher latency (~15ms) and a slight USB polling noise floor, which is acceptable for voice commands but poor for acoustic FFT analysis.

How to Extend: True Stereo I2S & Network Streaming

To record true stereo audio, add a second SPH0645 breakout. Wire the second mic's DOUT to GPIO 21 (PCM_DOUT). Update your /etc/asound.conf to use the route plugin to map the two physical mono streams into a single stereo ALSA device.

To extend this into an IoT edge node, replace the wavfile.write block with an MQTT publisher (using the paho-mqtt library) to stream 1-second FLAC-encoded chunks to a central home automation server for real-time acoustic anomaly detection.

Frequently Asked Questions

Can I record audio on Raspberry Pi using the 3.5mm analog jack?

No. The 3.5mm jack on the Raspberry Pi 4 and 5 is strictly an audio output (line out/headphones) driven by an onboard DAC. It does not have an ADC or a microphone bias voltage circuit. Attempting to wire a microphone directly to the analog jack will yield silence and risks damaging the Pi's audio codec chip.

Why is my I2S microphone recording pure static or white noise?

The SPH0645LM4H has a known timing quirk where it outputs data on the falling edge of the bit clock, while the Raspberry Pi's default I2S master mode expects it on the rising edge. This phase mismatch results in corrupted bits that sound like loud white noise. Adding dtoverlay=i2s-mmap to your config.txt forces the kernel to use a memory-mapped DMA buffer that corrects this timing alignment. If static persists, ensure your Pi 5 is actively cooled; thermal throttling shifts the SoC clock domains and breaks I2S synchronization.

How do I record audio on Raspberry Pi continuously without destroying my SD card?

SD cards have limited write-erase cycles. Continuously writing WAV files to /home/pi/ will kill a standard microSD card in a few months. To prevent this, mount a tmpfs RAM disk in your /etc/fstab (e.g., tmpfs /mnt/ramdisk tmpfs nodev,nosuid,size=256M 0 0). Record your audio chunks to the RAM disk, process them in memory, and only write to the SD card (or push to a network drive) when a specific acoustic trigger threshold is met.