Skip to Content

Reproduciendo audio con ESP32 y MAX98357

Reproduciendo audio con ESP32 y MAX98357

En este post, aprenderás cómo usar el módulo amplificador MAX98357A con el ESP32 para reproducir audio.

El MAX98357A es un conversor digital a analógico (DAC) compacto con amplificador integrado. Recibe datos de audio digital mediante el protocolo I2S y entrega audio amplificado directamente a un altavoz. Esta combinación simplifica tu montaje de hardware y mejora la calidad del sonido.

A lo largo de este tutorial, aprenderás a generar señales de audio, convertir texto a voz, escuchar radio por internet, reproducir archivos MP3 desde una tarjeta SD y usar audio por Bluetooth.

Overview

Componentes necesarios

Necesitarás al menos un módulo MAX98357A. Si quieres reproducir en estéreo, necesitarás dos módulos MAX98357A. Igualmente, necesitarás dos altavoces de 4-8 Ω y al menos 3 vatios.

Para reproducir archivos MP3 desde una tarjeta SD, además necesitarás una tarjeta SD de al menos 1GB y un módulo lector de tarjetas SD.

Por último, necesitas 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. Preferiblemente consigue un ESP32-S3 con PSRAM si planeas almacenar y reproducir música desde la memoria.

2 x Amplificador MAX98357A

2x Altavoz 4Ω 5W

Lector de tarjetas Micro SD

Tarjeta Micro SD 8GB

ESP32 lite Lolin32

ESP32 lite

USB data cable

Cable de datos USB

Dupont wire set

Set de cables Dupont

Half_breadboard56a

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 módulo amplificador como el MAX98357.

I2S, o Inter-IC Sound, es un estándar de interfaz de bus serie usado 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 precisa de las señales de audio.

En esencia, I2S transfiere datos de audio en Modulación por Impulsos Codificados (PCM) de manera 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).

I2S Timing Diagram
Diagrama de temporización I2S (source)

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-duplex, permitiendo entrada y salida de audio simultáneamente. Puede configurarse para operar 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 amplificador MAX98357A, que actúa como dispositivo esclavo I2S. En la siguiente sección veremos más de cerca el MAX98357A.

Características técnicas del módulo MAX98357A

El módulo MAX98357A es un amplificador digital que acepta entrada I2S directamente. Convierte la señal de audio digital entrante en una señal analógica y la amplifica para alimentar altavoces. Integra un amplificador Clase D de 3,2W con un conversor digital a analógico (DAC) incorporado. La interfaz de audio digital reconoce hasta 35 esquemas de reloj PCM y TDM diferentes, lo que elimina la necesidad de programación por I2C.

Block Diagram of the MAX98357A
Diagrama de bloques del MAX98357A (source)

El MAX98357A soporta muestras de audio de 16, 24 y 32 bits a tasas de muestreo desde 8 kHz hasta 96 kHz. Esta flexibilidad permite una reproducción de audio de alta calidad, adecuada para voz, música y otras aplicaciones de sonido.

El módulo funciona con una sola fuente de alimentación de 3,3V o 5V, lo que lo hace compatible con la mayoría de microcontroladores, incluido el ESP32. Cuenta con un regulador de baja caída integrado y protección contra sobrecalentamiento. La imagen de abajo muestra el frente y reverso de un módulo MAX98357A típico:

Front and Back of the MAX98357A Module
Frente y reverso del módulo MAX98357A

En la entrada, el MAX98357A espera tres señales principales: bit clock (BCLK), word select (LRC) y datos serie (SD). El bit clock sincroniza los bits de datos, mientras que la selección de palabra indica si los datos actuales corresponden al canal izquierdo o derecho. La línea de datos serie transporta las muestras de audio en un flujo continuo.

Functional Diagram of the MAX98357A
Diagrama funcional del MAX98357A (source)

Internamente, el módulo convierte los datos de audio digital entrantes en una señal analógica usando su DAC integrado. Esta señal analógica es amplificada por la etapa de amplificador Clase D, que puede alimentar un altavoz de 4 u 8 Ω con 3 vatios.

El MAX98357A incluye control de ganancia y puede configurarse para producir salida de canal izquierdo, derecho o una mezcla de ambos canales estéreo a través del pin SD. En la siguiente sección hablaremos de estos pines en más detalle.

Pinout del módulo MAX98357A

Un módulo MAX98357A típico tiene pines para la alimentación (Vin, GND), para la interfaz I2S (LRC, BCLK, DIN), para el control de ganancia (GAIN) y para la selección de canal y apagado (SD). La imagen de abajo muestra el pinout:

Pinout of MAX98357A Module
Pinout del módulo MAX98357A

Alimentación

El pin VIN acepta de 3,3V a 5V. El pin GND es la referencia de tierra y debe conectarse a la tierra del ESP32.

El consumo de corriente del MAX98357A para reproducción de audio a volumen moderado suele estar entre 200mA y 400mA. El regulador de voltaje de una placa ESP32 típica es de unos 800mA, pero el ESP32 lite usa un ME6211 de solo 500mA.

Esto significa que puedes alimentar un MAX98357A desde el pin de salida de 3,3V del ESP32, pero es arriesgado, ya que a volumen alto y ganancia máxima la corriente puede llegar hasta 1,5A (a 5V). Por eso, es mejor alimentar el MAX98357A desde una fuente de alimentación externa.

Ten en cuenta que el MAX98357A incluye un limitador de corriente de salida al altavoz de 2,8A. Si la corriente de salida supera este valor, el chip se apagará temporalmente y se reiniciará para protegerse.

Interfaz I2S

