PCM5102 Audio Codec: 32-Bit DAC and Volume Control in RPi Pico WAV Player
The RPi Pico WAV Player uses the Texas Instruments PCM5102 audio codec, a 32-bit I²S DAC that receives software-scaled PCM samples with volume control implemented in the PlayAudio subsystem.
The elehobica/rpi_pico_wav_player project leverages dedicated hardware and precision firmware to deliver high-quality audio playback on Raspberry Pi Pico. Understanding how the PCM5102 audio codec interfaces with the software volume control reveals the architecture behind the 32-bit audio pipeline.
Understanding the PCM5102 Audio Codec Hardware
The PCM5102 is a stereo audio DAC that converts digital I²S signals into analog audio output. The codec operates as a slave device, receiving bit clock (BCK), word select (LRCK), and serial data (DIN) from the RP2040 microcontroller.
Hardware Specifications and Pinout
According to the project documentation in README.md, the PCM5102 connects to specific GPIO pins on the Pico:
- BCK (Bit Clock): GPIO26
- LRCK (Left/Right Clock): GPIO27
- DIN (Data In): GPIO28
The README describes the component as "PCM5102 32bit I2S Audio DAC" and confirms it handles the full 32-bit PCM range expected by the codec hardware.
Software Volume Control Implementation
Volume management occurs entirely in software before samples reach the DAC. The PlayAudio class maintains a volume lookup table and applies scaling to 32-bit integers, ensuring the PCM5102 receives properly ranged data that utilizes its full dynamic range.
Volume Scaling Algorithm
The volume system stores discrete levels in vol_table defined in lib/PlayAudio/PlayAudio.cpp. The table maps user-facing volume levels (0-100) to fixed-point multipliers:
// Volume table initialization in PlayAudio.cpp
static const uint16_t vol_table[] = {
// ... lookup values for 0-100 range
};
When adjusting volume, the firmware retrieves the corresponding scalar from this table. The setVolume(), volumeUp(), and volumeDown() methods handle user input and clamp values between 0 and 100.
32-Bit Sample Processing
The actual scaling occurs in lib/PlayAudio/PlayWav.cpp during the audio decoding loop. The firmware converts source samples to 32-bit integers, applies the volume multiplier, then adds the DAC zero-offset:
// Inside PlayWav::decode() - sample scaling logic
int32_t scaled = static_cast<int32_t>(
(static_cast<int64_t>(buf_s32) * vol_table[volume] / 65536)
) + DAC_ZERO;
samples[i*2 + j] = scaled; // 32-bit sample written to I²S buffer
This calculation ensures the PCM5102 receives 32-bit aligned data centered around DAC_ZERO, maximizing the codec's signal-to-noise ratio while preventing clipping at extreme volume levels.
I²S Interface Configuration
The RP2040's I²S peripheral initialization occurs in lib/PlayAudio/i2s_audio_init.cpp. The i2s_setup() function configures the PIO (Programmable I/O) state machines to generate the precise timing required by the PCM5102:
// I²S initialization for PCM5102
i2s_setup(44100, ap); // Default sample rate, PCM5102 expects I²S data
The PCM5102 operates in standard I²S mode, expecting the MSB of the 32-bit sample to be valid on the second rising edge of BCK following an LRCK transition. The firmware's PIO program generates this exact timing pattern, ensuring the codec correctly interprets the high-resolution audio data.
Summary
- The PCM5102 from Texas Instruments serves as the 32-bit I²S audio codec, converting digital PCM data to analog output.
- Volume control is implemented entirely in software within
PlayAudio.cppandPlayWav.cpp, using a lookup table to scale 32-bit samples before transmission. - The I²S interface in
i2s_audio_init.cppdrives the PCM5102 with precise PIO-generated timing at standard sample rates like 44.1 kHz. - The 32-bit DAC output utilizes the full dynamic range of the PCM5102 by applying a zero-offset (
DAC_ZERO) to centered audio data.
Frequently Asked Questions
What audio codec does the RPi Pico WAV Player use?
The project uses the Texas Instruments PCM5102, a 32-bit stereo audio DAC that receives I²S signals from the RP2040 microcontroller. This codec is connected via GPIO pins 26 (BCK), 27 (LRCK), and 28 (DIN) according to the hardware documentation in README.md.
How does the PCM5102 handle 32-bit audio output?
The PCM5102 accepts 32-bit PCM samples via its I²S input and converts them to analog voltages with high dynamic range. The firmware maximizes this capability by sending scaled 32-bit integers centered around DAC_ZERO (typically 0x80000000 for unsigned alignment), ensuring the codec utilizes its full-scale output without clipping.
Where is volume control implemented in the code?
Volume control logic resides in two primary locations: lib/PlayAudio/PlayAudio.cpp defines the vol_table lookup array and volume setting methods (setVolume(), volumeUp(), volumeDown()), while lib/PlayAudio/PlayWav.cpp applies the actual scaling algorithm during sample decoding, multiplying 32-bit PCM values by the volume coefficient before adding the DAC zero-offset.
What is the DAC zero-offset value used for?
The DAC_ZERO constant (defined in the audio library) represents the mid-scale value of the PCM5102's 32-bit input range, typically corresponding to 0x80000000 for unsigned 32-bit alignment. This offset centers the bipolar audio signal around the DAC's mid-point, ensuring that silence corresponds to the analog zero-voltage point and that negative sample values produce negative voltages while positive values produce positive voltages.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →