En este post, aprenderás cómo usar un módulo PCM5102A con el ESP32 para reproducir audio. El PCM5102A es un convertidor digital a analógico (DAC) de alto rendimiento, que se comunica a través de la interfaz I2S (Inter-IC Sound).
Convierte datos de audio en una señal analógica de nivel de línea, adecuada para amplificación o uso directo con auriculares de alta impedancia. El módulo incluye una salida estéreo de 3,5 mm y funciona con una alimentación estándar de 3,3 V a 5 V, lo que lo hace compatible con microcontroladores comunes como las placas ESP32 o Arduino.
A lo largo de este tutorial, aprenderás a generar señales de audio, convertir texto a voz, transmitir radio por internet, reproducir archivos MP3 desde una tarjeta SD y usar audio por Bluetooth.
Componentes necesarios
Necesitarás un módulo PCM5102A. Existen diferentes versiones de placas basadas en el PCM5102A, pero todas deberían funcionar para este tutorial. Yo utilicé la placa que aparece abajo, que tiene un conector jack de 3,5 mm para la salida de línea.

También necesitarás un par de altavoces activos, preferiblemente con conector de 3,5 mm para conectarlos directamente a esta placa PCM5102A.
Para reproducir archivos MP3 desde una tarjeta SD, además necesitarás una tarjeta SD de al menos 1GB y un lector de tarjetas SD.
Por último, necesitarás un ESP32, una placa de pruebas (breadboard) y algunos cables. Yo usé un ESP32 lite, pero la mayoría de las otras placas ESP32 también deberían funcionar. Si planeas almacenar y reproducir música desde la memoria, te recomiendo una placa ESP32-S3 con PSRAM.

Amplificador PCM5102

Altavoz activo

Lector de tarjetas Micro SD

Tarjeta Micro SD 8GB

ESP32 lite

Cable de datos USB

Set de cables Dupont

Breadboard
Makerguides is a participant in affiliate advertising programs designed to provide a means for sites to earn advertising fees by linking to Amazon, AliExpress, Elecrow, and other sites. As an Affiliate we may earn from qualifying purchases.
El protocolo de audio I2S
Empecemos con una breve introducción al protocolo I2S, que se utiliza para transferir datos de audio digitalmente desde un ESP32 a un DAC como el PCM5102A.
I2S, o Inter-IC Sound, es un estándar de interfaz de bus serie utilizado para conectar dispositivos de audio digital. Fue introducido por Philips en los años 80 para simplificar la transmisión de datos de audio entre circuitos integrados. A diferencia de protocolos como SPI o I2C, I2S está diseñado específicamente para aplicaciones de audio, asegurando una temporización y sincronización precisas de las señales de audio.
En esencia, I2S transfiere datos de audio en modulación por impulsos codificados (PCM) de forma síncrona. El protocolo utiliza tres señales principales: el reloj serie (SCK), la selección de palabra (WS) y los datos serie (SD). El reloj serie pulsa a la velocidad de bits, indicando cuándo se envían los bits. La señal de selección de palabra alterna para indicar si los datos actuales corresponden al canal de audio izquierdo o derecho. Finalmente, la línea de datos serie transporta los bits de audio reales, transmitiendo primero el bit más significativo (MSB).

Normalmente, los datos de audio se envían en palabras de 16 o 24 bits, pero el protocolo puede soportar otras profundidades de bits dependiendo del hardware.
El periférico I2S del ESP32 soporta comunicación full-dúplex, permitiendo entrada y salida de audio simultáneamente. Puede configurarse para funcionar en modo maestro o esclavo. Cuando actúa como maestro, el ESP32 genera las señales de reloj y selección de palabra. Esta es la configuración habitual al conectar con el DAC PCM5102A, que actúa como dispositivo esclavo I2S. En la siguiente sección veremos el PCM5102A con más detalle.
Características técnicas del módulo PCM5102
Los módulos PCM5102A están basados en el Texas Instruments PCM5102A, un convertidor digital a analógico estéreo diseñado para reproducción de audio en alta resolución. Convierte flujos de audio digital en señales analógicas de nivel de línea usando una ruta de señal totalmente integrada que minimiza la necesidad de componentes externos.
El PCM5102A soporta salida estéreo con un nivel de salida analógica a escala completa típico de unos 2,1 Vrms centrado a tierra, permitiendo la conexión directa a nivel de línea sin necesidad de condensadores de bloqueo de DC externos.
El módulo utilizado en este tutorial viene con un conector estéreo de 3,5 mm para la salida de audio, junto con componentes pasivos integrados para el filtrado de salida y acoplamiento AC. También hay puentes de soldadura para la selección de funciones, de lo que hablaremos más adelante. La imagen de abajo muestra el frontal y la parte trasera del módulo PCM5102A:

Entrada de audio digital y sincronización
Los datos de audio digital se aceptan a través de una interfaz PCM estándar compatible con los formatos I2S y left-justified, soportando datos de 16, 24 y 32 bits. Se admiten tasas de muestreo desde 8 kHz hasta 384 kHz, lo que hace que el dispositivo sea adecuado tanto para aplicaciones de audio estándar como de alta resolución.
El PCM5102A incluye un PLL integrado de alto rendimiento que puede sintetizar el reloj interno de alta velocidad necesario para sus motores de interpolación y DAC a partir del bit clock (BCK) o de un reloj de sistema externo opcional (SCK). Esto reduce la necesidad de una fuente de reloj maestro externa y permite operar con una conexión I2S de 3 hilos (LRCK, BCK, DIN).
Procesamiento digital de señal y filtros
Una vez recibidos los datos de audio digital, la ruta interna de señal del PCM5102A incluye filtros de interpolación digital que sobremuestrean la señal de entrada por un factor (por ejemplo, 128× la tasa de muestreo) antes de la conversión. Estas etapas de interpolación reducen el ruido de cuantización y simplifican los requisitos del filtro de reconstrucción analógico.
Etapa de salida analógica y driver de línea
La etapa de salida analógica del módulo integra un driver de línea DirectPath™ con bomba de carga, capaz de entregar una salida de nivel de línea en cargas de hasta 1 kΩ por canal. El circuito inteligente de soft-ramp y mute analógico ayuda a evitar transitorios audibles durante el encendido, apagado o errores de reloj.
Ten en cuenta que no puedes conectar directamente un altavoz pasivo a la salida de línea del PCM5102A. ¡Necesitas un amplificador adicional o un altavoz activo!
Alimentación, control y condiciones de funcionamiento
El módulo PCM5102A está diseñado para funcionar con una sola fuente de alimentación, en el rango de 3,3V a 5V. Internamente, el DAC utiliza reguladores integrados de bajo dropout para generar los voltajes necesarios para el núcleo y la parte analógica.
El PCM5102A entra en modo de bajo consumo automáticamente cuando los relojes I2S están inactivos para reducir el consumo de energía. Los pines de hardware y los puentes de soldadura permiten configurar el formato de audio (por ejemplo, I2S vs left-justified) y el estado de mute suave, sin necesidad de interfaz de control serie (I2C/SPI) para el funcionamiento básico.
Pinout
La siguiente imagen muestra el pinout de la placa PCM5102A:

En la parte superior de la placa están los pines para la salida de línea: LROUT = canal izquierdo, ROUT = canal derecho, AGNG = tierra, y pines para controlar funciones específicas de la placa (más sobre esto en la siguiente sección).
Las funciones también se pueden configurar mediante puentes de soldadura en la parte trasera de la placa (H1L, H2L, H3L, H4L). Y el conector de 3,5 mm duplica los pines de salida de línea.
En el lado derecho encontrarás los pines para la interfaz I2S (SCK, BCK, DIN, LRCK) y los pines para la alimentación (VIN, GND). Los pines I2S pasan por un pack de resistencias que debería permitir señales de 5V, por ejemplo, desde un Arduino UNO. El voltaje de alimentación puede ser de 3,3V o 5V, ya que la placa tiene reguladores internos de bajo dropout.
Jumpers de función
El módulo PCM5102A tiene cinco jumpers/puentes de soldadura que deben configurarse correctamente para que la placa funcione con un ESP32. Cambian las siguientes funciones según estén conectados a High o Low. Los ajustes recomendados están marcados en negrita:
- SCK = Master Clock: Low si no se proporciona señal de reloj maestro externa
- H1L / FLT = Selección de filtro: Latencia normal ( Low ) / Latencia baja (High)
- H2L / DEMP = Control de de-énfasis para muestreo a 44,1kHz: Off ( Low ) / On (High)
- H3L / XSMT = Control de mute suave: Mute suave (Low) / desmute suave ( High )
- H4L / FMT = Selección de formato de audio I2S: Right justified ( Low ) / Left justified (High)
La selección de filtro con latencia normal es un FIR con buena respuesta, que retrasa la señal unos 500us (a 44,1 kHz). El filtro de baja latencia es un IIR con respuesta algo peor y retrasa la señal unos 80us. Muy pocas (si es que hay alguna) fuentes de audio aplican pre-énfasis, así que el control de de-énfasis debe estar apagado. El pin XSMT permitiría silenciar la salida mediante un GPO o un interruptor si el puente H3L no está soldado. Y para el formato de audio I2S elegimos right justified.
La imagen de abajo muestra el esquema del módulo PCM5102A con estos jumpers de función marcados en amarillo:

Puentes de soldadura
Puedes encontrar cuatro puentes de soldadura H1L, H2L, H3L y H4L en la parte trasera de la placa. La imagen de abajo te muestra qué puentes debes soldar a High (H) o Low (H):

Alternativamente, también hay 4 pines (FLT, DEMP, XMST, FMT) en la parte superior de la placa que puedes conectar a 3,3V (H) o GND (L) para controlar las funciones de la placa. Esto es útil si quieres usar interruptores o GPIO para controlar funciones. Especialmente la función de mute (XMST/H3L) puede ser interesante. Pero asegúrate de usar o los pines o los puentes, ¡pero no ambos al mismo tiempo!
Puente SCK
Hay un solo puente en la parte frontal de la placa que también debes soldar. Controla si se proporciona o no una señal de reloj maestro externa (SCK). En nuestro caso no proporcionamos SCK y por lo tanto hay que soldar el puente SCK para conectar SCK a tierra.

