Skip to Content

Reproduzir Áudio com ESP32 e MAX98357

Reproduzir Áudio com ESP32 e MAX98357

Neste artigo, vais aprender a usar o módulo amplificador MAX98357A com o ESP32 para reproduzir áudio.

O MAX98357A é um conversor digital-analógico (DAC) compacto com amplificador integrado. Recebe dados de áudio digitais através do protocolo I2S e envia áudio amplificado diretamente para uma coluna. Esta combinação simplifica a montagem do hardware e melhora a qualidade do som.

Ao longo deste tutorial, vais aprender a gerar sinais de áudio, converter texto em fala, fazer streaming de rádio da internet, reproduzir ficheiros MP3 a partir de um cartão SD e usar áudio por Bluetooth.

Overview

Componentes Necessários

Vais precisar de pelo menos um módulo MAX98357A. Se quiseres som estéreo, precisas de dois módulos MAX98357A. Da mesma forma, vais precisar de duas colunas de 4-8 Ω e pelo menos 3 Watts.

Para reproduzir ficheiros MP3 a partir de um cartão SD, vais precisar ainda de um cartão SD com pelo menos 1GB e de um módulo leitor de cartões SD.

Por fim, precisas de um ESP32, uma breadboard e alguns cabos. Usei um ESP32 lite, mas a maioria das outras placas ESP32 também deve funcionar. Preferencialmente, usa um ESP32-S3 com PSRAM se planeias guardar e reproduzir música a partir da memória.

2 x MAX98357A Amplificador

2x Coluna 4Ω 5W

Leitor de Cartão Micro SD

Cartão Micro SD 8GB

ESP32 lite Lolin32

ESP32 lite

USB data cable

Cabo de Dados USB

Dupont wire set

Conjunto de Cabos 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.

O Protocolo de Áudio I2S

Vamos começar com uma breve introdução ao protocolo I2S, usado para transferir dados de áudio digitalmente de um ESP32 para um módulo amplificador como o MAX98357.

I2S, ou Inter-IC Sound, é um padrão de interface de bus série usado para ligar dispositivos de áudio digitais. Foi introduzido pela Philips nos anos 80 para simplificar a transmissão de dados de áudio entre circuitos integrados. Ao contrário de protocolos como SPI ou I2C, o I2S foi desenhado especificamente para aplicações de áudio, garantindo temporização e sincronização precisas dos fluxos de áudio.

No essencial, o I2S transfere dados de áudio em Modulação por Código de Pulsos (PCM) de forma síncrona. O protocolo usa três sinais principais: o relógio série (SCK), a seleção de palavra (WS) e os dados série (SD). O relógio série pulsa à taxa de bits, ditando quando os bits são enviados. O sinal de seleção de palavra alterna para indicar se os dados atuais correspondem ao canal de áudio esquerdo ou direito. Por fim, a linha de dados série transporta os bits de áudio reais, transmitindo primeiro o bit mais significativo (MSB).

I2S Timing Diagram
Diagrama de Temporização I2S (source)

Normalmente, os dados de áudio são enviados em palavras de 16 ou 24 bits, mas o protocolo pode suportar outras profundidades de bits dependendo do hardware.

O periférico I2S do ESP32 suporta comunicação full-duplex, permitindo entrada e saída de áudio em simultâneo. Pode ser configurado para funcionar em modo master ou slave. Quando atua como master, o ESP32 gera os sinais de relógio e seleção de palavra. Esta é a configuração mais comum ao ligar ao amplificador MAX98357A, que funciona como dispositivo slave I2S. Na próxima secção vamos analisar o MAX98357A com mais detalhe.

Características Técnicas do Módulo MAX98357A

O módulo MAX98357A é um amplificador digital que aceita entrada I2S diretamente. Converte o fluxo de áudio digital recebido num sinal analógico e amplifica-o para alimentar colunas. Integra um amplificador Classe-D de 3,2W com conversor digital-analógico (DAC) incorporado. A interface de áudio digital reconhece até 35 esquemas de relógio PCM e TDM diferentes, eliminando a necessidade de programação I2C.

Block Diagram of the MAX98357A
Diagrama de Blocos do MAX98357A (source)

O MAX98357A suporta amostras de áudio de 16, 24 e 32 bits, com taxas de amostragem de 8 kHz até 96 kHz. Esta flexibilidade permite reprodução de áudio de alta qualidade, adequada para voz, música e outras aplicações sonoras.

O módulo funciona com uma única alimentação de 3,3V ou 5V, tornando-o compatível com a maioria dos microcontroladores, incluindo o ESP32. Tem regulador de baixa queda integrado e proteção contra sobreaquecimento. A imagem abaixo mostra a frente e o verso de um módulo MAX98357A típico:

Front and Back of the MAX98357A Module
Frente e Verso do Módulo MAX98357A

No lado da entrada, o MAX98357A espera três sinais principais: bit clock (BCLK), word select (LRC) e dados série (SD). O bit clock sincroniza os bits de dados, enquanto o word select indica se os dados atuais correspondem ao canal esquerdo ou direito. A linha de dados série transporta as amostras de áudio num fluxo contínuo.

Functional Diagram of the MAX98357A
Diagrama Funcional do MAX98357A (source)

Internamente, o módulo converte os dados de áudio digitais recebidos num sinal analógico usando o DAC integrado. Este sinal analógico é depois amplificado pela etapa Classe-D, que alimenta uma coluna de 4 ou 8 Ω com 3 Watts.

O MAX98357A inclui controlo de ganho e pode ser configurado para produzir canal esquerdo, direito ou uma saída mista do sinal estéreo através do pino SD. Na secção seguinte vamos falar destes pinos com mais detalhe.

Pinout do Módulo MAX98357A

Um módulo MAX98357A típico tem pinos para alimentação (Vin, GND), para a interface I2S (LRC, BCLK, DIN), para controlo de ganho (GAIN) e para seleção de canal e shutdown (SD). A imagem abaixo mostra o pinout:

Pinout of MAX98357A Module
Pinout do Módulo MAX98357A

Alimentação

O pino VIN aceita 3,3V a 5V. O pino GND é a referência de terra e deve ser ligado ao GND do ESP32.

O consumo típico do MAX98357A para reprodução de áudio a volume moderado é entre 200mA e 400mA. O regulador de tensão de uma placa ESP32 típica fornece cerca de 800mA, mas o ESP32 lite usa um ME6211 com apenas 500mA.

Isto significa que podes alimentar um MAX98357A a partir do pino de 3,3V do ESP32, mas é arriscado, pois em volume alto e ganho máximo a corrente pode chegar a 1,5A (a 5V). Por isso, é melhor alimentar o MAX98357A com uma fonte externa.

Nota que o MAX98357A inclui um limitador de corrente de saída para a coluna de 2,8A. Se a corrente de saída exceder este valor, o chip desliga-se temporariamente e reinicia para se proteger.

Interface I2S

O pino LRC significa Left-Right Clock ou Word Select. Indica se os dados de áudio atuais pertencem ao canal esquerdo ou direito. O ESP32 gera este sinal como parte do protocolo I2S.

O pino BCLK é o Bit Clock. Sincroniza os bits de dados enviados pela linha DIN. O ESP32 também fornece este sinal de relógio.

O pino DIN é a linha de entrada de dados. Este pino recebe os dados de áudio reais do ESP32.

Controlo de Ganho

Podes controlar o ganho do MAX98357A ligando o pino GAIN a VCC ou GND diretamente ou através de uma resistência de 100K. A tabela seguinte mostra que ligação resulta em que ganho.

Ganho Ligação
15dB GAIN — 100K — GND
12dB GAIN — GND
9dB Nenhum
6dB GAIN — VCC
3dB GAIN — 100K — VCC

O ganho de 9dB é a configuração por defeito e não é necessário fazer ligação nenhuma.

Controlo de Canal

O pino SD (Shutdown) do MAX98357A permite desligar o amplificador ou selecionar o canal direito, esquerdo ou uma saída mista do sinal estéreo. A imagem abaixo mostra o esquema do módulo MAX98357A com o pino SD Mode e informação sobre como selecionar o canal:

Schematics of MAX98357A Module
Esquema do Módulo MAX98357A

Se o pino SD não estiver ligado (por defeito), o amplificador gera uma saída mista dos canais esquerdo e direito ((L+R)/2). Se o pino SD estiver ligado à terra, o amplificador desliga-se. Caso contrário, a tensão no SD determina se é amplificado o canal esquerdo ou direito. A tabela seguinte mostra as tensões necessárias no pino SD para ativar as diferentes funções:

Tensão @ SD Função
< 0.16V Amplificador desligado
0.16 … 0.77V Canais esquerdo e direito misturados ((L+R)/2)
0.77 … 1.4V Canal direito (370KΩ @ 5V, 210KΩ @ 3V3)
> 1.4V Só canal esquerdo (100kΩ)

Para obter a tensão necessária no pino SD para selecionar o canal direito, tens de ligar o pino SD ao VCC através de uma resistência adequada. O esquema mostra a seguinte fórmula:

R = (94 * VDD – 100) KΩ

Isto significa que, a 5V, precisas de uma resistência de 370KΩ entre SD e 5V e, a 3,3V, precisas de uma resistência de 210KΩ.

Para selecionar o canal esquerdo podes usar uma resistência de 100kΩ a 5V ou 3,3V. E se quiseres saída mista (mono somado), basta deixar o pino SD desligado.

Datasheet

O botão seguinte liga ao datasheet do MAX98357A, onde podes encontrar mais detalhes técnicos:

Ligar o MAX98357A ao ESP32

Nesta secção vais aprender as diferentes formas de ligar o MAX98357A e as colunas a um ESP32.

Mono Somado

Começamos com a configuração mais simples. Usamos um único MAX98357A e uma coluna para reproduzir um sinal estéreo misturado (50% canal esquerdo, 50% canal direito).

