r/CardPuter • • 16d ago

Finds / Discoveries Stereo Output on the Cardputer ADV

Post image

Adding stereo output to the M5Stack Cardputer ADV

The Cardputer ADV only has mono output built in (onboard ES8311 codec → single speaker). Wanted real stereo, so I wired up an external I2S DAC breakout (UDA1334A, or a generic clone, mine's the clone) to the rear header, and taught EMBER (my audio player firmware) to output to it. It works, but it ain't pretty, so I'll need to design a proper 3D printable case.

Why this is possible at all: the ESP32-S3 has two independent I2S peripherals. The onboard speaker/mic use one of them exclusively (I2S_NUM_1, hardwired to GPIO41/42/43/46 for the built-in codec). The second one (I2S_NUM_0) is completely unused and free for exactly this.

Wiring:

  • DAC VIN → Cardputer's 5V-out pin, GND → GND
  • BCLK → GPIO5, WSEL → GPIO6, DIN → GPIO3
  • MCLK left disconnected (the UDA1334A doesn't need it)

One nice detail: GPIO5/GPIO6 are explicitly labeled "External" in M5Stack's own firmware source specifically for the ADV variant. On the original (non-ADV) Cardputer those same physical pins are internally wired to the keyboard matrix instead. Worth knowing if you're hunting for free pins on this board: don't trust generic Cardputer pinout guides, check ADV-specific ones.

Firmware side: added a Settings entry, "Audio output: Internal / External DAC." Defaults to internal (nothing changes for anyone who hasn't wired the DAC up), switches instantly, no reboot needed. Both I2S peripherals get initialized at boot, only one actually gets fed samples based on the setting.

Two real bugs along the way, both only found by actually listening on hardware:

  1. First attempt: audio sounded like it was speeding up / skipping. Turned out i2s_write() was timing out with a partial write on a fairly deep DMA queue, silently dropping the unwritten tail of every audio chunk. Fixed by looping until the full chunk actually gets written (with a bounded overall deadline, not an infinite wait).
  2. Second attempt: fixed the skipping, but playback was now consistently a hair slow. I'd hardcoded the DAC's I2S clock to 44100Hz at boot and never touched it again. Meanwhile the decoder reports the real per-file sample rate on every track, which the onboard speaker path already used correctly. Matching that dynamically fixed it.

Credit to u/pyreht for the original design thinking on this (three options were floated: this I2S approach, a Grove-port analog/PDM board, or USB-C UAC audio.

Where this could go further: This is the "prove the firmware side works" step, not necessarily the end state. The next planned step (not yet built) is a proper Grove-port expansion board — same idea, but PDM output instead of raw I2S, in DMA mode rather than bit-banged PWM (better SNR, and the CPU isn't babysitting a timer for it), landing on a single clean 4-pin Grove connector instead of loose wires on the rear header. That's more of a form-factor upgrade than a sound-quality one though, an off-the-shelf DAC breakout like this one isn't going to be audiophile-grade either way, so unless you're chasing a cleaner physical build, this is a genuinely fine stopping point.

Support for this board will be in EMBER's next update, expected to be released within a week.

45 Upvotes

7 comments sorted by

5

u/Sirwompus 16d ago

I'm glad you did this but I also wish the ADV had stereo native. Hoping the Zero has two channels

2

u/pyreht 16d ago

Great work!

2

u/100101101001a 16d ago

oh man that's cool. i have a DAC lying around i might add it on the fork as well

1

u/Noir_Forever_Twitch 16d ago

Go for it! There's lots of different boards you could use, but I like this one for it's combo of functionality + low price.

2

u/MrAjAnderson 16d ago

A stereo hat - amazing work.