El pin LRC significa Left-Right Clock o Word Select. Indica si los datos de audio actuales pertenecen al canal izquierdo o derecho. El ESP32 genera esta señal como parte del protocolo I2S.

El pin BCLK es el Bit Clock. Sincroniza los bits de datos enviados por la línea DIN. El ESP32 también proporciona esta señal de reloj.

El pin DIN es la línea de entrada de datos. Este pin recibe los datos de audio reales desde el ESP32.

Control de ganancia

Puedes controlar la ganancia del MAX98357A conectando el pin de ganancia a VCC o GND directamente o mediante una resistencia de 100K. La siguiente tabla muestra qué conexión resulta en qué ganancia.

Ganancia Conexión
15dB GAIN — 100K — GND
12dB GAIN — GND
9dB Ninguna
6dB GAIN — VCC
3dB GAIN — 100K — VCC

La ganancia de 9dB es la configuración por defecto y no se requiere ninguna conexión.

Control de canal

El pin SD (Shutdown) del MAX98357A te permite apagar el amplificador o seleccionar la salida derecha, izquierda o mixta desde la entrada estéreo. La imagen de abajo muestra el esquema del módulo MAX98357A con el pin SD Mode y la información sobre cómo seleccionar un canal:

Schematics of MAX98357A Module
Esquema del módulo MAX98357A

Si el pin SD no está conectado (por defecto), el amplificador genera una salida mixta de los canales izquierdo y derecho ((L+R)/2). Si el pin SD está conectado a tierra, el amplificador se apaga. De lo contrario, el voltaje en SD determina si se amplifica el canal izquierdo o derecho. La siguiente tabla muestra los voltajes requeridos en el pin SD para activar las diferentes funciones:

Voltaje @ SD Función
< 0.16V Amplificador apagado
0.16 … 0.77V Canal izquierdo y derecho mezclados ((L+R)/2)
0.77 … 1.4V Canal derecho (370KΩ @ 5V, 210KΩ @ 3V3)
> 1.4V Solo canal izquierdo (100kΩ)

Para lograr el voltaje requerido en el pin SD y seleccionar el canal derecho, necesitas conectar el pin SD a VCC mediante una resistencia adecuada. El esquema muestra la siguiente fórmula:

R = (94 * VDD – 100) KΩ

Esto significa que, a 5V necesitas una resistencia de 370KΩ entre SD y 5V, y a 3,3V necesitas una de 210KΩ.

Para seleccionar el canal izquierdo puedes usar una resistencia de 100kΩ a 5V o 3,3V. Y si quieres salida de canal mixto (mono sumado), simplemente deja el pin SD sin conectar.

Datasheet

El siguiente botón enlaza al datasheet del MAX98357A, donde puedes encontrar detalles técnicos adicionales:

Conectar MAX98357A al ESP32

En esta sección aprenderás las diferentes formas de conectar el MAX98357A y los altavoces a un ESP32.

Mono sumado

Empezamos con la configuración más sencilla. Usamos un solo MAX98357A y un solo altavoz para reproducir una señal estéreo mezclada (50% canal izquierdo, 50% canal derecho).

Comienza conectando Vin del MAX98357A a 3,3V del ESP32 y GND a G. Luego conecta los pines I2S como se muestra en la siguiente tabla:

MAX98357A ESP32
Vin 3V3
GND G
LRC 32
BCLK 25
DIN 33

Deja los pines GAIN y SD del MAX98357A sin conectar. Esto generará una mezcla de canal izquierdo y derecho con una ganancia de 9dB.

Al conectar el altavoz, asegúrate de respetar la polaridad correcta y usa un altavoz de 4Ω u 8Ω de al menos 3W. Puedes usar altavoces de mayor potencia, pero no de menor.

La siguiente imagen muestra el cableado completo de un MAX98357A con un ESP32 lite para sonido mono sumado (mezcla) con alimentación a través del pin de 3,3V:

Single MAX98357A with ESP32 at 3.3V for Mono Sound
Un solo MAX98357A con ESP32 a 3,3V para sonido mono

Como se mencionó antes, el MAX98357A puede consumir hasta 1,5A de corriente al reproducir sonido fuerte con ganancia máxima. El pin de 3,3V del ESP32 no puede suministrar tanta corriente y necesitas usar una fuente de alimentación externa. La imagen de abajo muestra cómo conectar una alimentación externa de 5V al circuito:

Single MAX98357A with ESP32 with external 5V for Mono Sound
Un solo MAX98357A con ESP32 y alimentación externa de 5V para sonido mono

Estéreo

Si quieres reproducir sonido estéreo necesitas dos altavoces, y dos MAX98357A (uno por canal) y resistencias para seleccionar el canal izquierdo o derecho. La imagen de abajo muestra el cableado completo:

Two MAX98357A with ESP32 at 3.3V for Stereo Sound
Dos MAX98357A con ESP32 a 3,3V para sonido estéreo

Ambos MAX98357A están conectados en paralelo, usando la misma alimentación y pines I2S que antes. La única diferencia es que el MAX98357A para el canal izquierdo tiene una resistencia de 100KΩ entre SD y 3,3V y el MAX98357A para el canal derecho tiene una de 210KΩ.

Ten en cuenta que el ESP32 debe producir una señal estéreo y el MAX98357A simplemente selecciona el canal izquierdo o derecho de la entrada estéreo dependiendo del voltaje en el pin SD.

Como antes, en vez de alimentar el MAX98357A desde el pin de 3,3V del ESP32, la opción más segura es usar alimentación externa. El diagrama de conexiones muestra cómo usar una fuente de alimentación externa de 5V:

Two MAX98357A with ESP32 with external 5V for Stereo Sound
Dos MAX98357A con ESP32 y alimentación externa de 5V para sonido estéreo

