In questo tutorial imparerai come registrare segnali audio con la scheda Seeed Studio XIAO-ESP32-S3-Sense. Se non hai mai usato la XIAO-ESP32-S3 Sense prima, dai un’occhiata al Getting started with XIAO-ESP32-S3-Sense tutorial prima.
Componenti necessari
Ovviamente, ti servirà una scheda XIAO ESP32 S3 Sense di Seeed Studio per provare gli esempi di codice. Nota che la scheda può scaldarsi e potresti voler montare un piccolo Heatsink (vedi il componente elencato qui sotto).
Inoltre, ti servirà una scheda SD per memorizzare l’audio registrato. Ho indicato una scheda da 32 GB, ma anche una più piccola (8 GB) va benissimo per fare delle prove. Infine, se il tuo computer non ha un lettore di schede SD integrato, ti servirà anche quello.

Seeed Studio XIAO ESP32 S3 Sense

Cavo USB C

Piccolo dissipatore 9×9 mm

Scheda SD 32GB

Lettore di schede SD
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.
Microfono della XIAO-ESP32-S3-Sense
La XIAO-ESP32-S3-Sense è dotata di un microfono digitale integrato MEMS Microphone di tipo MSM261D3526H1CPM che si trova sul Sense Hat. Vedi l’immagine qui sotto:

Puoi comunicare con il microfono tramite due linee di segnale (PDM_CLK, PDM_DATA) per il I2S protocol che sono collegate a IO42 e IO41 come mostrato nello schema qui sotto:

Nota che sul retro del PCB del Sense Hat ci sono due pad “Jumper” etichettati J1 e J2 (frecce rosse). Vedi l’immagine qui sotto:

Se tagli il sottile filo tra questi pad (seguendo le linee bianche) disabiliti il microfono, ma i GPIO D11 e D12 sul Sense Hat diventano disponibili; altrimenti sono usati dal microfono. Per maggiori dettagli vedi il Pin Multiplexing Information.
Lettura del segnale microfono dalla XIAO-ESP32-S3-Sense
Come primo esempio di codice, mostreremo il segnale audio rilevato dal microfono sul Serial Monitor e Serial Plotter:
#include "ESP_I2S.h"
const int8_t I2S_CLK = 42;
const int8_t I2S_DIN = 41;
const uint32_t SAMPLERATE = 16000;
I2SClass I2S;
void setup() {
Serial.begin(115200);
I2S.setPinsPdmRx(I2S_CLK, I2S_DIN);
if (!I2S.begin(I2S_MODE_PDM_RX, SAMPLERATE, I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO)) {
Serial.println("Can't find microphone!");
while (1)
;
}
}
void loop() {
int sample = I2S.read();
if (sample > 1) {
Serial.println(sample);
}
}
Costanti e oggetti
Il codice inizia includendo la libreria ESP_I2S. Definiamo poi le costanti per i pin a cui è collegata l’interfaccia I2S del microfono e la frequenza di campionamento:
#include "ESP_I2S.h" const int8_t I2S_CLK = 42; const int8_t I2S_DIN = 41; const uint32_t SAMPLERATE = 16000;
Successivamente creiamo gli oggetti I2S che ci permettono di trasferire dati da e verso il microfono tramite I2S protocol:
I2SClass I2S;
Funzione setup
Nella funzione setup inizializziamo l’interfaccia Serial, impostiamo i pin per l’interfaccia I2C e avviamo la comunicazione I2S:
void setup() {
Serial.begin(115200);
I2S.setPinsPdmRx(I2S_CLK, I2S_DIN);
if (!I2S.begin(I2S_MODE_PDM_RX, SAMPLERATE, I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO)) {
Serial.println("Can't find microphone!");
while (1)
;
}
}
Il parametro I2S_MODE_PDM_RX configura la periferica I2S per operare in modalità ricezione PDM (Pulse-Density Modulation). I microfoni PDM emettono un flusso di bit ad alta frequenza dove la densità di ‘1’ corrisponde all’ampiezza del segnale. In questa modalità, l’hardware ESP32 si occupa di decodificare questo flusso in campioni audio PCM utilizzabili.
Il parametro SAMPLERATE definisce il numero di campioni audio acquisiti al secondo, tipicamente misurato in Hertz (Hz). In questo codice è impostato a 16000, quindi il microfono viene campionato 16.000 volte al secondo. Questa frequenza è un buon compromesso tra dettaglio sufficiente per la voce umana e requisiti di elaborazione e memoria contenuti. Frequenze più basse riducono carico di memoria e CPU, utile per sistemi a batteria, ma riducono la risoluzione.
Il parametro I2S_DATA_BIT_WIDTH_16BIT imposta la profondità in bit di ogni campione audio PCM a 16 bit. La profondità in bit indica quanto precisamente ogni campione rappresenta l’ampiezza dell’onda sonora originale. 16 bit offrono 65.536 livelli di ampiezza possibili per campione, garantendo un buon intervallo dinamico per catturare variazioni sottili di volume e tono.
Il parametro I2S_SLOT_MODE_MONO configura l’interfaccia I2S per operare in modalità canale mono, cioè con un solo canale audio per la cattura dati. Questo è appropriato per un singolo microfono PDM, poiché l’uso stereo (due canali) sarebbe inutile e sprecherebbe risorse.
Funzione loop
Nella funzione loop leggiamo un singolo campione audio tramite I2S.read() dal microfono. Se il campione è maggiore di 1 (per filtrare silenzio o rumore di fondo) lo stampiamo sul monitor seriale:
void loop() {
int sample = I2S.read();
if (sample > 1) {
Serial.println(sample);
}
}
Se esegui il codice, apri il Serial Plotter e fischi a frequenza fissa, dovresti vedere una bella onda sinusoidale sul Serial Plotter:

Se vari la frequenza fischiando più basso o più alto, vedrai che la frequenza dell’onda sinusoidale visualizzata cambia di conseguenza.
Registrare audio con XIAO-ESP32-S3-Sense
In questo esempio mostrerò come registrare 5 secondi di audio e scrivere i dati come file audio in formato WAV sulla scheda SD.
Vogliamo avviare la registrazione premendo un pulsante e poi registrare per i successivi 5 secondi. Il seguente schema mostra come collegare un pulsante al pin D7 della scheda:

Qui sotto trovi il codice completo del progetto. Dagli un’occhiata veloce e poi ne analizzeremo i dettagli:
#include "ESP_I2S.h"
#include "FS.h"
#include "SD.h"
const uint32_t SAMPLERATE = 16000;
const int LEN = 5; // seconds
const byte btnPin = D7;
const byte ledPin = BUILTIN_LED;
I2SClass i2s;
void recordAudio() {
static int cnt = 0;
static char filename[64];
uint8_t *wav_buffer;
size_t wav_size;
Serial.print("RECORDING ... ");
wav_buffer = i2s.recordWAV(LEN, &wav_size);
sprintf(filename, "/audio%d.wav", cnt++);
File file = SD.open(filename, FILE_WRITE);
file.write(wav_buffer, wav_size);
file.close();
free(wav_buffer);
Serial.printf("COMPLETE => %s\n", filename);
}
void setup() {
Serial.begin(115200);
pinMode(btnPin, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
i2s.setPinsPdmRx(42, 41);
if (!i2s.begin(I2S_MODE_PDM_RX, SAMPLERATE,
I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO)) {
Serial.println("Can't find microphone!");
}
if (!SD.begin(21)) {
Serial.println("Failed to mount SD Card!");
}
}
void loop() {
if (!digitalRead(btnPin)) {
delay(500);
digitalWrite(ledPin, LOW);
recordAudio();
digitalWrite(ledPin, HIGH);
}
}
Librerie
Il codice inizia includendo due librerie importanti:
#include "ESP_I2S.h" #include "FS.h" #include "SD.h"
La libreria ESP_I2S.h fornisce un’astrazione per gestire l’ingresso audio tramite l’interfaccia I2S, usata dal microfono PDM. Le librerie FS.h e SD.h permettono l’accesso al file system della scheda SD, consentendo di salvare i file audio.
Costanti
Successivamente vengono definite alcune costanti:
const uint32_t SAMPLERATE = 16000; const int LEN = 5; // seconds const byte btnPin = D7; const byte ledPin = BUILTIN_LED;
La SAMPLERATE è impostata a 16.000 campioni al secondo, un valore standard per registrazioni vocali intelligibili.LEN specifica la durata della registrazione in secondi.btnPin è assegnato al pin di input del pulsante (D7), e ledPin è il LED onboard usato come feedback visivo durante la registrazione.
Oggetti
Successivamente creiamo l’oggetto I2SClass, usato per configurare e controllare l’interfaccia audio I2S.
I2SClass i2s;
Funzione recordAudio
Nella funzione recordAudio() gestiamo la registrazione audio e il salvataggio su file:
void recordAudio() {
static int cnt = 0;
static char filename[64];
uint8_t *wav_buffer;
size_t wav_size;
Un contatore statico cnt viene usato per creare nomi file unici per ogni registrazione. Vengono dichiarati un puntatore a buffer wav_buffer e una variabile wav_size per contenere i dati audio registrati e la loro dimensione.
Serial.print("RECORDING ... ");
wav_buffer = i2s.recordWAV(LEN, &wav_size);
La funzione inizia stampando un messaggio sul monitor seriale. Viene poi chiamata la funzione recordWAV() sull’oggetto i2s, che registra audio per la durata di LEN secondi e restituisce un puntatore ai dati WAV e la loro dimensione.
sprintf(filename, "/audio%d.wav", cnt++); File file = SD.open(filename, FILE_WRITE); file.write(wav_buffer, wav_size); file.close(); free(wav_buffer);
Viene generato un nome file usando il contatore, come /audio0.wav, /audio1.wav, ecc. La scheda SD viene aperta con SD.open e i dati WAV vengono scritti nel file. La memoria usata da wav_buffer viene poi liberata per evitare perdite di memoria.
Serial.printf("COMPLETE => %s\n", filename);
}
Dopo il salvataggio, viene stampato un messaggio di completamento sul monitor seriale con il nome del file salvato.
Funzione setup
Nella funzione setup() inizializziamo prima la comunicazione Serial a 115200 baud per permettere messaggi di debug.
void setup() {
Serial.begin(115200);
Configuriamo poi il pulsante come input con resistenza di pull-up interna, quindi legge HIGH di default e LOW quando premuto. Il pin del LED è impostato come output.
pinMode(btnPin, INPUT_PULLUP); pinMode(ledPin, OUTPUT);
Impostiamo quindi i GPIO 42 e 41 per l’ingresso del microfono PDM, corrispondenti al cablaggio di default del microfono onboard della XIAO ESP32-S3 Sense.
i2s.setPinsPdmRx(42, 41);
L’interfaccia I2S viene inizializzata in modalità ricezione PDM, con la frequenza di campionamento specificata, 16 bit di profondità e canale mono. Se l’inizializzazione fallisce, viene mostrato un messaggio di errore.
if (!i2s.begin(I2S_MODE_PDM_RX, SAMPLERATE,
I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO)) {
Serial.println("Can't find microphone!");
}
Infine, inizializziamo la scheda SD usando il GPIO 21 come pin CS (Chip Select). Se il montaggio fallisce, stampiamo un messaggio di errore.
if (!SD.begin(21)) {
Serial.println("Failed to mount SD Card!");
}
}
Funzione loop
Infine, la funzione loop() controlla la pressione del pulsante e avvia la registrazione:
void loop() {
if (!digitalRead(btnPin)) {
delay(500);
digitalWrite(ledPin, LOW);
recordAudio();
digitalWrite(ledPin, HIGH);
}
}
Il pulsante viene letto; se è LOW (premuto), il programma attende 500 millisecondi per il debounce, poi accende il LED, chiama recordAudio() e spegne il LED al termine. Questo fornisce un segnale visivo che la registrazione è in corso.
Conclusioni
In questo tutorial hai imparato come registrare audio usando la tua XIAO-ESP32-S3 Sense. Ora sei pronto, per esempio, a costruire applicazioni controllate dalla voce. Vedi il nostro Voice control with XIAO-ESP32-S3-Sense and Edge Impulse tutorial.
Se ti servono più informazioni sulla XIAO-ESP32-S3 Sense, dai un’occhiata al Getting started with XIAO-ESP32-S3-Sense tutorial. E per lo streaming video vedi il nostro Stream Video with with XIAO-ESP32-S3-Sense tutorial.
Infine, non dimenticare di consultare il Getting Started Wiki by Seeed Studio per la XIAO-ESP32-S3-Sense, che offre anche molte informazioni sulla scheda e numerosi esempi di codice.
Se hai domande, sentiti libero di lasciarle nella sezione commenti.
Buon divertimento con il tinkering ; )

