Riprodurre Audio con ESP32 (Firmware > 3.0.0) e Amplificatore LM386.

Ciao a tutti!

Oggi affrontiamo un problema che molti di voi mi hanno segnalato ultimamente smanettando con le schede ESP32. Con i recenti aggiornamenti del core/firmware dell'ESP32 (le versioni superiori alla 3.x), molti dei vecchi sketch che usavano il DAC interno per riprodurre audio hanno smesso di funzionare.

Dopo vari test, ho trovato una soluzione far suonare il nostro ESP32 collegato a un classico modulo amplificatore LM386, riproducendo un file WAV. Il trucco? Sfruttare la modalità I2S NoDAC

La lista della spesa per questo progetto è davvero minima:

  • Una scheda ESP32 (qualsiasi modello classico va benissimo)
  • Un modulo amplificatore LM386 (quelli classici con la rotellina blu per il volume)
  • Un piccolo speaker/altoparlante (es. 8 Ohm, 0.5W o 1W)
  • Qualche cavetto Jumper


Libreria necessaria: ESP8266Audio (la trovate nel gestore librerie dell'IDE di Arduino, creata da Earle F. Philhower).

Il collegamento è semplicissimo. La particolarità di questo sketch è che andremo a dirottare il segnale audio su un pin specifico simulando un DAC tramite la tecnica Delta-Sigma.

Colleghiamo i pin in questo modo:

  • ESP32 Pin 25 ➔ IN (o Audio In) del modulo LM386
  • ESP32 GND ➔ GND del modulo LM386
  • ESP32 VIN (o 5V) ➔ VCC del modulo LM386 (l'LM386 rende molto meglio se alimentato a 5V rispetto ai 3.3V)


Colleghiamo i due fili dello speaker ai morsetti a vite verde (o ai pin di uscita) del modulo LM386.

Nota bene: se sentite troppo rumore di fondo, assicuratevi che i GND siano in comune e provate a regolare il potenziometro sul modulino.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <Arduino.h>

#include "AudioFileSourcePROGMEM.h"
#include "AudioGeneratorWAV.h"
#include "AudioOutputI2SNoDAC.h" // 1. Includiamo la classe NoDAC

#include "viola.h"

AudioGeneratorWAV *wav;
AudioFileSourcePROGMEM *file;
AudioOutputI2SNoDAC *out; // 2. Dichiariamo l'oggetto corretto

void setup() {
  Serial.begin(115200);
  delay(1000);
  
  file = new AudioFileSourcePROGMEM(viola, sizeof(viola));
  
  // 3. Inizializza l'uscita in modalità Delta-Sigma (simulazione DAC)
  out = new AudioOutputI2SNoDAC();
  
  // 4. Dirottiamo l'uscita dati (DOUT) al pin 25 a cui è collegato l'LM386.
  // I primi due parametri (BCLK e WCLK) sono i clock I2S: non ci servono 
  // in analogico, quindi li scarichiamo su due pin inutilizzati (es. 26 e 27).
  out->SetPinout(26, 27, 25); 

  wav = new AudioGeneratorWAV();
  wav->begin(file, out);
}

void loop() {
  if (wav->isRunning()) {
    if (!wav->loop()) {
      wav->stop();
    }
  } else {
    delay(1000);
  }
}

Questo sketch contiene anche un file .h di esempio (contenente un audio già convertito) in modo che possiate testare la funzionalità della parte hardware preoccupandovi in un secondo momento della funzionalità della vostra traccia audio. Assicuratevi di avere nella stessa cartella dello sketch un file, chiamatelo viola.h ed incollateci dentro l'array di byte da riprodurre (link file sviluppatore).

Il segreto di questo codice sta tutto nelle classi utilizzate e nella configurazione dei pin. Con i vecchi firmware bastava chiamare il DAC interno, ma ora la soluzione più stabile è usare AudioOutputI2SNoDAC.

Questa classe genera un segnale pseudo-analogico ad altissima frequenza (Delta-Sigma) che il nostro LM386 e il nostro speaker "filtrano" naturalmente, trasformandolo in vera e propria musica o voce.

La riga fondamentale è questa: out->SetPinout(26, 27, 25);

Il protocollo I2S normalmente richiede 3 fili (due per il clock e uno per i dati). Dato che a noi interessa solo il segnale dati "grezzo" da mandare all'amplificatore, assegniamo i due clock (BCLK e WCLK) a due pin a caso che non useremo (il 26 e il 27), mentre mandiamo i dati utili (DOUT) al Pin 25, che è fisicamente collegato al nostro amplificatore.

Se non dovesse ancora funzionare a dovere e sentite troppo fruscio o distorsione, è utile filtrare e "pulire" il segnale audio tra ESP32 e modulo LM386. Allo scopo occorrerà creare un piccolo Filtro Passa-Basso affiancato da un condensatore di blocco.

Non fatevi spaventare dai paroloni, vi basteranno tre componenti da pochissimi centesimi e un paio di saldature:

  • 1 Resistenza: tra 1kΩ e 4.7kΩ (da collegare in serie, partendo dal Pin 25 dell'ESP32).

  • 1 Condensatore ceramico (a lenticchia): da 10nF o 100nF (da collegare tra l'uscita della resistenza e il GND/massa). Questo serve a tagliare via le frequenze alte del "rumore digitale".

  • 1 Condensatore elettrolitico: (es. da 1µF a 10µF) da inserire in serie, subito dopo il filtro appena creato e prima di entrare nel pin IN dell'LM386.

Dopo aver testato con successo l'hardware, possiamo finalmente passare alla riproduzione del file WAV.
Ecco il codice da caricare:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <Arduino.h>
#include <LittleFS.h>
#include <WiFi.h>

#include "AudioFileSourceLittleFS.h" 
#include "AudioGeneratorWAV.h"
#include "AudioOutputI2SNoDAC.h"

AudioGeneratorWAV *wav;
AudioFileSourceLittleFS *file;
AudioOutputI2SNoDAC *out;

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_OFF); // Spegne completamente il modulo WiFi
  btStop();            // Spegne completamente il modulo Bluetooth (se presente)
  delay(1000);

  // 1. Avviamo il File System interno
  if (!LittleFS.begin(true)) {
    Serial.println("Attenzione: Errore nel montaggio di LittleFS!");
    return;
  }

  // 2. Puntiamo direttamente al nostro file .wav
  file = new AudioFileSourceLittleFS("/audio.wav");

  // 3. Inizializziamo il finto DAC verso l'LM386 (stesso metodo di prima)
  out = new AudioOutputI2SNoDAC();
  out->SetPinout(26, 27, 25);

  out->SetGain(0.9);

  wav = new AudioGeneratorWAV();
  if (!wav->begin(file, out)) {
    Serial.println("ERRORE: Formato WAV non supportato!");
  }
}

void loop() {
  if (wav->isRunning()) {
    if (!wav->loop()) {
      wav->stop();
    }
  } else {
    delay(1000);
  }
}

Ora passiamo al file audio, Attenzione, non potete dare in pasto all'ESP32 un file audio a caso scaricato da internet, va preparato e "snellito" a dovere!

Per farlo usiamo Audacity, il re indiscusso dei software audio gratuiti. Ecco la ricetta esatta per non avere problemi:

  1. Da Stereo a Mono: L'LM386 ha un solo speaker, il doppio canale è solo memoria sprecata. Importate il file in Audacity, selezionate tutta la traccia (Ctrl + A) e andate sul menu in alto: Tracce ➔ Mix ➔ Mixa traccia stereo in mono.

  2. Abbassare la Frequenza: I classici 44100 Hz dei CD pesano troppo per il nostro microcontrollore. In basso a sinistra, cambiate la Frequenza di campionamento progetto (Hz) a 16000 Hz (o 22050 Hz al massimo).

  3. Esportazione a 16-bit: Questo è il passaggio vitale. Andate su File ➔ Esporta ➔ Esporta come WAV. Come formato scegliete WAV (Microsoft) e come codifica impostate rigorosamente 16-bit PCM.

Perché proprio a 16-bit? La libreria AudioOutputI2SNoDAC lavora nativamente in 16 o 32-bit. Se provate a risparmiare spazio esportando a 8-bit (credendo di fare una furbata), il decoder andrà in crisi e l'ESP32 non emetterà il minimo suono (letteralmente: silenzio assoluto!).

Come caricare il file WAV sull'ESP32 (LittleFS)

Ora che abbiamo il nostro file perfetto, come lo infiliamo nella memoria dell'ESP32? Usiamo LittleFS, il file system interno che trasforma una porzione di memoria del microcontrollore in una minuscola chiavetta USB.

Ecco i passaggi:

  1. La cartella "data": Andate nella cartella del vostro computer dove è salvato lo sketch di Arduino. Create una nuova cartella al suo interno e chiamatela esattamente data (tutto minuscolo). Spostate il vostro magico file .wav appena esportato lì dentro.

  2. Spazio alla musica (Partition Scheme): Nell'IDE di Arduino, andate su Strumenti ➔ Partition Scheme e scegliete un'opzione che dedichi spazio al file system (ad esempio "Default 4MB with spiffs" o simili, l'importante è che ci sia almeno 1.5MB dedicato all'FS).

  3. Il caricamento (Arduino IDE 2.x): Premete Ctrl + Shift + P (o Cmd+Shift+P su Mac), cercate il comando Upload LittleFS to Pico/ESP8266/ESP32 e cliccatelo. (Nota: se usate ancora il vecchio Arduino IDE 1.8, vi basterà cliccare su "ESP32 LittleFS Data Upload" direttamente dal menu Strumenti).

⚠️ Attenzione al bug della porta COM! Se durante l'upload ricevete un errore del tipo ERROR: No port specified o il caricamento fallisce, è un capriccio dell'IDE. Per risolvere:

  • Chiudete il Monitor Seriale (tiene occupata la porta!).

  • Andate nel menu Strumenti ➔ Porta e cliccate di nuovo fisicamente sulla porta COM del vostro ESP32, in modo da forzare l'IDE a trasmettere il parametro al plugin.

  • Rilanciate il comando. Quando vedrete la scritta LittleFS Upload successful!, siete pronti a caricare lo sketch!

Una volta fatto l'upload del file e dello sketch... preparatevi ad alzare il volume!

Spero che questo tutorial vi abbia risolto il mal di testa dell'aggiornamento firmware dell'ESP32. Se il progetto vi è stato utile, condividetelo e fatemi sapere nei commenti cosa state costruendo.

Come sempre, un saluto a tutti!

Nessun commento:

Posta un commento

Lascia un commento qui sotto, ti risponderò il prima possibile!

Altri Post