Ten en cuenta que el pin SD del MAX98357A sigue conectado a 3,3V mediante una resistencia de 100KΩ o 210KΩ. También puedes conectar las resistencias a la fuente externa de 5V, pero entonces deberías usar una resistencia de 370KΩ para el canal derecho en vez de la de 210KΩ. La resistencia de 100KΩ para el canal izquierdo puede quedarse igual.

Tarjeta 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 conexiones de abajo muestra cómo conectar un lector de tarjetas SD y el MAX98357A a un ESP32:

Single MAX98357A with ESP32 and SD Card Reader for Mono Sound
Un solo MAX98357A con ESP32 y lector de tarjetas SD para sonido mono

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 estás seguro de cuáles son los pines SPI por defecto de tu ESP32, consulta el Find I2C and SPI default pins tutorial.

Si quieres reproducir sonido estéreo necesitas conectar dos módulos MAX98357A. El siguiente diagrama muestra cómo hacerlo:

Two MAX98357A with ESP32 and SD Card Reader for Stereo Sound
Dos MAX98357A con ESP32 y lector de tarjetas SD para sonido estéreo

Si necesitas más ayuda para conectar el lector de tarjetas SD, consulta nuestro SD Card Module with ESP32 tutorial.

Instalación de librerías

Hay varias librerías de Arduino que puedes usar para generar audio para un dispositivo I2S como el MAX98357A. A continuación, comento brevemente las tres más usadas.

Primero, está la librería ESP8266Audio de Earle F. Philhower, que soporta placas ESP8266, ESP32, Raspberry Pi Pico RP2040 y Pico 2 RP2350.

Luego está la librería ESP32-audioI2S de schreibfaul1. Ten en cuenta que esta librería solo funciona en chips multinúcleo como ESP32, ESP32-S3, ESP32-P4 y tu placa debe tener PSRAM. No funciona en placas ESP32-S2, ESP32-C3.

Por último, está la librería arduino-audio-tools de Phil Schatzmann, que es la más potente y con muchísimas funciones. Es la librería que vamos a usar en este tutorial, pero las otras también valen la pena probarlas.

Instalar core ESP32

A enero de 2026, no pude hacer funcionar la librería arduino-audio-tools con el core ESP32 actual (Versión 3.3.6). Para los ejemplos de este tutorial necesitas bajar el core ESP32 a la Versión 2.0.17.

Suponiendo que ya tienes instalado el core ESP32, bajarlo de versión es fácil. Abre el BOARDS MANAGER, escribe “esp32” en la barra de búsqueda y luego selecciona la versión 2.0.17 para el core “esp32 by Espressif” y haz clic en “UPDATE” como se muestra abajo:

Installing ESP32 Core Version 2.0.17
Instalando ESP32 Core Versión 2.0.17

Si necesitas más ayuda para bajar de versión o instalar el core ESP, consulta el Install ESP32 core in Arduino IDE tutorial.

Instalar la librería arduino-audio-tools

Para instalar la librería arduino-audio-tools ve al 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 necesitamos dos librerías más de Phil Schatzmann: la arduino-libhelix y la ESP32-A2DP. Puedes instalarlas igual. Haz clic en el enlace para ir al repo 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.

Reproducir sonido de prueba

Antes de probar algo complejo, primero vamos a reproducir un sonido de prueba. Esto nos permitirá verificar el cableado del MAX98357A con el ESP32 y que los canales izquierdo y derecho están correctamente seleccionados al reproducir sonido estéreo. Además, este código no depende de ninguna librería y funciona tanto con el core ESP32 actual (3.x) como con el antiguo (2.x).

#include <driver/i2s.h>
#include <math.h>

#define I2S_PORT I2S_NUM_0

// MAX98357
#define MAX_DIN 33   
#define MAX_LRC 32   
#define MAX_BCLK 25  

// Audio parameters
#define SAMPLE_RATE 44100
#define TONE_FREQ 500
#define AMPLITUDE 1000  // Max 32767

// Channels
#define LEFT false
#define RIGHT true

// Buffer size (frames, not samples)
#define BUFFER_LEN 256

// Stereo buffer: Left, Right
int16_t samples[BUFFER_LEN * 2];

void setup() {
  i2s_config_t i2s_config = {
    .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
    .sample_rate = SAMPLE_RATE,
    .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
    .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
    .communication_format = I2S_COMM_FORMAT_I2S,
    .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
    .dma_buf_count = 8,
    .dma_buf_len = BUFFER_LEN,
    .use_apll = false,
    .tx_desc_auto_clear = true,
    .fixed_mclk = 0
  };

  i2s_pin_config_t pin_config = {
    .bck_io_num = MAX_BCLK,
    .ws_io_num = MAX_LRC,
    .data_out_num = MAX_DIN,
    .data_in_num = I2S_PIN_NO_CHANGE
  };

  i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
  i2s_set_pin(I2S_PORT, &pin_config);
}

void loop() {
  static float phase = 0.0;
  const float phaseIncrement = 2.0 * PI * TONE_FREQ / SAMPLE_RATE;

  for (int i = 0; i < BUFFER_LEN; i++) {
    int16_t sound = (int16_t)(AMPLITUDE * sin(phase));
    int16_t silence = 0;

    samples[2 * i] = (LEFT) ? sound : silence;       // Left channel
    samples[2 * i + 1] = (RIGHT) ? sound : silence;  // Right channel

    phase += phaseIncrement;
    if (phase >= 2.0 * PI) phase -= 2.0 * PI;
  }

  size_t bytes_written;
  i2s_write(I2S_PORT, samples, sizeof(samples), &bytes_written, portMAX_DELAY);
}

