Getting reliable audio out of a Raspberry Pi 5 is a rite of passage for embedded makers. Unlike the Pi 4, the Pi 5 completely dropped the analog PWM headphone jack, routing all audio through the RP1 southbridge chip. This means your options are strictly digital: HDMI, USB, or I2S. If you are building a kiosk, an interactive art piece, or a retro console where USB dongles are too bulky and HDMI audio routing is a nightmare, I2S is the only professional choice.

This guide cuts through the outdated Bullseye-era tutorials and gives you the exact wiring, PipeWire configuration, and Python code to get I2S audio working on the Raspberry Pi 5 running the latest 64-bit OS.

The Decision Matrix: Which Audio Output for Your Pi?

Before you solder a single header, you need to pick the right audio architecture. Here is the decision path based on real-world project constraints:

Project Constraint Audio Method Latency / Quality Verdict
Need zero-latency GPIO sync & custom enclosure I2S DAC (MAX98357A) Low latency / 16-bit 44.1kHz Default Pick for Embedded
Need 24-bit/192kHz audiophile line-out HiFiBerry DAC+ Pro HAT Ultra-low jitter / High-res Choose for high-end audio projects
Just need basic system beeps, no GPIO wiring USB Audio Adapter (e.g., Sabrent) High latency / 16-bit Choose for simple desktop/kiosk use
Video and audio over a single cable HDMI Audio Variable / Depends on display Choose only if display has built-in speakers
The Concrete Pick: For 90% of embedded builds requiring a built-in speaker, the Adafruit MAX98357A I2S Class-D Amplifier (Product ID: 3006) is the definitive choice. It costs under $8, requires only 5 GPIO pins, and drives a 3W speaker directly without needing a separate amp board.

Parts List & Pin Mapping for Pi 5 I2S Audio

The Raspberry Pi 5 uses the RP1 chip to handle peripherals. The I2S (Inter-IC Sound) pins are fixed to specific BCM GPIO numbers. Do not attempt to move these to other pins; the RP1 hardware PWM/I2S blocks are hardwired to these traces.

Bill of Materials

  • Compute: Raspberry Pi 5 (4GB or 8GB variant) — ~$60-$80
  • DAC/Amp: Adafruit MAX98357A I2S Amplifier Breakout (Product ID: 3006) — ~$7.50
  • Transducer: 3W 4-Ohm Speaker with JST-PH 2.0 connector — ~$5.00
  • Wiring: Silicone Female-to-Female jumper wires (26 AWG) — ~$4.00
  • Power: Raspberry Pi 27W USB-C PD Power Supply — ~$12.00
  • Indicator: Standard 5mm LED with 330Ω resistor (for GPIO sync testing) — ~$0.10

Hardware Pin Mapping Table

Pi 5 BCM GPIO Physical Pin # MAX98357A Pad Function / Signal
BCM 18 (PCM_CLK) 12 BCLK Bit Clock (I2S timing)
BCM 19 (PCM_FS) 35 LRC Left/Right Clock (Word Select)
BCM 21 (PCM_DOUT) 40 DIN Serial Audio Data Out
5V Power 2 or 4 VIN Power In (Do NOT use 3.3V)
GND 6 GND Common Ground
BCM 17 (GPIO) 11 N/A (LED Anode) Status LED Sync (via 330Ω resistor)
Power Warning: The MAX98357A can pull up to 1.5A at peak volume when driving a 4-ohm load. Always wire VIN to the 5V rail, and ensure you are using the official 27W Pi 5 power supply. Brownouts on the 5V rail will cause the RP1 chip to reset the I2S bus, resulting in audio popping or complete dropouts.