Especificaciones técnicas
La siguiente tabla resume las especificaciones técnicas del PCM5102A:
| Parámetro | Especificación |
|---|---|
| Dispositivo DAC | Texas Instruments PCM5102A |
| Arquitectura interna | DAC delta-sigma de alto rendimiento con filtros de interpolación digital |
| Interfaz de audio digital | Formatos estándar I2S, left-justified, right-justified, DSP (PCM) |
| Tasas de muestreo soportadas | 8 kHz a 384 kHz |
| Profundidad de bits soportada | 16-bit, 24-bit, 32-bit |
| Requisitos de reloj de entrada | Bit Clock (BCK), Word Clock (LRCK); reloj de sistema externo opcional (SCK) |
| Sincronización | PLL integrado con multiplicador de reloj de alto rendimiento; generación interna de reloj maestro |
| Sobremuestreo de filtro digital | Múltiples etapas con alta relación de sobremuestreo (por ejemplo, 128 x fs) |
| Tipo de salida analógica | Salidas internas diferenciales con filtrado pasivo integrado a salida single-ended |
| Conector de salida | Jack estéreo de 3,5 mm |
| Voltaje de salida a escala completa | Aprox. 2,1 Vrms (centrado a tierra) |
| Carga de salida soportada | Diseñado para cargas de nivel de línea ≥ 1 kΩ por canal |
| Relación señal/ruido (SNR) | ~112 dB (A-weighted, típico) |
| Distorsión armónica total + Ruido (THD+N) | ~-93 dB (típico) |
| Driver de línea | Driver de línea DirectPath™ con bomba de carga integrado |
| Mute/Soft-Ramp | Mute analógico integrado al encender/apagar o pérdida de reloj |
| Voltaje de alimentación (AVDD) | 3,3 V … 5V |
| Niveles lógicos | Compatible LVCMOS con niveles de E/S del ESP32 |
| Interfaz de control | Configuración por pines de hardware (no se requiere I2C/SPI para funcionamiento básico) |
| Consumo de energía | Modo de bajo consumo automático cuando los relojes están inactivos |
Para información adicional consulta la hoja de datos del PCM5102A que está enlazada abajo:
Conectar PCM5102A al ESP32
En esta sección vamos a cablear el PCM5102A con el ESP32. Empezamos conectando VIN del PCM5102A a 3.3V del ESP32 y GND a G. Después conectamos los pines I2S como se muestra en la siguiente tabla:
| PCM5102A | ESP32 |
|---|---|
| VIN | 3V3 |
| GND | G |
| LRCK | 32 |
| BCK | 25 |
| DIN | 33 |
| SCK | G |
Si has soldado el puente SCK realmente no necesitas la conexión de SCK a tierra, pero no pasa nada si la dejas.
La siguiente imagen muestra el cableado completo del módulo PCM5102A con un ESP32 lite. Ten en cuenta que debes conectar la salida de línea del PCM5102A a un amplificador o altavoz activo. No debes conectar un altavoz pasivo o auriculares de baja impedancia directamente al PCM5102A.

Lector de tarjetas SD
Si quieres reproducir archivos de audio necesitas conectar un lector de tarjetas SD que almacene los archivos de audio en una tarjeta SD. El diagrama de cableado de abajo te muestra cómo conectar un lector de tarjetas SD y el PCM5102A a un ESP32:

El lector de tarjetas SD se comunica por SPI y los pines SPI por defecto del ESP32 son CS=5, MOSI=23, CLK=18 y MISO=19. La tabla de abajo resume las conexiones que debes hacer entre el lector de tarjetas SD y el ESP32:
| Lector de tarjetas SD | ESP32 |
|---|---|
| 3V3 | 3V |
| GND | G |
| CS/SS | 5 |
| MOSI | 23 |
| CLK/SCK | 18 |
| MISO | 19 |
Si no tienes claro cuáles son los pines SPI por defecto de tu ESP32, échale un vistazo al Find I2C and SPI default pins tutorial.
La siguiente foto muestra mi cableado del PCM5102A con un lector de tarjetas SD, un ESP32 y un pequeño altavoz activo mono para pruebas:

Instalación de librerías
En este tutorial vamos a usar la librería arduino-audio-tools de Phil Schatzmann para enviar datos de audio al PCM5102A. Para instalar la librería ve a la arduino-audio-tools repo, haz clic en el botón verde «<> Code» y luego en «Download ZIP» para descargar la librería como archivo ZIP, como se muestra abajo:

Luego abre un Sketch, ve a Sketch -> Include Library -> Add .ZIP Library … para instalar la librería ZIP descargada (arduino-audio-tools-main.zip):