El código configura el ESP32 como transmisor maestro I2S, genera en tiempo real una señal de audio de onda senoidal y la envía al amplificador para producir sonido en el canal izquierdo, derecho o ambos.

Imports

El código incluye la librería driver/i2s.h, que proporciona las funciones del driver I2S del ESP32 para comunicación de audio. También incluye la librería estándar de matemáticas math.h para usar funciones matemáticas como sin() para generar la forma de onda de audio.

#include <driver/i2s.h>;
#include <math.h>;

Constantes

Se definen varias constantes para configurar la interfaz I2S y los parámetros de audio. I2S_PORT selecciona el número de periférico I2S 0 en el ESP32. Los pines MAX_DIN, MAX_LRC y MAX_BCLK corresponden a las líneas de datos, selección de palabra (left-right clock) y bit clock conectadas al amplificador MAX98357.

Los parámetros de audio incluyen una tasa de muestreo de 44.100 Hz, una frecuencia de tono de 500 Hz y una amplitud de 1000 (dentro del rango de un entero con signo de 16 bits). Lo más importante es que el código también define banderas booleanas LEFT y RIGHT para controlar qué canales de audio emiten sonido.

Por último, BUFFER_LEN define el número de frames de audio por buffer, y un array estéreo samples almacena las muestras de audio intercaladas de los canales izquierdo y derecho.

#define I2S_PORT I2S_NUM_0

// MAX98357
#define MAX_DIN 33   
#define MAX_LRC 32   
#define MAX_BCLK 25  

// Audio parameters
#define SAMPLE_RATE 44100
#define TONE_FREQ 500
#define AMPLITUDE 1000  // Max 32767

// Channels
#define LEFT false
#define RIGHT true

// Buffer size (frames, not samples)
#define BUFFER_LEN 256

// Stereo buffer: Left, Right
int16_t samples[BUFFER_LEN * 2];

Función setup

La función setup() inicializa el driver I2S y configura los pines para la comunicación con el amplificador MAX98357.

Se crea una estructura i2s_config_t para especificar el modo I2S como transmisor maestro, muestras de 16 bits, formato de canal estéreo (derecho e izquierdo) y una tasa de muestreo de 44,1 kHz. También se configuran los parámetros del buffer DMA para una transferencia eficiente de datos.

A continuación, una estructura i2s_pin_config_t asigna los pines GPIO para bit clock (bck_io_num), selección de palabra (ws_io_num) y salida de datos (data_out_num). El pin de entrada de datos no se usa y se pone en I2S_PIN_NO_CHANGE.

Por último, se instala el driver I2S con i2s_driver_install() y se aplica la configuración de pines con i2s_set_pin().

void setup() {
  i2s_config_t i2s_config = {
    .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
    .sample_rate = SAMPLE_RATE,
    .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
    .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
    .communication_format = I2S_COMM_FORMAT_I2S,
    .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
    .dma_buf_count = 8,
    .dma_buf_len = BUFFER_LEN,
    .use_apll = false,
    .tx_desc_auto_clear = true,
    .fixed_mclk = 0
  };

  i2s_pin_config_t pin_config = {
    .bck_io_num = MAX_BCLK,
    .ws_io_num = MAX_LRC,
    .data_out_num = MAX_DIN,
    .data_in_num = I2S_PIN_NO_CHANGE
  };

  i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
  i2s_set_pin(I2S_PORT, &pin_config);
}

Función loop

La función loop() genera continuamente muestras de audio y las envía al periférico I2S para su reproducción.

Una variable estática phase lleva el seguimiento de la posición actual dentro del ciclo de la onda senoidal. El phaseIncrement se calcula en base a la frecuencia de tono deseada y la tasa de muestreo, determinando cuánto avanza la fase por muestra.

Dentro del bucle, el código llena el buffer samples con datos de audio estéreo intercalados. Para cada frame, calcula el seno de la fase actual, lo escala por la amplitud y lo convierte a entero de 16 bits. Dependiendo de las banderas LEFT y RIGHT, el sonido se asigna a los canales izquierdo y/o derecho, mientras que el otro canal se pone en silencio (cero).

La fase se incrementa y se ajusta para mantenerse dentro del rango de 0 a 2π radianes, asegurando una forma de onda continua.

Después de llenar el buffer, la función i2s_write() envía los datos de audio al driver I2S, que los transmite al amplificador. La función bloquea hasta que se escriben todos los bytes, manteniendo una reproducción de audio fluida.

void loop() {
  static float phase = 0.0;
  const float phaseIncrement = 2.0 * PI * TONE_FREQ / SAMPLE_RATE;

  for (int i = 0; i < BUFFER_LEN; i++) {
    int16_t sound = (int16_t)(AMPLITUDE * sin(phase));
    int16_t silence = 0;

    samples[2 * i] = (LEFT) ? sound : silence;       // Left channel
    samples[2 * i + 1] = (RIGHT) ? sound : silence;  // Right channel

    phase += phaseIncrement;
    if (phase >= 2.0 * PI) phase -= 2.0 * PI;
  }

  size_t bytes_written;
  i2s_write(I2S_PORT, samples, sizeof(samples), &bytes_written, portMAX_DELAY);
}

Puedes usar este código para verificar que el sonido estéreo se reproduce correctamente al usar dos módulos MAX98357 y dos altavoces. Si pones la constante LEFT en true y RIGHT en false, solo el altavoz izquierdo debería sonar. De igual forma, puedes comprobar que el canal derecho suena correctamente. Si no es así, revisa el voltaje y las resistencias en el pin SD del MAX98357, que controla el canal.