Wiring and Software Configuration (Step-by-Step)

  1. De-energize and Wire: Unplug the Pi 5. Connect the 5 I2S/power wires according to the table above. Connect the speaker to the JST port on the MAX98357A. Connect the LED anode to BCM 17 via the 330Ω resistor, and cathode to GND.
  2. Enable the I2S Overlay: Boot the Pi. In Raspberry Pi OS Bookworm (and newer), the boot partition is mounted at /boot/firmware/. Open the config file:
    sudo nano /boot/firmware/config.txt
    Add these lines at the bottom to load the MAX98357A device tree overlay and disable the default HDMI audio routing:
    dtparam=i2s=on
    dtoverlay=max98357a
    dtparam=audio=off
  3. Reboot and Verify Hardware: Run sudo reboot. Once back in, verify the kernel loaded the codec:
    dmesg | grep max98357a
    You should see the ASOC (ALSA System on Chip) driver binding to the I2C/I2S bus.
  4. Install Python Audio Dependencies: Modern Pi OS uses PipeWire instead of PulseAudio. The Python sounddevice library relies on PortAudio. Install the system bindings:
    sudo apt update
    sudo apt install portaudio19-dev python3-pip python3-gpiozero
    pip3 install sounddevice numpy --break-system-packages
  5. Set Default PipeWire Sink: List your audio sinks using pw-cli ls | grep node.name. Find the string for the MAX98357A (usually alsa_output.platform-sound.card0 or similar). Set it as default in ~/.config/pipewire/pipewire.conf or via the desktop GUI to ensure system-wide routing.

Python Playback Code with Error Handling

This script targets the Raspberry Pi 5 (64-bit OS). It generates a 440Hz sine wave using NumPy, streams it to the I2S DAC via PortAudio, and toggles a GPIO LED in perfect sync to prove the hardware timing. It includes robust error handling for ALSA device mapping failures.

import sounddevice as sd
import numpy as np
from gpiozero import LED
import time
import sys

# ==========================================
# PIN & HARDWARE DEFINITIONS
# ==========================================
LED_SYNC_PIN = 17       # BCM 17 (Physical Pin 11)
I2S_SAMPLE_RATE = 44100 # MAX98357A native optimal rate
FREQUENCY_HZ = 440.0    # A4 Note
DURATION_SEC = 3.0      # Playback length
AMPLITUDE = 0.5         # 50% volume to prevent speaker clipping

# Initialize GPIO for embedded sync indicator
status_led = LED(LED_SYNC_PIN)

def generate_sine_wave(freq, sr, duration, amp):
    """Generates a mono 16-bit PCM sine wave array."""
    t = np.linspace(0, duration, int(sr * duration), False)
    wave = np.sin(2 * np.pi * freq * t) * amp
    return wave.astype(np.float32)

def play_audio_with_sync():
    wave_data = generate_sine_wave(FREQUENCY_HZ, I2S_SAMPLE_RATE, DURATION_SEC, AMPLITUDE)
    
    # Turn on LED exactly when audio buffer starts streaming
    status_led.on()
    print(f"[INFO] Streaming {DURATION_SEC}s of {FREQUENCY_HZ}Hz to I2S DAC...")
    
    try:
        # Block=False allows us to manage the LED timing, but we must wait for completion
        sd.play(wave_data, samplerate=I2S_SAMPLE_RATE, device='default')
        sd.wait() # Blocks until audio buffer is empty
    except sd.PortAudioError as e:
        status_led.off()
        print(f"[FATAL] PortAudio Error: {e}")
        print("[FIX] Check 'aplay -l' to ensure MAX98357A is recognized.")
        sys.exit(1)
    except Exception as e:
        status_led.off()
        print(f"[FATAL] Unexpected playback error: {e}")
        sys.exit(1)
    finally:
        # Turn off LED exactly when audio finishes
        status_led.off()
        print("[INFO] Playback complete. LED synced.")

if __name__ == "__main__":
    print("[BOOT] Initializing Pi 5 I2S Audio & GPIO Sync...")
    time.sleep(0.5) # Brief debounce for power rail stabilization
    play_audio_with_sync()

Debugging: Exact Error Strings and First Three Checks

Audio on Linux is a layered stack: Hardware → Device Tree → ALSA → PipeWire → PortAudio → Python. When it fails, do not guess. Follow this exact diagnostic path.

The First Three Things to Check

  1. Is the hardware mapped? Run aplay -l. You must see card X: sndrpihifiberry [snd_rpi_hifiberry_dac] or max98357a. If it only shows vc4hdmi, your config.txt overlay failed to load.
  2. Did the Device Tree compile? Run vcdbg log msg 2>&1 | grep dtdebug or check dmesg | grep i2s. If you see 'pinmux conflict', another HAT or overlay is stealing BCM 18/19/21.
  3. Is PipeWire hoarding the sink? Run pw-cli info all | grep state. If the node is 'suspended' or 'running' but silent, PipeWire's echo-cancel module might be hijacking the stream.

Ranked Causes for Common Exact Error Strings

Exact Error String Ranked Causes (Most Likely First) The Fix
ALSA lib pcm_dmix.c:1032:(snd_pcm_dmix_open) unable to open slave 1. PipeWire is holding exclusive lock.
2. Wrong hw:X,Y mapping in .asoundrc.
Stop PipeWire temporarily (systemctl --user stop pipewire) to test raw ALSA, or use device='default' in Python to let PipeWire route it.
sounddevice.PortAudioError: Error opening OutputStream: Invalid device [PaErrorCode -9996] 1. Python script hardcoded an ALSA string (e.g., hw:1,0) that shifted on reboot.
2. PortAudio cache is stale.
Change the device parameter in sd.play() to 'default'. Never hardcode hw:X,Y in embedded scripts; USB devices and I2S hats swap card numbers randomly.
gpiozero.exc.GPIOPinInUse: pin 17 is already in use 1. A previous Python script crashed and didn't release the pin.
2. Another overlay is using BCM 17.
Run sudo killall python3 to clear hung processes. Ensure no SPI/UART overlays are claiming BCM 17 in config.txt.

Extending and Simplifying the Build

Once you have the baseline I2S audio working, you will inevitably need to adapt it for production or scale it down for a quick prototype.

How to Simplify (The 'I Just Need It Working' Path)

If the Device Tree overlays and PipeWire sinks are eating up your development time, abandon I2S and buy a $12 USB Audio Dongle (like the StarTech ICUSBAUDIO). Plug it in, delete the dtoverlay lines from config.txt, and the Pi OS desktop will automatically route audio to it. You lose GPIO sync and some latency, but you save 3 hours of Linux audio debugging. Use this for digital signage where audio timing doesn't matter.

How to Extend (The Production Path)

  • Add a DSP: If you need EQ, crossover, or volume limiting to protect your speaker, insert an ADAU1701 SigmaDSP between the Pi's I2S out and the MAX98357A's I2S in. You program the DSP via Analog Devices' SIGMA Studio on a PC, and it processes the audio in hardware before amplification.
  • Stereo Output: The MAX98357A is mono. For stereo, use the HiFiBerry DAC+ (Product ID: 2368). It uses the exact same I2S pins (BCM 18, 19, 21) but includes a Burr-Brown PCM5102A DAC chip and dual RCA line-outs. Note that it outputs line-level audio, so you will need to add an external Class-D amp board like the TPA3116 if you are driving raw speakers.
  • Hardware Mute: The MAX98357A breakout has a GAIN pad and an SD (Shutdown) pad. Wire the SD pad to a spare GPIO (e.g., BCM 27). Pulling it LOW physically mutes the amp at the silicon level, eliminating the 'pop' sound that occurs when the Pi boots and the I2S bus initializes.
Final Bench Note: Always measure the 5V rail at the MAX98357A VIN pad with a multimeter while playing bass-heavy audio at max volume. If it dips below 4.8V, your speaker wires are too thin or your power supply is sagging. Upgrade to 18 AWG speaker wire and verify your USB-C PD cable is rated for 5A.

For deeper reading on Pi 5 peripheral routing, consult the official Raspberry Pi config.txt documentation. For the specific amplifier specs and gain pad configurations, reference the Adafruit MAX98357A learning guide.