All projects
03 / hardware & embedded audio · 2025

ESP32-S3
MP3 Player

Getting music from a microSD card to an external audio DAC turned into a lesson in debugging one subsystem at a time.

Playback working · October 2025

ESP32-S3 / Arduino C++ / SPI microSD / PCM5102A I²S DAC

The current prototype

On the workbench
MP3 player prototype on a work mat, with a wired breadboard, microcontroller, small illuminated display, microSD module, battery, and connected boards.

My current MP3 player prototype on the workbench. Photo cleaned up with AI for presentation; the original photo is also available.

View full-size photo (opens in a new tab)
The idea

A small music player, built from the signal path up.

I set out to build a standalone MP3 playback prototype using an ESP32-S3, a microSD card, and a PCM5102A digital-to-analog converter. The ESP32 would read compressed audio from storage, decode it in firmware, and send digital samples over I²S to the DAC. The concept was straightforward. The debugging was not. Early combined playback sketches froze, restarted, or produced silence and distorted tones. That forced me to separate the project into smaller tests: could the SD card actually read the file? Could the DAC produce sound? If both worked, what was failing when the audio decoder entered the picture? I eventually got MP3 playback working. The process was useful practice in embedded debugging: reducing problems to isolated tests, reading serial output, understanding memory constraints, and checking which library version was actually installed.

Hardware list

Parts & connections

microSD SPI ESP32-S3 I²S PCM5102A DAC analog audio output

Three pieces that had to cooperate, plus their firmware
ComponentInterfaceRole & known specifications
ESP32-S3-WROOM-1-N16R8SPI / I²SReads files, decodes MP3, and drives I²S. 16 MB flash and 8 MB PSRAM configuration; Arduino-ESP32 3.3.x used during debugging.
microSD cardSPISDHC storage reported as 15,343 MB; standalone tests read /test.mp3.
PCM5102A DACI²SConverts digital samples to analog audio. Independent waveform tests produced audible sound.
Arduino C++ firmwareSD / audio librariesSD.h / SPI.h; ESP8266Audio tested; ESP32-audioI2S v3.4.3 preceded successful playback.

Historical tests show two different GPIO wiring maps. The final working pin assignment has not been verified; neither test map should be treated as final wiring.

Development log

Tests, failures & playback

Reconstructed from development conversations dated October 25, 2025. These notes distinguish observed failures, attempted fixes, and reported success. The final sketch and wiring are not available.

01 — Starting with sound, but not music

I could drive the PCM5102A with simple generated waveforms, so the basic I²S output path was capable of making sound. But trying to play an MP3 from the SD card frequently caused a freeze or reset. Producing a tone and reliably decoding streamed audio turned out to be very different tasks.

02 — Proving the SD card worked on its own

The playback sketch kept failing around SD initialization, so I wrote a separate test for the card instead of changing everything at once. The ESP32 mounted the SDHC card, listed /test.mp3, and successfully created and removed directories. The serial monitor sometimes printed sdCommand(): no token received, but the standalone tests proved that the card and its basic SPI connection were functional.

03 — Proving the DAC worked on its own

Next I drove the DAC with a generated sine wave through I²S. That produced audible output. With storage and DAC tests passing independently, I had better evidence that the combined file-streaming and decode path deserved most of my attention.

04 — Watchdog resets and alternative libraries

In combined playback tests I repeatedly hit ESP32 watchdog resets, including TG1WDT_SYS_RST. I tried different approaches to audio playback, including ESP8266Audio and ESP32-audioI2S. Depending on the sketch, playback reached a "Playing" message but produced no sound, or resulted in a loud, stuttering tone. I also explored SPI timing, PSRAM settings, buffering, and I²S configuration, without a confirmed fix from those changes alone.

05 — Following the buffer errors

A later ESP32-audioI2S v3.4.2 test exposed a much more specific failure: an unexpectedly large input buffer allocation, m_writePtr > m_endPtr, and MP3, indata underflow, followed by memory corruption and a reboot. Those logs pointed to the library's buffering/streaming path rather than simply a missing SD file or a silent DAC. I also hit an API dead end when a buffer-size method from an example was not present in my installed alternative library.

06 — Getting playback working

After updating ESP32-audioI2S from v3.4.2 to v3.4.3, I confirmed that MP3 playback was working. The successful setup also used enabled PSRAM, three-wire I²S, and regular servicing of the library's playback loop. The library update was the clearest immediate change before success; I can't prove every other setting was independently required.

What I learned

Debug the boundary between working parts.

This project taught me why embedded problems are easier to diagnose when each subsystem has its own pass/fail test. I had to distinguish an SD warning from a total storage failure, audible I²S test output from reliable decoded playback, and a speculative pin problem from concrete buffer/underflow errors. It also reinforced the importance of recording exact dependency versions, hardware wiring, and board memory configuration—not just whether a sketch compiles.

Debug notes: evidence and limits

Observed in v3.4.2: inputBufferSize: 655349 bytes, m_writePtr > m_endPtr, and MP3, indata underflow, followed by heap corruption and a reboot. These are diagnostic fragments from testing.

SPI timing, PSRAM, and I²S configuration were investigated. A buffer-size API attempt did not compile in the installed alternative library. A WAV test was inconclusive because the expected file was missing. The libraries were tried separately; a direct conflict between them was not established.

Working MP3 playback was reported after the v3.4.3 update. A final enclosure, battery, controls, and polished player interface are not documented.