Começa por ligar o Vin do MAX98357A ao 3.3V do ESP32 e o GND ao G. Depois liga os pinos I2S conforme mostrado na tabela seguinte:

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

Deixa os pinos GAIN e SD do MAX98357A desligados. Assim, será gerada uma mistura dos canais esquerdo e direito com ganho de 9dB.

Ao ligar a coluna, verifica a polaridade correta e usa uma coluna de 4Ω ou 8Ω com pelo menos 3W. Podes usar colunas com mais potência, mas não com menos.

A imagem seguinte mostra toda a cablagem de um MAX98357A com um ESP32 lite para som mono misturado, com alimentação pelo pino de 3.3V:

Single MAX98357A with ESP32 at 3.3V for Mono Sound
MAX98357A único com ESP32 a 3.3V para Som Mono

Como referido antes, o MAX98357A pode consumir até 1.5A quando reproduz som alto com ganho máximo. O pino de 3.3V do ESP32 não consegue fornecer tanta corrente e deves usar uma fonte de alimentação externa. A imagem abaixo mostra como ligar uma alimentação externa de 5V ao circuito:

Single MAX98357A with ESP32 with external 5V for Mono Sound
MAX98357A único com ESP32 e alimentação externa de 5V para Som Mono

Estéreo

Se quiseres som estéreo, precisas de duas colunas, dois MAX98357A (um por canal) e resistências para selecionar o canal esquerdo ou direito. A imagem abaixo mostra toda a cablagem:

Two MAX98357A with ESP32 at 3.3V for Stereo Sound
Dois MAX98357A com ESP32 a 3.3V para Som Estéreo

Ambos os MAX98357A são ligados em paralelo, usando a mesma alimentação e pinos I2S como antes. A única diferença é que o MAX98357A para o canal esquerdo tem uma resistência de 100KΩ entre SD e 3.3V e o MAX98357A para o canal direito tem uma resistência de 210KΩ.

Nota que o ESP32 tem de produzir um sinal estéreo e o MAX98357A simplesmente seleciona o canal esquerdo ou direito da entrada estéreo, dependendo da tensão no pino SD.

Como antes, em vez de alimentar o MAX98357A pelo pino de 3.3V do ESP32, a opção mais segura é usar alimentação externa. O diagrama mostra como usar uma fonte de 5V externa:

Two MAX98357A with ESP32 with external 5V for Stereo Sound
Dois MAX98357A com ESP32 e alimentação externa de 5V para Som Estéreo

Nota que o pino SD do MAX98357A continua ligado a 3.3V através de uma resistência de 100KΩ ou 210KΩ. Podes ligar as resistências à fonte de 5V externa, mas nesse caso deves usar uma resistência de 370KΩ para o canal direito em vez da de 210KΩ. A resistência de 100KΩ para o canal esquerdo pode ficar igual.

Cartão SD

Se quiseres reproduzir ficheiros de áudio, precisas de ligar um leitor de cartões SD que armazene os ficheiros de áudio num cartão SD. O diagrama abaixo mostra como ligar um leitor de cartões SD e o MAX98357A a um ESP32:

Single MAX98357A with ESP32 and SD Card Reader for Mono Sound
MAX98357A único com ESP32 e Leitor de Cartão SD para Som Mono

O Leitor de Cartão SD comunica via SPI e os pinos SPI por defeito do ESP32 são CS=5, MOSI=23, CLK=18 e MISO=19. A tabela abaixo resume as ligações entre o Leitor de Cartão SD e o ESP32:

Leitor de Cartão SD ESP32
3V3 3V
GND G
CS/SS 5
MOSI 23
CLK/SCK 18
MISO 19

Se não tens a certeza de quais são os pinos SPI por defeito do teu ESP32, vê o Find I2C and SPI default pins tutorial.

Se quiseres som estéreo, precisas de ligar dois módulos MAX98357A. O diagrama seguinte mostra como fazer isso:

Two MAX98357A with ESP32 and SD Card Reader for Stereo Sound
Dois MAX98357A com ESP32 e Leitor de Cartão SD para Som Estéreo

Se precisares de mais ajuda a ligar o Leitor de Cartão SD, vê o nosso SD Card Module with ESP32 tutorial.

Instalar Bibliotecas

Existem várias bibliotecas Arduino que podes usar para gerar áudio para um dispositivo I2S como o MAX98357A. A seguir, falo rapidamente das três mais usadas.

Primeiro, existe a biblioteca ESP8266Audio do Earle F. Philhower, que suporta placas ESP8266, ESP32, Raspberry Pi Pico RP2040 e Pico 2 RP2350.

Depois, existe a biblioteca ESP32-audioI2S do schreibfaul1. Nota que esta biblioteca só funciona em chips multi-core como ESP32, ESP32-S3, ESP32-P4 e a tua placa tem de ter PSRAM. Não funciona nas placas ESP32-S2, ESP32-C3.

Por fim, existe a biblioteca arduino-audio-tools do Phil Schatzmann, que é a biblioteca mais poderosa e com mais funções. É esta biblioteca que vamos usar neste tutorial, mas as outras também valem a pena experimentar.