Para algunos ejemplos de código necesitaremos dos librerías más de Phil Schatzmann: la arduino-libhelix y la ESP32-A2DP. Puedes instalarlas de la misma forma. Haz clic en el enlace para ir al repositorio de github, haz clic en el botón verde «<> Code» para descargar las librerías (arduino-libhelix-main.zip, ESP32-A2DP-main.zip) y luego instálalas.
Por último, si es la primera vez que programas una placa ESP32 desde tu Arduino IDE, tendrás que instalar también el core de ESP32. Para más detalles consulta el Install ESP32 core in Arduino IDE tutorial.
Ejemplo de código: Sonido de prueba
En este primer ejemplo simplemente generamos un tono de prueba en forma de onda senoidal y lo sacamos por la interfaz I2S al DAC
/*
www.makerguides.com
Libraries:
- ESP32 Core 3.3.6
- [arduino-audio-tools](https://github.com/pschatzmann/arduino-audio-tools)
Version: 1.2.2
- [arduino-libhelix](https://github.com/pschatzmann/arduino-libhelix)
*/
#include "AudioTools.h"
// PCM5102A
#define DIN_PIN 33 // serial data
#define LRCK_PIN 32 // word select
#define BCLK_PIN 25 // serial clock
#define VOLUME 1000 // max 32000
AudioInfo info(44100, 2, 16);
SineWaveGenerator<int16_t> sineWave(VOLUME);
GeneratedSoundStream<int16_t> sound(sineWave);
I2SStream out;
StreamCopy copier(out, sound);
void setup(void) {
auto config = out.defaultConfig(TX_MODE);
config.copyFrom(info);
config.pin_bck = BCLK_PIN;
config.pin_ws = LRCK_PIN;
config.pin_data = DIN_PIN;
out.begin(config);
sineWave.begin(info, N_B4);
}
void loop() {
copier.copy();
}
Imports
El código comienza incluyendo la librería AudioTools.h, que proporciona clases y funciones para generar y transmitir señales de audio fácilmente en el ESP32.
#include "AudioTools.h";
Constantes
A continuación, definimos los pines conectados al módulo DAC PCM5102A. Estos pines corresponden a las señales de la interfaz I2S: DIN_PIN para datos serie, LRCK_PIN para selección de palabra (left-right clock), y BCLK_PIN para el reloj serie. También definimos una constante VOLUME para establecer la amplitud de la onda senoidal generada, con una amplitud máxima de 32000.
#define DIN_PIN 33 // serial data #define LRCK_PIN 32 // word select #define BCLK_PIN 25 // serial clock #define VOLUME 1000 // max 32000
Configuración de audio y objetos
El objeto AudioInfo info define el formato de audio: una tasa de muestreo de 44.100 Hz, 2 canales (estéreo) y 16 bits por muestra. Esto corresponde a audio de calidad CD estándar.
El objeto SineWaveGenerator sineWave se utiliza para generar una señal de audio en forma de onda senoidal con el volumen especificado. Produce muestras de enteros de 16 bits con signo.
El objeto GeneratedSoundStream sound envuelve el generador de onda senoidal en una interfaz de stream, facilitando el envío de los datos de audio a una salida.
El objeto I2SStream out representa la interfaz de salida I2S en el ESP32, que enviará los datos de audio al DAC PCM5102A.
Por último, el objeto StreamCopy copier se encarga de copiar continuamente los datos de audio del stream generado al stream de salida I2S.
AudioInfo info(44100, 2, 16); SineWaveGenerator<int16_t> sineWave(VOLUME); GeneratedSoundStream<int16_t> sound(sineWave); I2SStream out; StreamCopy copier(out, sound);
Función Setup
Dentro de la función setup(), configuramos el stream de salida I2S. Empezamos obteniendo una configuración por defecto para el modo transmisión usando out.defaultConfig(TX_MODE). Luego, copiamos los ajustes de formato de audio del objeto info a esta configuración.
A continuación, asignamos los pines I2S a la configuración: BCLK_PIN para el bit clock, LRCK_PIN para la selección de palabra, y DIN_PIN para la línea de datos serie.
Después de configurar los pines, inicializamos el stream de salida I2S con out.begin(config). Finalmente, iniciamos el generador de onda senoidal con el formato de audio y una frecuencia de nota musical predefinida N_B4 (que corresponde a la nota B4).
void setup(void) {
auto config = out.defaultConfig(TX_MODE);
config.copyFrom(info);
config.pin_bck = BCLK_PIN;
config.pin_ws = LRCK_PIN;
config.pin_data = DIN_PIN;
out.begin(config);
sineWave.begin(info, N_B4);
}
Función Loop
La función loop() copia continuamente los datos de audio del stream del generador de onda senoidal al stream de salida I2S usando copier.copy(). Esto mantiene el audio sonando indefinidamente sin interrupciones.
void loop() {
copier.copy();
}
Ejemplo de código: Bluetooth
Este siguiente código demuestra cómo reproducir audio por Bluetooth en un ESP32 usando el DAC PCM5102A. Utiliza varias librerías para gestionar el streaming de audio y la funcionalidad Bluetooth A2DP (Advanced Audio Distribution Profile). El ESP32 recibe datos de audio por Bluetooth y los saca por la interfaz I2S al convertidor digital-analógico PCM5102A.
/*
www.makerguides.com
Libraries:
- ESP32 Core 3.3.6
- [arduino-audio-tools](https://github.com/pschatzmann/arduino-audio-tools)
Version: 1.2.2
- [arduino-libhelix](https://github.com/pschatzmann/arduino-libhelix)
Version: 0.9.2
- [ESP32-A2DP](https://github.com/pschatzmann/ESP32-A2DP)
Version: 1.8.8
*/
#include "AudioTools.h"
#include "BluetoothA2DPSink.h"
#define DIN_PIN 33 // serial data
#define LRCK_PIN 32 // word select
#define BCLK_PIN 25 // serial clock
I2SStream i2s;
BluetoothA2DPSink a2dp_sink(i2s);
void setup() {
auto config = i2s.defaultConfig();
config.pin_bck = BCLK_PIN;
config.pin_ws = LRCK_PIN;
config.pin_data = DIN_PIN;
i2s.begin(config);
a2dp_sink.start("MyMusic");
}
void loop() { }
Imports
El código comienza incluyendo las librerías necesarias. AudioTools.h proporciona capacidades de streaming de audio, mientras que BluetoothA2DPSink.h gestiona la funcionalidad de Bluetooth A2DP sink, permitiendo que el ESP32 reciba streams de audio desde fuentes Bluetooth como smartphones.
#include "AudioTools.h" #include "BluetoothA2DPSink.h"
Constantes
A continuación, tres constantes definen los pines GPIO usados para la interfaz I2S, que es el protocolo de comunicación entre el ESP32 y el DAC PCM5102A. Estos pines corresponden a la línea de datos serie (DIN_PIN), la línea de selección de palabra o left-right clock (LRCK_PIN), y la línea de bit clock (BCLK_PIN).
#define DIN_PIN 33 // serial data #define LRCK_PIN 32 // word select #define BCLK_PIN 25 // serial clock
Objetos
Se crea un objeto I2SStream llamado i2s para gestionar el stream de datos de audio I2S. Luego, se instancia un objeto BluetoothA2DPSink llamado a2dp_sink, pasando el stream i2s como parámetro. Esto enlaza la entrada de audio Bluetooth directamente a la salida I2S, permitiendo una reproducción de audio fluida.
I2SStream i2s; BluetoothA2DPSink a2dp_sink(i2s);
Función Setup
Dentro de la función setup(), se configura la interfaz I2S. Se obtiene la configuración I2S por defecto mediante i2s.defaultConfig(), y se asignan los pines relevantes para bit clock, selección de palabra y datos según las constantes definidas antes. La interfaz I2S se inicializa con esta configuración usando i2s.begin(config).
Después de configurar la interfaz I2S, se inicia el Bluetooth A2DP sink con el nombre de dispositivo "MyMusic". Esto hace que el ESP32 sea visible como receptor de audio Bluetooth con ese nombre, permitiendo que otros dispositivos se conecten y transmitan audio.
void setup() {
auto config = i2s.defaultConfig();
config.pin_bck = BCLK_PIN;
config.pin_ws = LRCK_PIN;
config.pin_data = DIN_PIN;
i2s.begin(config);
a2dp_sink.start("MyMusic");
}
Abre tu móvil y busca dispositivos Bluetooth para encontrar el dispositivo "MyMusic" y luego empieza a reproducir música.
Función Loop
La función loop() está vacía porque el Bluetooth A2DP sink y el stream I2S gestionan el procesamiento y la reproducción de audio de forma asíncrona. Una vez completada la configuración, el ESP32 escucha continuamente streams de audio Bluetooth y los saca por la interfaz I2S sin requerir código adicional en el loop principal.
void loop() { }
Ejemplo de código: Radio por Internet
Este código muestra cómo construir un reproductor de radio por internet usando un microcontrolador ESP32 y un módulo DAC PCM5102A. Se conecta a una red WiFi, transmite audio MP3 desde una emisora de radio online, decodifica el audio y lo saca por la interfaz I2S al DAC. El código también gestiona los metadatos del stream, como los títulos de las canciones.
/*
www.makerguides.com
Libraries:
- ESP32 Core 3.3.6
- [arduino-audio-tools](https://github.com/pschatzmann/arduino-audio-tools)
Version: 1.2.2
- [arduino-libhelix](https://github.com/pschatzmann/arduino-libhelix)
Version: 0.9.2
*/
#include <Arduino.h>
#include <WiFi.h>
#include <Wire.h>
#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
#include "AudioTools/Communication/HTTP/ICYStream.h"
// PCM5102A
#define DIN_PIN 33 // serial data
#define LRCK_PIN 32 // word select
#define BCLK_PIN 25 // serial clock
#define VOLUME 0.3 // Volume
const char* ssid = "ssid";
const char* password = "pwd";
const char* url = "https://jazz.stream.laut.fm/jazz";
ICYStream icystream;
I2SStream i2s;
VolumeStream volume(i2s);
EncodedAudioStream mp3decode(&volume, new MP3DecoderHelix());
StreamCopy copier(mp3decode, icystream);
void callbackMetadata(MetaDataType type, const char* str, int len) {
Serial.printf("%s: %s\n", toStr(type), str);
}
void setup() {
Serial.begin(115200);
AudioLogger::instance().begin(Serial, AudioLogger::Warning);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
auto config = i2s.defaultConfig(TX_MODE);
config.pin_bck = BCLK_PIN;
config.pin_ws = LRCK_PIN;
config.pin_data = DIN_PIN;
i2s.begin(config);
volume.begin(config);
volume.setVolume(VOLUME);
mp3decode.begin();
icystream.begin(url);
icystream.setMetadataCallback(callbackMetadata);
}
void loop() {
copier.copy();
}
Imports
El código comienza incluyendo varias librerías necesarias para la conectividad WiFi, la salida de audio I2S y la decodificación MP3. Las librerías Arduino.h y WiFi.h proporcionan funciones básicas de Arduino y WiFi. La librería Wire.h se incluye pero no se usa explícitamente aquí. La librería AudioTools y sus componentes relacionados gestionan el streaming, la decodificación y la reproducción de audio.
#include <Arduino.h> #include <WiFi.h> #include <Wire.h> #include "AudioTools.h" #include "AudioTools/AudioCodecs/CodecMP3Helix.h" #include "AudioTools/Communication/HTTP/ICYStream.h"
Constantes y definición de pines
A continuación, el código define los pines usados para la interfaz I2S para comunicarse con el DAC PCM5102A. Estos pines corresponden a los datos serie, selección de palabra (left-right clock) y señales de bit clock. Además, se establece un nivel de volumen como constante de tipo float.
#define DIN_PIN 33 // serial data #define LRCK_PIN 32 // word select #define BCLK_PIN 25 // serial clock #define VOLUME 0.3 // Volume
Las credenciales WiFi y la URL del stream de radio por internet se almacenan como punteros constantes de tipo char.
const char* ssid = "ssid"; const char* password = "pwd"; const char* url = "https://jazz.stream.laut.fm/jazz";
Objetos de streaming de audio
Se crean varios objetos para gestionar la cadena de streaming de audio. El objeto ICYStream gestiona el streaming HTTP de los datos MP3 desde la URL de la radio por internet, mientras que el objeto I2SStream gestiona la comunicación I2S con el DAC. El objeto VolumeStream permite ajustar el volumen de reproducción y está conectado al stream I2S. Y el objeto EncodedAudioStream decodifica los datos MP3 usando el decodificador Helix MP3 y saca el audio decodificado al stream de volumen. Finalmente, el objeto StreamCopy copia los datos de audio decodificados del decodificador MP3 al stream ICY.
ICYStream icystream; I2SStream i2s; VolumeStream volume(i2s); EncodedAudioStream mp3decode(&volume, new MP3DecoderHelix()); StreamCopy copier(mp3decode, icystream);
Función de callback de metadatos
Se define la función callbackMetadata para gestionar los metadatos recibidos del stream de radio por internet, como el título o artista de la canción actual. Imprime el tipo de metadato y su contenido en el monitor serie para depuración o visualización.
void callbackMetadata(MetaDataType type, const char* str, int len) {
Serial.printf("%s: %s\n", toStr(type), str);
}
Función Setup
En la función setup() se inicializa la comunicación serie a 115200 baudios para la salida de depuración. También se inicia el logger de audio para capturar advertencias y errores. El ESP32 intenta conectarse a la red WiFi especificada, reintentando cada 500 milisegundos hasta tener éxito.
Una vez establecida la conexión WiFi, se configura la interfaz I2S en modo transmisión con los pines especificados para bit clock, selección de palabra y datos. El stream I2S y el stream de volumen se inicializan con esta configuración, y el volumen se ajusta al nivel predefinido.
Se inicia el decodificador MP3 y se inicializa el stream ICY con la URL de la radio por internet. Se registra la función de callback de metadatos para recibir y gestionar los metadatos del stream.
void setup() {
Serial.begin(115200);
AudioLogger::instance().begin(Serial, AudioLogger::Warning);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
auto config = i2s.defaultConfig(TX_MODE);
config.pin_bck = BCLK_PIN;
config.pin_ws = LRCK_PIN;
config.pin_data = DIN_PIN;
i2s.begin(config);
volume.begin(config);
volume.setVolume(VOLUME);
mp3decode.begin();
icystream.begin(url);
icystream.setMetadataCallback(callbackMetadata);
}
Función Loop
La función loop() copia continuamente los datos de audio del stream de radio por internet a través del decodificador MP3 y el control de volumen hasta la salida I2S. Esto mantiene la reproducción de audio funcionando indefinidamente.
void loop() {
copier.copy();
}
Ejemplo de código: Reproducir MP3 desde tarjeta SD
El siguiente código muestra cómo reproducir archivos de audio MP3 almacenados en una tarjeta SD usando un microcontrolador ESP32 y el módulo DAC PCM5102A. Utiliza las librerías arduino-audio-tools y arduino-libhelix para gestionar la decodificación y reproducción de audio a través de la interfaz I2S.
/*
www.makerguides.com
Libraries:
- ESP32 Core 3.3.6
- [arduino-audio-tools](https://github.com/pschatzmann/arduino-audio-tools)
Version: 1.2.2
- [arduino-libhelix](https://github.com/pschatzmann/arduino-libhelix)
Version: 0.9.2
*/
#include "AudioTools.h"
#include "AudioTools/Disk/AudioSourceSD.h"
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
// PCM5102A
#define DIN_PIN 33 // serial data
#define LRCK_PIN 32 // word select
#define BCLK_PIN 25 // serial clock
#define VOLUME 0.5 // Volume
#define PATH "/"
#define EXT "mp3"
AudioSourceSD source(PATH, EXT);
I2SStream i2s;
MP3DecoderHelix decoder;
AudioPlayer player(source, i2s, decoder);
void printMetaData(MetaDataType type, const char* str, int len){
Serial.printf("%s: %s\n", toStr(type), str);
}
void setup() {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
auto config = i2s.defaultConfig(TX_MODE);
config.pin_bck = BCLK_PIN;
config.pin_ws = LRCK_PIN;
config.pin_data = DIN_PIN;
i2s.begin(config);
player.setMetadataCallback(printMetaData);
player.setVolume(VOLUME);
player.begin();
}
void loop() {
player.copy();
}
Imports
Al principio, el código incluye varios archivos de cabecera de las librerías de audio. Estos proporcionan las clases y funciones necesarias para leer archivos de audio desde la tarjeta SD, decodificar streams MP3 y sacar audio por I2S.
#include "AudioTools.h" #include "AudioTools/Disk/AudioSourceSD.h" #include "AudioTools/AudioCodecs/CodecMP3Helix.h"
Constantes y definición de pines
El código define los pines usados para conectar el ESP32 al DAC PCM5102A. Estos pines corresponden a las señales I2S: datos serie (DIN), selección de palabra (LRCK) y reloj serie (BCLK). Además, se establece un nivel de volumen como valor float entre 0.0 y 1.0.
#define DIN_PIN 33 // serial data #define LRCK_PIN 32 // word select #define BCLK_PIN 25 // serial clock #define VOLUME 0.5 // Volume
Las constantes PATH y EXT especifican el directorio raíz y la extensión de los archivos de audio a reproducir, que en este caso son archivos MP3 ubicados en la raíz de la tarjeta SD.
#define PATH "/" #define EXT "mp3"
Objetos de audio
Se instancian varios objetos para gestionar la reproducción de audio. AudioSourceSD gestiona la lectura de archivos de audio desde la tarjeta SD que coincidan con la ruta y extensión especificadas. I2SStream gestiona el stream de salida de audio I2S. MP3DecoderHelix es el decodificador MP3 basado en la librería Helix. Por último, AudioPlayer une estos componentes para coordinar la reproducción.
AudioSourceSD source(PATH, EXT); I2SStream i2s; MP3DecoderHelix decoder; AudioPlayer player(source, i2s, decoder);
Función de callback de metadatos
Se define la función printMetaData() para recibir información de metadatos como artista, título o álbum de los archivos MP3 durante la reproducción. Imprime esta información en el monitor serie usando Serial.printf. La función recibe el tipo de metadato, una cadena con el metadato y su longitud como parámetros.
void printMetaData(MetaDataType type, const char* str, int len){
Serial.printf("%s: %s\n", toStr(type), str);
}
Función Setup
En la función setup() se inicializa la comunicación serie a 115200 baudios para permitir la salida de depuración. El nivel de logging de audio se ajusta a Warning para reducir la verbosidad.
A continuación, se configura la interfaz I2S en modo transmisión. Se obtiene la configuración I2S por defecto y se modifica para asignar los pines definidos anteriormente para bit clock, selección de palabra y datos. El stream I2S se inicia con esta configuración.
El reproductor de audio se configura para usar el callback printMetaData para mostrar metadatos durante la reproducción. El volumen se ajusta al nivel definido y el reproductor se inicia con player.begin().
void setup() {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
auto config = i2s.defaultConfig(TX_MODE);
config.pin_bck = BCLK_PIN;
config.pin_ws = LRCK_PIN;
config.pin_data = DIN_PIN;
i2s.begin(config);
player.setMetadataCallback(printMetaData);
player.setVolume(VOLUME);
player.begin();
}
Función Loop
La función loop() llama continuamente a player.copy(), que procesa los datos de audio leyendo desde la tarjeta SD, decodificando el stream MP3 y enviando las muestras de audio a la salida I2S. Esto mantiene la reproducción de audio funcionando sin problemas.
void loop() {
player.copy();
}
Ejemplo de código: Texto a voz
Este ejemplo de código muestra cómo implementar un sistema de texto a voz (TTS) en un ESP32 usando la API TTS de OpenAI y sacar el audio por un DAC PCM5102A. Los datos de audio se transmiten en formato MP3, se decodifican y se reproducen por la interfaz I2S. El programa se conecta a WiFi, envía texto a la API de OpenAI, recibe el habla sintetizada y la reproduce en tiempo real.
/*
www.makerguides.com
Libraries:
- ESP32 Core 3.3.6
- [arduino-audio-tools](https://github.com/pschatzmann/arduino-audio-tools)
Version: 1.2.2
- [arduino-libhelix](https://github.com/pschatzmann/arduino-libhelix)
Version: 0.9.2
*/
#include <Arduino.h>
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
// PCM5102A
#define DIN_PIN 33 // serial data
#define LRCK_PIN 32 // word select
#define BCLK_PIN 25 // serial clock
// Text to Speech
#define TTS_MODEL "gpt-4o-mini-tts"
#define TTS_VOICE "marin"
#define TTS_VOLUME 0.6
// WiFi credentials
const char* ssid = "ssid";
const char* password = "pwd";
// OpenAI configuration
const char* openaiHost = "api.openai.com";
const int openaiPort = 443;
const char* openaiApiKey = "apikey";
WiFiClientSecure client;
I2SStream i2s;
VolumeStream volume(i2s);
EncodedAudioStream mp3decode(&volume, new MP3DecoderHelix());
StreamCopy copier(mp3decode, client);
void text2speech(const char* text) {
client.setInsecure();
if (!client.connect("api.openai.com", 443)) {
Serial.println("Connection failed");
return;
}
String body = String("{") +
"\"model\":\"" + TTS_MODEL + "\"," +
"\"voice\":\"" + TTS_VOICE + "\"," +
"\"format\":\"mp3\"," +
"\"input\":\"" + text + "\"" +
"}";
client.println("POST /v1/audio/speech HTTP/1.1");
client.println("Host: api.openai.com");
client.println("Authorization: Bearer " + String(openaiApiKey));
client.println("Content-Type: application/json");
client.print("Content-Length: ");
client.println(body.length());
client.println();
client.print(body);
// ---- Skip HTTP headers ----
while (client.connected()) {
String line = client.readStringUntil('\n');
if (line == "\r") break;
}
}
void setup() {
Serial.begin(115200);
AudioLogger::instance().begin(Serial, AudioLogger::Warning);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
auto config = i2s.defaultConfig(TX_MODE);
config.pin_bck = BCLK_PIN;
config.pin_ws = LRCK_PIN;
config.pin_data = DIN_PIN;
i2s.begin(config);
mp3decode.begin();
volume.begin(config);
volume.setVolume(TTS_VOLUME);
text2speech("Hello, how are you doing today?");
}
void loop() {
copier.copy();
}
Imports
El código comienza incluyendo las librerías necesarias. Arduino.h proporciona las funciones principales de Arduino. WiFi.h y WiFiClientSecure.h gestionan la conexión WiFi y la comunicación HTTPS segura. La librería AudioTools y su códec MP3 CodecMP3Helix se usan para el streaming y la decodificación de audio.
#include <Arduino.h> #include <WiFi.h> #include <WiFiClientSecure.h> #include "AudioTools.h" #include "AudioTools/AudioCodecs/CodecMP3Helix.h"
Constantes y definición de pines
Se definen los pines para el DAC PCM5102A para configurar la interfaz I2S. Estos incluyen el pin de datos serie (DIN_PIN), el pin de selección de palabra (LRCK_PIN) y el pin de reloj serie (BCLK_PIN). Además, se establecen constantes para el modelo TTS, la voz y el nivel de volumen. Las credenciales WiFi y los detalles de la API de OpenAI también se declaran como punteros constantes de tipo char.
// PCM5102A #define DIN_PIN 33 // serial data #define LRCK_PIN 32 // word select #define BCLK_PIN 25 // serial clock // Text to Speech #define TTS_MODEL "gpt-4o-mini-tts" #define TTS_VOICE "marin" #define TTS_VOLUME 0.6 // WiFi credentials const char* ssid = "ssid"; const char* password = "pwd"; // OpenAI configuration const char* openaiHost = "api.openai.com"; const int openaiPort = 443; const char* openaiApiKey = "apikey";
Puedes probar otros modelos TTS, como «tts-1» y otras voces como «alloy», «ash», «coral», «echo», «fable», «onyx», «nova», «sage», «shimmer», «marin», «cedar». Para más detalles consulta platform.openai.com/docs/guides/text-to-speech.
Las credenciales WiFi y los detalles de la API de OpenAI también se almacenan como cadenas constantes. Tendrás que reemplazar «ssid» y «pwd» por las credenciales de tu WiFi.
// WiFi credentials const char* ssid = "ssid"; const char* password = "pwd";
También necesitarás obtener una «apikey» de OpenAI. Ve a https://platform.openai.com y regístrate con una dirección de correo electrónico o una cuenta existente de Google o Microsoft.
// OpenAI configuration const char* openaiHost = "api.openai.com"; const int openaiPort = 443; const char* openaiApiKey = "apikey";
Después de verificar tu correo y completar la configuración inicial, inicia sesión en el panel de OpenAI, platform.openai.com/api-keys y busca o crea tu API Key (=SECRET KEY) como se muestra abajo:

La API Key es una cadena única y larga, que empieza por «sk-proj-» y que necesitas para autenticar tus peticiones a la API (ver abajo).
sk-proj-xcA.......................OtDu0U
Eso es todo lo que necesitas para obtener una API key, pero te recomiendo que pongas un límite de uso en tu cuenta. Para más detalles consulta el Vision Chatbot with DFRobot ESP32-S3 AI Camera and OpenAI tutorial.
Objetos de audio y red
Se instancian varios objetos para gestionar el streaming de audio y la comunicación de red. WiFiClientSecure gestiona la conexión HTTPS con el servidor de OpenAI. I2SStream gestiona la salida de audio I2S. El objeto VolumeStream envuelve el stream I2S para controlar el volumen de audio. EncodedAudioStream se usa para decodificar el stream de audio MP3 usando el decodificador Helix MP3. Por último, StreamCopy copia el stream de audio decodificado al cliente de red.
WiFiClientSecure client; I2SStream i2s; VolumeStream volume(i2s); EncodedAudioStream mp3decode(&volume, new MP3DecoderHelix()); StreamCopy copier(mp3decode, client);
Función de texto a voz
La función text2speech() toma una cadena de texto como entrada y la envía a la API TTS de OpenAI para generar audio hablado. Primero configura el cliente para aceptar conexiones SSL inseguras (útil para desarrollo). Luego intenta conectar con el servidor de OpenAI en el puerto 443. Si la conexión falla, imprime un mensaje de error y retorna.
La función construye un cuerpo JSON que contiene el modelo TTS, la voz, el formato de salida (MP3) y el texto de entrada. Envía una petición HTTP POST con los encabezados apropiados, incluyendo el token de autorización con la API key. Tras enviar el cuerpo de la petición, lee y salta los encabezados de la respuesta HTTP para preparar el streaming de los datos de audio.
void text2speech(const char* text) {
client.setInsecure();
if (!client.connect("api.openai.com", 443)) {
Serial.println("Connection failed");
return;
}
String body = String("{") +
"\"model\":\"" + TTS_MODEL + "\"," +
"\"voice\":\"" + TTS_VOICE + "\"," +
"\"format\":\"mp3\"," +
"\"input\":\"" + text + "\"" +
"}";
client.println("POST /v1/audio/speech HTTP/1.1");
client.println("Host: api.openai.com");
client.println("Authorization: Bearer " + String(openaiApiKey));
client.println("Content-Type: application/json");
client.print("Content-Length: ");
client.println(body.length());
client.println();
client.print(body);
// ---- Skip HTTP headers ----
while (client.connected()) {
String line = client.readStringUntil('\n');
if (line == "\r") break;
}
}
Función Setup
En la función setup() se inicializa la comunicación serie para la salida de depuración. El logger de audio se configura para mostrar advertencias. El ESP32 se conecta a la red WiFi especificada, esperando hasta que la conexión esté establecida.
A continuación, se configura la interfaz I2S con los pines definidos anteriormente para bit clock, selección de palabra y salida de datos. El decodificador MP3 y el control de volumen se inicializan con esta configuración, y el volumen se ajusta al nivel definido.
Por último, se llama a la función text2speech() con un texto de saludo de ejemplo, lo que inicia el proceso TTS y comienza el streaming de audio desde la API de OpenAI.
void setup() {
Serial.begin(115200);
AudioLogger::instance().begin(Serial, AudioLogger::Warning);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
auto config = i2s.defaultConfig(TX_MODE);
config.pin_bck = BCLK_PIN;
config.pin_ws = LRCK_PIN;
config.pin_data = DIN_PIN;
i2s.begin(config);
mp3decode.begin();
volume.begin(config);
volume.setVolume(TTS_VOLUME);
text2speech("Hello, how are you doing today?");
}
Función Loop
La función loop() copia continuamente el stream de audio MP3 decodificado desde el servidor de OpenAI a la salida I2S. Esto mantiene la reproducción de audio mientras la conexión permanezca abierta.
void loop() {
copier.copy();
}
Conclusiones
En este proyecto has aprendido cómo reproducir audio usando el ESP32 y el DAC PCM5102A. Hemos explorado los detalles técnicos del módulo PCM5102A y cómo conectarlo al ESP32. También aprendiste a convertir texto a voz, transmitir radio por internet, reproducir archivos MP3 desde una tarjeta SD y reproducir audio por Bluetooth.
Si tienes alguna pregunta, no dudes en dejarla en la sección de comentarios.
¡Feliz cacharreo! ; )