Para los siguientes ejemplos usaremos la librería arduino-audio-tools, que ocultará todos los detalles de la comunicación I2S y simplificará el código.

Texto a voz

Este siguiente ejemplo muestra cómo convertir texto a voz usando la interfaz I2S con un amplificador MAX98357. Se conecta a WiFi, envía texto a la API de texto a voz (TTS) de OpenAI, recibe un flujo de audio MP3, lo decodifica y lo reproduce a través del amplificador. El código usa la librería arduino-audio-tools para gestionar el streaming y la decodificación de audio.

/*
www.makerguides.com

Libraries:
- ESP32 Core 2.0.17
- [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"

// MAX98357 I2S pins
#define MAX_DIN   33
#define MAX_LRC   32
#define MAX_BCLK  25

// 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  = MAX_BCLK;
  config.pin_ws   = MAX_LRC;
  config.pin_data = MAX_DIN;
  i2s.begin(config);

  mp3decode.begin();
  volume.begin(config);
  volume.setVolume(TTS_VOLUME);

  text2speech("Hello, this a test for text to speech.");
}

void loop() {
  copier.copy();
}

Imports

El código comienza incluyendo varias librerías. Arduino.h es la librería principal de Arduino. WiFi.h y WiFiClientSecure.h proporcionan conectividad WiFi y cliente HTTPS seguro. La librería AudioTools y su códec MP3 CodecMP3Helix se usan para streaming y 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

A continuación, se definen los pines usados para la interfaz I2S hacia el amplificador MAX98357. Estos pines corresponden a la entrada de datos (MAX_DIN), selección de palabra o left-right clock (MAX_LRC) y bit clock (MAX_BCLK).

// MAX98357 I2S pins
#define MAX_DIN   33
#define MAX_LRC   32
#define MAX_BCLK  25

Además, se establecen constantes para el modelo TTS, la voz y el nivel de volumen.

// Text to Speech
#define TTS_MODEL "gpt-4o-mini-tts"
#define TTS_VOICE "marin"
#define TTS_VOLUME 0.6

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 guardan 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 un correo electrónico o una cuenta de Google o Microsoft existente.

// 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:

OpenAI API keys
Claves API de OpenAI

La API Key es una cadena única y larga, que empieza por «sk-proj-«, necesaria 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 también. 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 la API de OpenAI. I2SStream gestiona la salida de audio I2S. VolumeStream envuelve el stream I2S para controlar el volumen de audio. EncodedAudioStream decodifica los datos de audio MP3 usando el decodificador Helix MP3. Finalmente, StreamCopy copia el stream de audio decodificado desde el cliente de red a la salida de audio.

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() envía una cadena de texto a la API TTS de OpenAI y prepara el stream de audio para su reproducción. Primero configura el cliente para aceptar certificados inseguros (ú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 especificando 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 la autorización usando la API key. Tras enviar el cuerpo de la petición, lee y salta los encabezados de respuesta HTTP para posicionar el stream del cliente al inicio de los datos de audio MP3.

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

La función setup() inicializa la comunicación serie para depuración y configura el logger de audio para mostrar advertencias. Luego conecta a la red WiFi especificada, esperando hasta que la conexión se establezca.

Una vez conectado el WiFi, se configura la interfaz I2S en modo transmisión con los pines definidos antes. Se inicializan el stream I2S, el decodificador MP3 y el control de volumen. El volumen se ajusta al nivel predefinido.

Por último, se llama a la función text2speech() con una cadena de texto de ejemplo para empezar a transmitir y reproducir la voz sintetizada.

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  = MAX_BCLK;
  config.pin_ws   = MAX_LRC;
  config.pin_data = MAX_DIN;
  i2s.begin(config);

  mp3decode.begin();
  volume.begin(config);
  volume.setVolume(TTS_VOLUME);

  text2speech("Hello, this a test for text to speech.");
}

Función loop

La función loop() copia continuamente datos del stream del decodificador MP3 a la salida de audio I2S. Esto mantiene la reproducción de audio mientras haya datos disponibles del cliente de red.

void loop() {
  copier.copy();
}

Radio por internet

Este ejemplo muestra cómo implementar una radio web sencilla. Se conecta a una red WiFi, transmite radio por internet en formato MP3, decodifica el audio, ajusta el volumen y saca el sonido por el amplificador digital MAX98357.

/*
www.makerguides.com

Libraries:
- ESP32 Core 2.0.17
- [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"

// MAX98357
#define MAX_DIN 33   // serial data
#define MAX_LRC 32   // word select
#define MAX_BCLK 25  // serial clock
#define MAX_VOL 0.5  // 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 = MAX_BCLK;
  config.pin_ws = MAX_LRC;
  config.pin_data = MAX_DIN;

  i2s.begin(config);
  volume.begin(config);
  volume.setVolume(MAX_VOL);
  mp3decode.begin();
  icystream.begin(url);
  icystream.setMetadataCallback(callbackMetadata);
}

void loop() {
  copier.copy();
}

Imports

El código comienza incluyendo las librerías necesarias para conectividad WiFi, comunicación I2C y procesamiento de audio. Las librerías Arduino.h y WiFi.h proporcionan funciones básicas de Arduino y WiFi. La librería Wire.h se incluye para comunicación I2C, que a menudo se usa para controlar periféricos. 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

A continuación, se definen los pines para el amplificador MAX98357. Estos pines corresponden a las señales I2S: MAX_DIN para la entrada de datos serie, MAX_LRC para la selección de palabra (left-right clock) y MAX_BCLK para el reloj serie. El volumen se establece como un valor flotante entre 0 y 1, donde MAX_VOL es 0.5, representando el 50% de volumen.

#define MAX_DIN 33   // serial data
#define MAX_LRC 32   // word select
#define MAX_BCLK 25  // serial clock
#define MAX_VOL 0.5  // Volume

Credenciales WiFi y URL del stream

Las credenciales de la red WiFi se guardan en las constantes ssid y password. La constante url contiene la dirección del stream de radio por internet a reproducir, en este caso un stream de jazz.

const char* ssid = "ssid";
const char* password = "pwd";
const char* url = "https://jazz.stream.laut.fm/jazz";

Aquí tienes algunas URLs más de streams de radio por internet que puedes probar:

"https://jazz.stream.laut.fm/jazz"
"http://vis.media-ice.musicradio.com/CapitalMP3";
"http://stream.srg-ssr.ch/m/rsj/mp3_128"
"http://stream.live.vc.bbcmedia.co.uk/bbc_world_service"
"http://icecast.omroep.nl/radio1-bb-mp3"
"http://stream-02-eu.relaxingjazz.com/stream/1/"

Objetos de audio

Se instancian varios objetos para gestionar la cadena de audio. El objeto ICYStream gestiona el streaming HTTP de la radio por internet y la interfaz de salida de audio I2S. El objeto VolumeStream envuelve el stream I2S para controlar el volumen de audio. Y el objeto EncodedAudioStream decodifica los datos MP3 usando el códec MP3DecoderHelix. Por último, 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

La función callbackMetadata() se define para manejar los metadatos recibidos del stream de radio por internet, como títulos de canciones o información del artista. Imprime el tipo de metadato y el contenido en el monitor serie para depuración o informació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 permitir el registro y la depuración. El logger de audio se configura para mostrar advertencias y mensajes superiores en el monitor serie.

El ESP32 intenta conectarse a la red WiFi especificada, comprobando el estado de la conexión cada 500 milisegundos hasta que se conecta.

Después de conectar, la configuración I2S se obtiene usando el modo de transmisión por defecto. Los pines I2S se asignan a las constantes definidas previamente para bit clock, selección de palabra y entrada de datos. La interfaz I2S y el control de volumen se inicializan con esta configuración, y el volumen se ajusta al 50%.

Se inicia el decodificador MP3 y el stream de radio por internet se inicializa con la URL proporcionada. Se registra la función de callback de metadatos para manejar los metadatos entrantes durante la reproducción.

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 = MAX_BCLK;
  config.pin_ws = MAX_LRC;
  config.pin_data = MAX_DIN;

  i2s.begin(config);
  volume.begin(config);
  volume.setVolume(MAX_VOL);
  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 controlador de volumen hasta la salida I2S. Este proceso mantiene la reproducción de audio funcionando indefinidamente.

void loop() {
  copier.copy();
}

Si quieres añadir más funciones como un controlador de volumen, consulta nuestro Playing Audio with ESP32 and PCM5102A tutorial. Y si quieres añadir una pantalla, consulta el tutorial Internet Radio with ESP32 and MAX 98357A.

Reproducir MP3 desde tarjeta SD

Este ejemplo muestra cómo reproducir archivos de audio MP3 almacenados en una tarjeta SD usando un ESP32, el amplificador I2S MAX98357 y la librería AudioTools. El código inicializa el hardware de audio, configura el decodificador MP3 y transmite continuamente los datos de audio al amplificador.

/*
www.makerguides.com

Libraries:
- ESP32 Core 2.0.17
- [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"

// MAX98357
#define MAX_DIN 33   
#define MAX_LRC 32   
#define MAX_BCLK 25  

#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 cfg = i2s.defaultConfig(TX_MODE);
  cfg.pin_bck = MAX_BCLK;  
  cfg.pin_ws = MAX_LRC;    
  cfg.pin_data = MAX_DIN;    
  i2s.begin(cfg);

  //source.setFileFilter("*Bob Dylan*");
  player.setMetadataCallback(printMetaData);
  player.setVolume(0.4);
  player.begin();
}

void loop() {
  player.copy();
}

Imports

El código comienza incluyendo los archivos de cabecera de la librería AudioTools. Estos proporcionan las clases y funciones necesarias para gestionar fuentes de audio, decodificar archivos MP3 y transmitir audio por I2S.

#include "AudioTools.h"
#include "AudioTools/Disk/AudioSourceSD.h"
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"

Constantes

A continuación, se definen los pines conectados al amplificador MAX98357. Estos especifican la entrada de datos I2S (MAX_DIN), selección de palabra o left-right clock (MAX_LRC) y bit clock (MAX_BCLK) en el ESP32.

#define MAX_DIN 33   
#define MAX_LRC 32   
#define MAX_BCLK 25  

Además, se establecen constantes para la ruta de la fuente de audio y la extensión de archivo. Aquí, PATH es el directorio raíz de la tarjeta SD y EXT especifica que solo se tendrán en cuenta archivos MP3.

#define PATH "/"
#define EXT "mp3"

Objetos

Se instancian varios objetos para gestionar la cadena de reproducción de audio. AudioSourceSD representa la fuente de audio de la tarjeta SD, filtrando archivos por la ruta y extensión especificadas. I2SStream gestiona el stream de salida de audio I2S. MP3DecoderHelix es el decodificador MP3 basado en el códec Helix. Por último, AudioPlayer une estos componentes para gestionar la reproducción.

AudioSourceSD source(PATH, EXT);
I2SStream i2s;
MP3DecoderHelix decoder;
AudioPlayer player(source, i2s, decoder);

Función de callback de metadatos

La función printMetaData() se define para manejar información de metadatos como artista o título de la pista. Recibe el tipo de metadato y la cadena, y la imprime en la consola serie para depuración o información.

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 el registro. También se inicia el logger de AudioTools con nivel de advertencia para capturar mensajes importantes.

La configuración I2S se obtiene de los ajustes por defecto para el modo transmisión. Los pines para bit clock, selección de palabra y datos se asignan a las constantes definidas previamente correspondientes a las conexiones del MAX98357. El stream I2S se inicializa con esta configuración.

Opcionalmente, se puede establecer un filtro de archivos en la fuente de audio para reproducir solo archivos que coincidan con un patrón (comentado en este ejemplo). El callback de metadatos se asigna a la función printMetaData() para recibir metadatos durante la reproducción. El volumen se ajusta al 40% para controlar la salida. Por último, se inicia el reproductor de audio.

void setup() {
  Serial.begin(115200);
  AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);

  auto cfg = i2s.defaultConfig(TX_MODE);
  cfg.pin_bck = MAX_BCLK;  
  cfg.pin_ws = MAX_LRC;    
  cfg.pin_data = MAX_DIN;    
  i2s.begin(cfg);

  //source.setFileFilter("*Bob Dylan*");
  player.setMetadataCallback(printMetaData);
  player.setVolume(0.4);
  player.begin();
}

Función loop

La función loop() llama continuamente a player.copy(), que gestiona el streaming de audio desde la tarjeta SD a través del decodificador y por I2S al amplificador. Esto mantiene la reproducción de audio funcionando sin bloquear otros procesos.

void loop() {
  player.copy();
}

Si quieres añadir más funciones como un controlador de volumen y botones para saltar pistas, consulta el Playing Audio with ESP32 and PCM5102A tutorial.

Reproducir audio por Bluetooth

Este ejemplo muestra cómo transmitir audio por Bluetooth. El código configura la interfaz I2S con pines específicos e inicializa un receptor Bluetooth A2DP, permitiendo que el ESP32 reciba y reproduzca audio desde dispositivos Bluetooth.

/*
www.makerguides.com

Libraries:
- ESP32 Core 2.0.17
- [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 MAX_DIN 33   // serial data
#define MAX_LRC 32   // word select
#define MAX_BCLK 25  // serial clock

I2SStream i2s;
BluetoothA2DPSink a2dp_sink(i2s);

void setup() {
  auto cfg = i2s.defaultConfig();
  cfg.pin_bck = MAX_BCLK;
  cfg.pin_ws = MAX_LRC;
  cfg.pin_data = MAX_DIN;
  i2s.begin(cfg);

  a2dp_sink.start("MyMusic");
}

void loop() { }

Imports

El código comienza incluyendo dos librerías importantes. La librería AudioTools.h proporciona herramientas para gestionar streams de audio y configurar la interfaz I2S. La librería BluetoothA2DPSink.h permite que el ESP32 actúe como receptor Bluetooth A2DP, es decir, puede recibir streams de audio desde fuentes Bluetooth como smartphones.

#include "AudioTools.h"
#include "BluetoothA2DPSink.h"

Constantes

A continuación, se definen tres constantes para especificar los pines GPIO usados para la interfaz I2S. Estos pines conectan el ESP32 al amplificador MAX98357. MAX_DIN es el pin de entrada de datos serie, MAX_LRC es el pin de selección de palabra o left-right clock, y MAX_BCLK es el pin de reloj serie.

#define MAX_DIN 33   // serial data
#define MAX_LRC 32   // word select
#define MAX_BCLK 25  // serial clock

Objetos

Se crea un objeto I2SStream llamado i2s para gestionar el stream de audio I2S. Luego, se instancia un objeto BluetoothA2DPSink llamado a2dp_sink, pasándole el objeto i2s. Esta configuración enlaza la entrada de audio Bluetooth directamente a la salida I2S, permitiendo la reproducción de audio sin interrupciones a través del amplificador.

I2SStream i2s;
BluetoothA2DPSink a2dp_sink(i2s);

Función setup

Dentro de la función setup(), se configura e inicia la interfaz I2S. Primero, se obtiene la configuración I2S por defecto llamando a i2s.defaultConfig(). Luego, se asignan los pines para bit clock (pin_bck), selección de palabra (pin_ws) y entrada de datos (pin_data) a las constantes definidas previamente. Finalmente, la interfaz I2S se inicializa con esta configuración llamando a i2s.begin(cfg).

Después de configurar I2S, se inicia el receptor Bluetooth A2DP con el nombre de dispositivo "MyMusic". Este nombre aparecerá cuando otros dispositivos Bluetooth busquen receptores de audio disponibles.

void setup() {
  auto cfg = i2s.defaultConfig();
  cfg.pin_bck = MAX_BCLK;
  cfg.pin_ws = MAX_LRC;
  cfg.pin_data = MAX_DIN;
  i2s.begin(cfg);

  a2dp_sink.start("MyMusic");
}

Para probarlo, abre tu móvil, busca «dispositivos conectados» o «dispositivos Bluetooth», busca el dispositivo «MyMusic», conéctate a él y luego reproduce música. Deberías escucharla a través de tu ESP32 y MAX98357.

Función loop

La función loop() está vacía porque todo el streaming y la reproducción de audio se gestionan de forma asíncrona por el receptor Bluetooth A2DP y la interfaz I2S. Una vez iniciado, el ESP32 escucha continuamente streams de audio Bluetooth y los saca por I2S al amplificador sin requerir más código en el bucle principal.

void loop() { }

Conclusiones

En este proyecto, aprendiste cómo reproducir audio usando el ESP32 y el amplificador MAX98357. Vimos los detalles técnicos del módulo MAX98357A y cómo conectarlo al ESP32 para sonido mono o estéreo. También aprendiste a convertir texto a voz, escuchar radio por internet, reproducir archivos MP3 desde una tarjeta SD y reproducir audio por Bluetooth.

Si quieres añadir más funciones como un controlador de volumen y botones para saltar pistas, consulta nuestro Playing Audio with ESP32 and PCM5102A tutorial. Igualmente, si necesitas más información sobre el módulo lector de tarjetas SD usado aquí, échale un vistazo al SD Card Module with ESP32 tutorial.

Para un sonido mejor y más potente puedes usar el DAC PCM5102A y añadir un amplificador. Consulta los siguientes tutoriales para más información:

Si tienes alguna pregunta, siéntete libre de dejarla en los comentarios.

¡Feliz cacharreo ; )

FAQ

P: ¿Qué es el MAX98357A y por qué debería usarlo?

El MAX98357A es un amplificador de audio digital con DAC integrado, lo que significa que toma audio digital directamente del ESP32 usando I2S y entrega una señal ya amplificada que puede alimentar un altavoz sin necesidad de un amplificador extra, haciendo el circuito más simple y mejorando la calidad de sonido respecto al DAC interno del ESP32.

P: ¿Cómo se conecta el MAX98357A al ESP32?

El módulo usa tres señales I2S más alimentación.

Cableado típico:

ESP32_3V3 or 5V ----> VIN
ESP32_GND ---------> GND

ESP32_GPIO25 -----> BCLK
ESP32_GPIO32 -----> LRC
ESP32_GPIO33 -----> DIN

El ESP32 actúa como maestro I2S y envía los datos de audio, mientras el MAX98357A los recibe y los convierte en sonido.

P: ¿Puedo conectar un altavoz directamente al MAX98357A?

Sí, porque el MAX98357A ya incluye una etapa de amplificación, así que puedes conectar un altavoz directamente.

SPK+ ---- Speaker ---- SPK-

Los altavoces típicos son de 4Ω a 8Ω, 3W o más. El amplificador puede entregar unos 3W de potencia, suficiente para altavoces pequeños.

P: ¿Cómo obtengo sonido estéreo?

El MAX98357A es mono, así que para estéreo necesitas dos módulos.

ESP32 --> 2x MAX98357A --> 2x Speakers

Ambos módulos comparten las mismas señales I2S, pero usan resistencias para seleccionar los canales izquierdo y derecho.

SD -- 100kΩ -- 3.3V (left channel)
SD -- 210kΩ -- 3.3V (right channel)

Así, cada amplificador reproduce un canal.

P: ¿Qué fuente de alimentación debo usar?

El módulo funciona con 3,3V o 5V, pero la alimentación es importante para un buen sonido. A volumen alto, el módulo puede consumir mucha corriente, así que alimentarlo desde el pin de 3,3V del ESP32 a menudo no es suficiente y puede causar distorsión o reinicios.

P: ¿Cómo puedo mejorar la calidad de sonido con filtrado de alimentación?

Una alimentación limpia es fundamental, porque el ruido afecta directamente la salida de audio. Puedes añadir condensadores:

VIN -- 100nF -- GND
VIN -- 100µF -- GND

El condensador pequeño elimina el ruido de conmutación rápido, mientras que el grande suaviza el rizado de voltaje y previene caídas durante picos de audio fuertes.

Además puedes usar un condensador de filtrado:

5V -- 10Ω --+-- AMP_VIN
|
220µF
|
GND

Esto reduce el ruido de USB o reguladores conmutados.

P: ¿Debo usar una fuente de alimentación externa?

Sí, especialmente para volumen alto, porque el MAX98357A puede consumir corrientes altas al reproducir audio fuerte, y el regulador del ESP32 puede no soportarlo de forma fiable.

External 5V ----> MAX98357A
ESP32_GND ------> Shared GND

Esto mejora la estabilidad y reduce la distorsión.

P: ¿Cómo puedo aumentar el volumen?

El volumen depende de tres factores principales: voltaje de alimentación, ganancia del amplificador y tipo de altavoz. Para aumentar el volumen:

  • Usa 5V en vez de 3,3V
  • Usa un altavoz de menor impedancia (4Ω en vez de 8Ω)

Un altavoz de 4Ω consume más potencia y produce más volumen, pero también aumenta la carga sobre el amplificador.

P: ¿Qué es el pin GAIN y cómo afecta al sonido?

El pin GAIN ajusta el nivel de ganancia del amplificador.

GAIN -- GND (lower gain)
GAIN -- VCC (higher gain)
GAIN -- FLOAT (default)

Una ganancia mayor aumenta el volumen pero también puede aumentar el ruido y la distorsión, así que a menudo es mejor empezar con ganancia baja y ajustar por software.

P: ¿Por qué escucho ruido o siseo incluso cuando no hay audio?

El ruido puede venir de varias fuentes como rizado de alimentación, mala conexión a tierra o interferencias del ESP32. Soluciones comunes:

  • Añade condensadores de desacoplo
  • Usa una fuente de alimentación externa limpia
  • Mantén los cables cortos

P: ¿Qué prácticas de cableado mejoran la calidad de sonido?

Un buen cableado es muy importante, especialmente para audio digital y amplificadores conmutados. Mantén los cables cortos:

ESP32 --> MAX98357A (short lines)

y usa conexión a tierra en estrella:

ESP32_GND ----+---- AMP_GND
|
POWER_GND

Evita pasar los cables de altavoz cerca de los de señal, porque las señales de conmutación de alta corriente pueden introducir ruido.

P: ¿Qué formatos de audio y funciones se soportan?

El MAX98357A soporta los formatos de audio digital típicos usados con ESP32.

  • Audio de 16, 24 o 32 bits
  • Tasas de muestreo de 8 kHz a 96 kHz