Instalar core ESP32

Em janeiro de 2026, não consegui pôr a biblioteca arduino-audio-tools a funcionar com o core ESP32 atual (Versão 3.3.6). Para os exemplos deste tutorial tens de fazer downgrade do core ESP32 para a Versão 2.0.17.

Assumindo que já tens o core ESP32 instalado, fazer downgrade é fácil. Abre o BOARDS MANAGER, escreve “esp32” na barra de pesquisa e depois seleciona a versão 2.0.17 para o core “esp32 by Espressif” e clica em “UPDATE” como mostrado abaixo:

Installing ESP32 Core Version 2.0.17
Instalar ESP32 Core Versão 2.0.17

Se precisares de mais ajuda para fazer downgrade ou instalar o core ESP, vê o Install ESP32 core in Arduino IDE tutorial.

Instalar Biblioteca arduino-audio-tools

Para instalar a biblioteca arduino-audio-tools vai ao arduino-audio-tools repo, clica no botão verde “<> Code” e depois em “Download ZIP” para descarregar a biblioteca como ficheiro ZIP, como mostrado abaixo:

Depois abre um Sketch, vai a Sketch -> Include Library -> Add .ZIP Library … para instalar a biblioteca ZIP descarregada (arduino-audio-tools-main.zip):

Para alguns exemplos de código precisamos de mais duas bibliotecas do Phil Schatzmann: a arduino-libhelix e a ESP32-A2DP. Podes instalá-las da mesma forma. Clica no link para ir ao repositório github, clica no botão verde “<> Code” para descarregar as bibliotecas (arduino-libhelix-main.zip, ESP32-A2DP-main.zip) e depois instala-as.

Reproduzir Som de Teste

Antes de tentares algo mais complexo, vamos primeiro tentar reproduzir um som de teste. Isto permite verificar a cablagem do MAX98357A com o ESP32 e se os canais esquerdo e direito estão corretamente selecionados ao reproduzir som estéreo. Além disso, este código não depende de nenhuma biblioteca e funciona tanto com o core ESP32 atual (3.x) como com o antigo (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);
}

O código configura o ESP32 como transmissor master I2S, gera um sinal de áudio de onda sinusoidal em tempo real e envia-o para o amplificador para produzir som no canal esquerdo, direito ou ambos.

Imports

O código inclui a biblioteca driver/i2s.h, que fornece as funções do driver I2S do ESP32 para comunicação de áudio. Também inclui a biblioteca matemática padrão math.h para usar funções matemáticas como sin() para gerar a forma de onda de áudio.

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

Constantes

São definidas várias constantes para configurar a interface I2S e os parâmetros de áudio. I2S_PORT seleciona o periférico I2S número 0 no ESP32. Os pinos MAX_DIN, MAX_LRC e MAX_BCLK correspondem aos sinais de dados, seleção de palavra (relógio esquerda-direita) e bit clock ligados ao amplificador MAX98357.

Os parâmetros de áudio incluem a taxa de amostragem de 44.100 Hz, uma frequência de tom de 500 Hz e uma amplitude de 1000 (num intervalo de inteiro assinado de 16 bits). O mais importante é que o código também define flags booleanas LEFT e RIGHT para controlar quais os canais de áudio que emitem som.

Por fim, BUFFER_LEN define o número de frames de áudio por buffer, e um array estéreo samples guarda as amostras de áudio intercaladas dos canais esquerdo e direito.

#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];

Função Setup

A função setup() inicializa o driver I2S e configura os pinos para comunicação com o amplificador MAX98357.

É criada uma estrutura i2s_config_t para especificar o modo I2S como transmissor master, amostras de 16 bits, formato de canal estéreo (direito e esquerdo) e taxa de amostragem de 44,1 kHz. Também define parâmetros de buffer DMA para transferência eficiente de dados.

De seguida, uma estrutura i2s_pin_config_t atribui os pinos GPIO para bit clock (bck_io_num), seleção de palavra (ws_io_num) e saída de dados (data_out_num). O pino de entrada de dados não é usado e é definido como I2S_PIN_NO_CHANGE.

Por fim, o driver I2S é instalado com i2s_driver_install() e a configuração dos pinos é aplicada com 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);
}

Função Loop

A função loop() gera continuamente amostras de áudio e envia-as para o periférico I2S para reprodução.

Uma variável estática phase mantém a posição atual dentro do ciclo da onda sinusoidal. O phaseIncrement é calculado com base na frequência de tom desejada e na taxa de amostragem, determinando quanto a fase avança por amostra.

Dentro do loop, o código preenche o buffer samples com dados de áudio estéreo intercalados. Para cada frame, calcula o seno da fase atual, escala pela amplitude e converte para inteiro de 16 bits. Dependendo das flags LEFT e RIGHT, o som é atribuído ao canal esquerdo e/ou direito, enquanto o outro canal é silenciado (zero).

A fase é incrementada e ajustada para se manter no intervalo de 0 a 2π radianos, garantindo uma forma de onda contínua.

Depois de preencher o buffer, a função i2s_write() envia os dados de áudio para o driver I2S, que os transmite para o amplificador. A função bloqueia até todos os bytes serem escritos, mantendo a reprodução de áudio suave.

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);
}

Podes usar este código para verificar se o som estéreo é reproduzido corretamente ao usar dois módulos MAX98357 e duas colunas. Se definires a constante LEFT como true e RIGHT como false, só a coluna esquerda deve emitir som. Da mesma forma, podes verificar se o canal direito funciona corretamente. Se não funcionar, verifica a tensão e as resistências no pino SD do MAX98357, que controla o canal.

Nos exemplos seguintes vamos usar a biblioteca arduino-audio-tools, que esconde todos os detalhes da comunicação I2S e simplifica o código.

Texto para fala

Este exemplo demonstra como converter texto em fala usando a interface I2S com um amplificador MAX98357. Liga-se ao WiFi, envia texto para a API Text-to-Speech (TTS) da OpenAI, recebe um stream de áudio MP3, descodifica-o e reproduz através do amplificador. O código usa a biblioteca arduino-audio-tools para gerir o streaming e descodificação de áudio.

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

O código começa por incluir várias bibliotecas. Arduino.h é a biblioteca principal do Arduino. WiFi.h e WiFiClientSecure.h fornecem conectividade WiFi e cliente HTTPS seguro. A biblioteca AudioTools e o codec MP3 CodecMP3Helix são usados para streaming e descodificação de áudio.

#include <Arduino.h>
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"

Constantes e Definição de Pinos

De seguida, são definidos os pinos usados para a interface I2S com o amplificador MAX98357. Estes pinos correspondem à entrada de dados (MAX_DIN), seleção de palavra ou relógio esquerda-direita (MAX_LRC) e bit clock (MAX_BCLK).

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

Além disso, são definidos constantes para o modelo TTS, voz e nível de volume.

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

Podes experimentar outros modelos TTS, como “tts-1” e outras vozes como “alloy”, “ash”, “coral”, “echo”, “fable”, “onyx”, “nova”, ‘sage”, “shimmer”, “marin”, “cedar”. Para mais detalhes vê platform.openai.com/docs/guides/text-to-speech.

As credenciais WiFi e detalhes da API OpenAI também são guardados como strings constantes. Terás de substituir “ssid” e “pwd” pelas credenciais do teu WiFi.

// WiFi credentials
const char* ssid     = "ssid";
const char* password = "pwd";

Também vais precisar de obter uma “apikey” da OpenAI. Vai a https://platform.openai.com e regista-te com um email ou conta Google/Microsoft existente.

// OpenAI configuration
const char* openaiHost = "api.openai.com";
const int   openaiPort = 443;
const char* openaiApiKey = "apikey";

Depois de verificares o email e completares a configuração inicial, faz login no dashboard da OpenAI, platform.openai.com/api-keys e encontra ou cria a tua API Key (=SECRET KEY) como mostrado abaixo:

OpenAI API keys
Chaves API OpenAI

A API Key é uma string longa e única, começando por “sk-proj-“, necessária para autenticar os teus pedidos à API (ver abaixo).

sk-proj-xcA.......................OtDu0U

Isto é tudo o que precisas para obter uma API key, mas recomendo que definas um limite de uso para a tua conta. Para mais detalhes vê o Vision Chatbot with DFRobot ESP32-S3 AI Camera and OpenAI tutorial.

Objetos de Áudio e Rede

São instanciados vários objetos para gerir o streaming de áudio e a comunicação de rede. WiFiClientSecure gere a ligação HTTPS à API da OpenAI. I2SStream gere a saída de áudio I2S. VolumeStream envolve o stream I2S para controlar o volume de áudio. EncodedAudioStream descodifica os dados de áudio MP3 usando o Helix MP3 decoder. Por fim, StreamCopy copia o stream de áudio descodificado do cliente de rede para a saída de áudio.

WiFiClientSecure client;
I2SStream i2s;
VolumeStream volume(i2s);
EncodedAudioStream mp3decode(&volume, new MP3DecoderHelix());
StreamCopy copier(mp3decode, client);

Função Texto-para-Fala

A função text2speech() envia uma string de texto para a API TTS da OpenAI e prepara o stream de áudio para reprodução. Primeiro, configura o cliente para aceitar certificados inseguros (útil para desenvolvimento). Depois tenta ligar ao servidor OpenAI na porta 443. Se a ligação falhar, imprime uma mensagem de erro e retorna.

A função constrói um corpo JSON especificando o modelo TTS, voz, formato de saída (MP3) e o texto de entrada. Envia um pedido HTTP POST com os headers apropriados, incluindo autorização com a API key. Depois de enviar o corpo do pedido, lê e ignora os headers da resposta HTTP para posicionar o stream do cliente no início dos dados de áudio 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;
  }
}

Função Setup

A função setup() inicializa a comunicação série para debugging e define o logger de áudio para mostrar avisos. Depois liga-se à rede WiFi especificada, esperando até a ligação ser estabelecida.

Depois de ligar ao WiFi, a interface I2S é configurada para modo de transmissão com os pinos definidos anteriormente. O stream I2S, o descodificador MP3 e o controlo de volume são inicializados. O volume é definido para o nível pré-definido.

Por fim, a função text2speech() é chamada com uma string de texto de exemplo para começar a fazer streaming e reproduzir a fala 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.");
}

Função Loop

A função loop() copia continuamente dados do stream do descodificador MP3 para a saída de áudio I2S. Isto mantém o áudio a tocar enquanto houver dados disponíveis do cliente de rede.

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

Rádio da Internet

Este exemplo mostra como implementar uma Web rádio simples. Liga-se a uma rede WiFi, faz streaming de rádio da internet em formato MP3, descodifica o áudio, ajusta o volume e envia o som para o 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

O código começa por incluir as bibliotecas necessárias para conectividade WiFi, comunicação I2C e processamento de áudio. As bibliotecas Arduino.h e WiFi.h fornecem funções básicas de Arduino e WiFi. A biblioteca Wire.h é incluída para comunicação I2C, frequentemente usada para controlar periféricos. A biblioteca AudioTools e os seus componentes relacionados gerem o streaming, descodificação e reprodução de áudio.

#include <Arduino.h>
#include <WiFi.h>
#include <Wire.h>
#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
#include "AudioTools/Communication/HTTP/ICYStream.h"

Constantes

De seguida, são definidos os pinos para o amplificador MAX98357. Estes pinos correspondem aos sinais I2S: MAX_DIN para entrada de dados série, MAX_LRC para seleção de palavra (relógio esquerda-direita) e MAX_BCLK para o relógio série. O volume é definido como um valor float entre 0 e 1, onde MAX_VOL é 0.5, representando 50% de volume.

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

Credenciais WiFi e URL do Stream

As credenciais da rede WiFi são guardadas nas constantes ssid e password. A constante url guarda o endereço do stream de rádio da internet a ser reproduzido, neste caso um stream de jazz.

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

Aqui tens mais alguns URLs de streams de rádio da internet que podes experimentar:

"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 Áudio

São instanciados vários objetos para gerir o pipeline de áudio. O objeto ICYStream gere o streaming HTTP da rádio da internet e a interface de saída de áudio I2S. O objeto VolumeStream envolve o stream I2S para controlar o volume de áudio. E o objeto EncodedAudioStream descodifica os dados MP3 usando o codec MP3DecoderHelix. Por fim, o objeto StreamCopy copia os dados de áudio descodificados do descodificador MP3 para o stream ICY.

ICYStream icystream;
I2SStream i2s;
VolumeStream volume(i2s);
EncodedAudioStream mp3decode(&volume, new MP3DecoderHelix());
StreamCopy copier(mp3decode, icystream);

Função de Callback de Metadata

A função callbackMetadata() é definida para tratar metadata recebida do stream de rádio da internet, como títulos de músicas ou informação do artista. Imprime o tipo de metadata e o conteúdo no monitor série para debugging ou informação.

void callbackMetadata(MetaDataType type, const char* str, int len) {
  Serial.printf("%s: %s\n", toStr(type), str);
}

Função Setup

Na função setup(), a comunicação série é inicializada a 115200 baud para permitir logging e debugging. O logger de áudio é configurado para mostrar avisos e acima no monitor série.

O ESP32 tenta ligar-se à rede WiFi especificada, verificando repetidamente o estado da ligação a cada 500 milissegundos até ter sucesso.

Depois de ligar, a configuração I2S é obtida usando o modo de transmissão por defeito. Os pinos I2S são atribuídos às constantes definidas anteriormente para bit clock, seleção de palavra e entrada de dados. A interface I2S e o controlo de volume são inicializados com esta configuração, e o volume é definido para 50%.

O descodificador MP3 é iniciado e o stream de rádio da internet é inicializado com o URL fornecido. A função de callback de metadata é registada para tratar metadata recebida durante a reprodução.

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);
}

Função Loop

A função loop() copia continuamente dados de áudio do stream de rádio da internet através do descodificador MP3 e do controlador de volume para a saída I2S. Este processo mantém a reprodução de áudio a correr indefinidamente.

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

Se quiseres adicionar mais funcionalidades como um controlador de volume, vê o nosso Playing Audio with ESP32 and PCM5102A tutorial. E se quiseres adicionar um display vê o Internet Radio with ESP32 and MAX 98357A tutorial.

Reproduzir MP3 do cartão SD

Este exemplo mostra como reproduzir ficheiros de áudio MP3 guardados num cartão SD usando um ESP32, o amplificador I2S MAX98357 e a biblioteca AudioTools. O código inicializa o hardware de áudio, configura o descodificador MP3 e faz streaming contínuo dos dados de áudio para o 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

O código começa por incluir os ficheiros de header da biblioteca AudioTools. Estes fornecem as classes e funções necessárias para gerir fontes de áudio, descodificar ficheiros MP3 e fazer streaming de áudio via I2S.

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

Constantes

De seguida, são definidos os pinos ligados ao amplificador MAX98357. Estes especificam os pinos de entrada de dados I2S (MAX_DIN), seleção de palavra ou relógio esquerda-direita (MAX_LRC) e bit clock (MAX_BCLK) no ESP32.

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

Além disso, são definidos constantes para o caminho da fonte de áudio e extensão de ficheiro. Aqui, PATH é o diretório raiz do cartão SD e EXT especifica que só ficheiros MP3 serão considerados.

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

Objetos

São instanciados vários objetos para gerir o pipeline de reprodução de áudio. AudioSourceSD representa a fonte de áudio do cartão SD, filtrando ficheiros pelo caminho e extensão especificados. I2SStream gere o stream de saída de áudio I2S. MP3DecoderHelix é o descodificador MP3 baseado no codec Helix. Por fim, AudioPlayer liga estes componentes para gerir a reprodução.

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

Função de Callback de Metadata

A função printMetaData() é definida para tratar informação de metadata como artista ou título da faixa. Recebe o tipo de metadata e a string, depois imprime no terminal série para debugging ou informação.

void printMetaData(MetaDataType type, const char* str, int len){
  Serial.printf("%s: %s\n", toStr(type), str);
}

Função Setup

Na função setup(), a comunicação série é inicializada a 115200 baud para logging. O logger da AudioTools também é iniciado com nível de aviso para capturar mensagens importantes.

A configuração I2S é obtida das definições por defeito para modo de transmissão. Os pinos para bit clock, seleção de palavra e dados são atribuídos às constantes definidas anteriormente correspondentes às ligações do MAX98357. O stream I2S é então inicializado com esta configuração.

Opcionalmente, pode ser definido um filtro de ficheiros na fonte de áudio para reproduzir apenas ficheiros que correspondam a um padrão (comentado neste exemplo). O callback de metadata é definido para a função printMetaData() para receber metadata durante a reprodução. O volume é definido para 40% para controlar o volume de saída. Por fim, o player de áudio é iniciado.

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();
}

Função Loop

A função loop() chama continuamente player.copy(), que gere o streaming de áudio do cartão SD através do descodificador e saída via I2S para o amplificador. Isto mantém a reprodução de áudio a correr suavemente sem bloquear outros processos.

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

Se quiseres adicionar mais funcionalidades como um controlador de volume e botões para passar faixas, vê o Playing Audio with ESP32 and PCM5102A tutorial.

Reproduzir Áudio por Bluetooth

Este exemplo mostra como fazer streaming de áudio por Bluetooth. O código configura a interface I2S com pinos específicos e inicializa um Bluetooth A2DP sink, permitindo ao ESP32 receber e reproduzir áudio de 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

O código começa por incluir duas bibliotecas importantes. A biblioteca AudioTools.h fornece ferramentas para gerir streams de áudio e configurar a interface I2S. A biblioteca BluetoothA2DPSink.h permite ao ESP32 funcionar como Bluetooth A2DP sink, ou seja, pode receber streams de áudio de fontes Bluetooth como smartphones.

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

Constantes

De seguida, são definidas três constantes para especificar os pinos GPIO usados para a interface I2S. Estes pinos ligam o ESP32 ao amplificador MAX98357. MAX_DIN é o pino de entrada de dados série, MAX_LRC é o pino de seleção de palavra ou relógio esquerda-direita, e MAX_BCLK é o pino de relógio série.

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

Objetos

É criado um objeto I2SStream chamado i2s para gerir o stream de áudio I2S. Depois, é instanciado um objeto BluetoothA2DPSink chamado a2dp_sink, passando-lhe o objeto i2s. Esta configuração liga diretamente a entrada de áudio Bluetooth à saída I2S, permitindo reprodução de áudio sem interrupções através do amplificador.

I2SStream i2s;
BluetoothA2DPSink a2dp_sink(i2s);

Função Setup

Dentro da função setup(), a interface I2S é configurada e iniciada. Primeiro, a configuração I2S por defeito é obtida chamando i2s.defaultConfig(). Depois, as atribuições dos pinos para bit clock (pin_bck), seleção de palavra (pin_ws) e entrada de dados (pin_data) são definidas para as constantes previamente definidas. Por fim, a interface I2S é inicializada com esta configuração chamando i2s.begin(cfg).

Depois de configurar o I2S, o Bluetooth A2DP sink é iniciado com o nome de dispositivo "MyMusic". Este nome vai aparecer quando outros dispositivos Bluetooth procurarem sinks de áudio disponíveis.

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 experimentar, abre o teu telemóvel, procura “dispositivos ligados” ou “dispositivos Bluetooth”, procura o dispositivo “MyMusic”, liga-te a ele e depois reproduz música. Deves conseguir ouvi-la a tocar no teu ESP32 e MAX98357.

Função Loop

A função loop() está vazia porque todo o streaming e reprodução de áudio são geridos de forma assíncrona pelo Bluetooth A2DP sink e pela interface I2S. Depois de iniciado, o ESP32 ouve continuamente streams de áudio Bluetooth e envia-os via I2S para o amplificador sem precisar de mais código no loop principal.

void loop() { }

Conclusões

Neste projeto, aprendeste a reproduzir áudio usando o ESP32 e o amplificador MAX98357. Explorámos os detalhes técnicos do módulo MAX98357A e como ligá-lo ao ESP32 para som mono ou estéreo. Também aprendeste a converter texto em fala, fazer streaming de rádio da internet, reproduzir ficheiros MP3 de um cartão SD e reproduzir áudio via Bluetooth.

Se quiseres adicionar mais funcionalidades como um controlador de volume e botões para passar faixas, vê o nosso Playing Audio with ESP32 and PCM5102A tutorial. Da mesma forma, se precisares de mais informação sobre o módulo Leitor de Cartão SD usado aqui, vê o SD Card Module with ESP32 tutorial.

Para um som melhor e mais potente podes usar o DAC PCM5102A e adicionar um amplificador. Vê os tutoriais seguintes para mais informações:

Se tiveres alguma dúvida, deixa nos comentários.

Boas experiências ; )

FAQ

P: O que é o MAX98357A e porque devo usá-lo?

O MAX98357A é um amplificador de áudio digital com DAC integrado, ou seja, recebe áudio digital diretamente do ESP32 via I2S e fornece um sinal já amplificado que pode alimentar uma coluna sem amplificador extra, tornando o circuito mais simples e melhorando a qualidade do som em relação ao DAC interno do ESP32.

P: Como é que o MAX98357A se liga ao ESP32?

O módulo usa três sinais I2S mais alimentação.

Ligação típica:

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

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

O ESP32 atua como master I2S e envia os dados de áudio, enquanto o MAX98357A recebe e converte em som.

P: Posso ligar uma coluna diretamente ao MAX98357A?

Sim, porque o MAX98357A já inclui uma etapa de amplificação, por isso podes ligar uma coluna diretamente.

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

As colunas típicas são de 4Ω a 8Ω, 3W ou mais. O amplificador fornece cerca de 3W de potência, suficiente para colunas pequenas.

P: Como obtenho som estéreo?

O MAX98357A é mono, por isso para estéreo precisas de dois módulos.

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

Ambos os módulos partilham os mesmos sinais I2S, mas usam resistências para selecionar os canais esquerdo e direito.

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

Assim, cada amplificador reproduz um canal.

P: Que alimentação devo usar?

O módulo funciona com 3.3V ou 5V, mas a alimentação é importante para boa qualidade de som. Em volume alto, o módulo pode consumir muita corrente, por isso alimentá-lo pelo pino 3.3V do ESP32 normalmente não chega e pode causar distorção ou resets.

P: Como posso melhorar a qualidade do som com filtragem de alimentação?

Uma alimentação limpa é fundamental, porque o ruído afeta diretamente a saída de áudio. Podes adicionar condensadores:

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

O condensador pequeno remove ruído de comutação rápido, enquanto o grande suaviza a ondulação da tensão e evita quedas durante picos de áudio altos.

Além disso, podes usar um condensador de filtragem:

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

Isto reduz ruído vindo do USB ou de reguladores comutados.

P: Devo usar uma fonte de alimentação externa?

Sim, especialmente para volumes altos, porque o MAX98357A pode consumir correntes elevadas ao reproduzir áudio alto e o regulador do ESP32 pode não aguentar de forma fiável.

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

Isto melhora a estabilidade e reduz a distorção.

P: Como posso aumentar o volume?

O volume depende de três fatores principais: tensão de alimentação, ganho do amplificador e tipo de coluna. Para aumentar o volume:

  • Usa 5V em vez de 3.3V
  • Usa uma coluna de menor impedância (4Ω em vez de 8Ω)

Uma coluna de 4Ω consome mais potência e produz mais volume, mas também aumenta a carga no amplificador.

P: O que faz o pino GAIN e como afeta o som?

O pino GAIN define o nível de ganho do amplificador.

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

Ganho mais alto aumenta o volume mas também pode aumentar o ruído e distorção, por isso normalmente é melhor começar com ganho baixo e ajustar por software.

P: Porque ouço ruído ou hiss mesmo sem áudio a tocar?

O ruído pode vir de várias fontes como ondulação da alimentação, má ligação à terra ou interferência do ESP32. Soluções comuns:

  • Adiciona condensadores de desacoplamento
  • Usa uma fonte de alimentação externa limpa
  • Mantém os cabos curtos

P: Que práticas de cablagem melhoram a qualidade do som?

Boa cablagem é muito importante, especialmente para áudio digital e amplificadores de comutação. Mantém os cabos curtos:

ESP32 --> MAX98357A (short lines)

e usa ligação à terra em estrela:

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

Evita passar cabos de coluna junto a cabos de sinal, porque os sinais de comutação de alta corrente podem introduzir ruído.

P: Que formatos de áudio e funcionalidades são suportados?

O MAX98357A suporta os formatos de áudio digital típicos usados com ESP32.

  • Áudio de 16, 24 ou 32 bits
  • Taxas de amostragem de 8 kHz a 96 kHz