Un player wav/mp3 economico, controllabile da UART. Libreria per Arduino e ESP8266

Cercavo una soluzione economica e semplice per un sistema domotico che sto implementando in casa e che comunica tramite la rete LAN/Wi-Fi. La mia idea è quella di realizzare una sorta di centro messaggi (sostanzialmente una scatola che parla) che abbia una duplice funzione: deterrente per intrusi (simulatore di presenza) e segnalazione anomalie in casa (es.: allarme fuga di gas, sistemi abilitati/disabilitati, allarmi e avvertimenti vari anche presi dal web tipo: terremoti nelle vicinanze, allerta meteo ecc).

Cercando un po’ in giro mi sono imbattuto in un’infinità di economici moduli cinesi in grado di riprodurre files WAV e MP3 semplicemente comandati da una linea seriale (TX/RX – tra l’altro per molti moduli la linea di ricezione sul microcontrollore non è neanche strattamente necessaria, quindi il collegamento si può tranquillamente ridurre ad un unico filo).

Dico la verità: non mi sono soffermato molto, ho scelto quello più adatto alle mie esigenze. Il modulo che ho preso è dotato di un’uscita per cuffie/amplificatore con jack standard da 3.5mm, di un amplificatore on-board dichiarato da 3W al quale può essere collegato un altoparlantino da 8Ω e di un lettore di scheda microsd. E’ inoltre presente un LED che segnala il play in corso (si spegne quando il play è finito).

Il modulo accetta sia le microsd classiche (fino a 2Gb) che quelle SDHC (superiori a 2Gb). Ci sono soltanto 4 pin: alimentazione, RX e TX (comunica a 9600,8,n,1). Va alimentato necessariamente a 5V (ho provato a meno: non funziona!) mentre la linea di comunicazione seriale funziona a 3.3V (il chip pare abbia un regolatore interno), per cui è decisamente adatto all’utilizzo che ne voglio fare su un modulo ESP8266, in particolare accoppiato su un ESP-01.

Tra l’altro, questo modulo, è l’ideale per dare voce a giocattoli, presepi e altri dispositivi in cui lo spazio è ristretto, proprio perchè ha un amplificatorino integrato.

Il modulo in questione, a scanso di equivoci, è il seguente:

Potete acquistarlo su Amazon. Non esistono molte informazioni in giro sui chip utilizzati da questi moduli, il venditore da cui l’ho comprato mi ha fornito un pdf con l’elenco dei comandi e un semplice sketch per Arduino IDE. 

Questo modulo in particolare costa intorno ai 7 euro, ma esistono player mp3 anche più economici (meno di 3 euro!), basati sul chip siglato YX5300, ma ho preferito questo per il fatto che ha anche un piccolo amplificatore integrato che mi permette di collegarci direttamente un altoparlante e realizzare quindi una scatoletta abbastanza compatta e con pochi collegamenti.

I due chip presenti sul mio modulo sono l’amplificatore di potenza (siglato 8002A, per il quale il datasheet è facilmente reperibile con una ricerca su Google) e il chip multifunzione che esegue la lettura della microSD, accetta comandi seriali, decodifica i files WAV/MP3 e li porta su un’uscita DAC che va a finire sulla presa cuffie e sull’ingresso dell’amplificatore.

Questo chip, purtroppo, non ha identificazioni di nessun tipo: sopra non c’è stampata nessuna sigla e quando incontro situazioni del genere mi si accende la curiosità e do il via alle ricerche.

Cercando in rete mi sono imbattuto su un modulo del tutto simile ma che non ha la microSD, piuttosto è dotato di una memoria flash on-board sulla quale possono essere memorizzati i files e a cui si accede tramite una porta microUSB (il chip oltre a fare tutto il resto, fa anche da interfaccia tra porta USB e memoria flash). Di questo secondo modulo è possibile reperire maggiori informazioni in rete e viene venduto come JQ8400FL (la sigla FL alla fine odora proprio di FLASH, ad identificare il fatto che il chip si interfaccia con la memoria flash on board).

Il problema (relativo) di questo secondo modulo dotato di flash, è che i comandi seriali non sono gli stessi del modulo che ho acquistato per cui la libreria non è compatibile. Analizzando gli schemi delle due schede, però, noto che sono praticamente identici: anche sul mio modulo, dallo schema, fanno capolino dei pin non utilizzati (in particolare i pins 5 e 6) ai quali fanno capo le due linee D+/D- della porta USB (che invece sull’altro modulo sono collegati alla porta usb). Poi cambia qualcosina come i valori delle resistenze ma, insomma, sembra proprio che di questo chip ne esistano due revisioni: una fatta per funzionare con una memoria flash (e che quindi sfrutta la porta USB per leggere/scrivere sulla flash e difatti nei tutorial si fa riferimento al fatto che tale modulo viene visto dal pc come un’unità di archiviazione) e un’altra fatta per funzionare con le Trans-Flash (le microSD).

Da ulteriori ricerche viene fuori, su siti cinesi che vendono componenti al dettaglio, che esiste un chip siglato JQ8400TF (TF = Trans-Flash ?). Bingo. Purtroppo non esistono datasheet riguardo questo secondo chip/modulo, ma sinceramente mi sta bene il file PDF e l’esempio Arduino che il cinese mi ha inviato. Grazie all’utente raptuz abbiamo scoperto che esiste un altro chip, praticamente uguale a questo, siglato QJ004-16S. Di quest’ultimo si trova qualche informazione in più ma tutti i negozi cinesi che ho trovato non ce l’hanno in stock, ad ogni modo sembra essere proprio lo stesso circuito integrato.

Comandi del modulo

Con tale modulo (quello che ho comprato io, ritratto nella foto), si comunica in maniera molto semplice: tutti i comandi inviati sulla seriale devono avere un byte di avvio comunicazione (0x7E) seguito dal numero di bytes che si invierà (escluso il byte di start e questo byte), seguono quindi il byte del comando ed eventuali byte di parametri per il comando e infine un byte di fine (0xEF). Non esistono ritorni a capo (nè LF, nè BR).

A differenza di tutti gli altri moduli seriali mp3/wav, questo non prevede checksum, probabilmente per molti sarà un male (eh ma la sicurezza!) ma io la vedo da un altro punto di vista: mi semplifica le cose.

 Ci sono i comandi classici che ci si aspetta da un normale player:

ByteComandoDescrizione
0x01PLAYfa partire il play (è necessario aver "iniettato" prima una canzone). Oppure fa ripartire il play dopo una pausa/stop
0x02PAUSEMette in pausa la canzone (il successivo play riprende dal punto in cui si è data pausa)
0x03NEXT SONGEsegue il play del file successivo a quello attuale
0x04PREV SONGEsegue il play del file precedente a quello attuale
0x05VOLUME UPAumenta il volume di un passo
0x06VOLUME DOWNDiminuisce il volume di un passo
0x0AFORWARDEsegue il play veloce in avanti
0x0BREWINDEsegue il play veloce all'indietro
0x0ESTOPFerma la canzone

Io nella mia libreria faccio riferimento ai comandi nella tabella indicata sopra come da 1 byte, nel senso che quei comandi si inviano da soli, senza altri byte che li seguono. In pratica, seguendo la struttura dati che dicevo prima ([start] [numero di bytes] [comando + eventuali parametri] [stop]), sulla linea seriale, per eseguire il play ad esempio, basterà inviare:

0x7E 0x02 0x01 0xEF

dove:

  • 0x7E: byte di start
  • 0x02: dopo di me seguiranno due bytes (ovvero il comando e il byte di stop)
  • 0x01: comando play
  • 0xEF: byte di fine

Il modulo lavora ad indici: in pratica esegue la lettura della microsd e si crea un indice sequenziale dei files sulla scheda. L’indice è lo stesso che avreste sul pc quando fate l’ordinamento alfabetico crescente. In pratica gli dite “esegui il play della canzone n°1” e lui ordina in ordine alfabetico crescente i files presenti e fa il play della canzone in cima alla lista. Per cui è bene sistemare i files sulla scheda dandogli magari i nomi “001.mp3”, “002.wav” ecc, ma va bene anche “001-cane che abbaia.mp3”, “002-suono della sirena.wav” ecc, al modulo forniamo soltanto l’indice (che è a base uno, quindi non si parte da zero come ci verrebbe spontaneo fare).

C’è un comando per impostare il volume (è possibile impostare valori da 0x00 a 0x30, valori superiori a 0x30 vengono accettati ma il volume è sempre al massimo a 0x30) che è 0x31 seguito dal valore del volume. Questo comando è da 2 bytes, quindi scriveremo:

0x7E 0x03 0x30 0x15 0xEF

che vuol dire:

  • 0x7E : start
  • 0x03 : dopo di me seguono 3 bytes (comando volume, valore di volume, byte di fine)
  • 0x30 : comando “imposta volume al valore”
  • 0x15 : valore da dare al volume (su una scala da 0x00 a 0x30)
  • 0xEF : fine

Altro comando da 2 bytes è la selezione del dispositivo da cui leggere i files(!!).

Anche per via di questo comando e di come si imposta, sono stato dell’idea che tale chip esistesse in due revisioni, ma mai terminate. In pratica mi aspettavo che, per quanto detto sopra nell’introduzione, lo stesso chip potesse leggere sia da una memoria flash che da una scheda SD dato che esiste questo comando. Ma poi vedo che questo modulo è in grado di leggere unicamente dalla scheda SD perchè è possibile impostare soltanto la SD! (e in più l’altra revisione del chip ha anche comandi seriali diversi). Durante l’inizializzazione, quindi, anche se non è possibile fare diversamente, è comunque necessario dare il comando “leggi dalla SD” (0x35):

0x7E 0x03 0x35 0x01 0xEF
  • Start
  • seguono 3 bytes
  • comando “seleziona il dispositivo da cui leggere i files”
  • valore “trans-flash” (unica selezione disponibile su questo modulo)
  • fine

I due comandi visti ora (imposta volume e seleziona dispositivo), sono da due bytes (comando + valore da 1 byte).

Seguono quindi i comandi più utili ai nostri fini:

ByteComandoDescrizione
0x31PLAY WITH VOLUMESegue il valore di volume (da 0x00 a 0x30) e il byte dell'indice della canzone (da 0x00 a 0xFF)
0x41PLAY INDEXsegue un valore a 16 bit che indica l'indice del file (da 0x00 a 0xFFFF). Si inviano in pratica due bytes: byte alto e byte basso dell'indice
0x42PLAY DIR/INDEXSeguono due bytes, il primo byte è l'indice della cartella (segue lo stesso ragionamento per l'ordinamento dei files) e il secondo byte è l'indice del file contenuto in quella cartella
0x43INJECT INDEXFa la stessa cosa del comando PLAY INDEX, ma la canzone non parte. Per farla partire verrà inviato il comando semplice PLAY

In pratica nella mia applicazione, dopo l’inizializzazione (settaggio porta seriale, selezione dispositivo Trans-Flash e settaggio volume) io utilizzo semplicemente il comando PLAY INDEX. Per esempio, per fare il play della prima canzone invio in sequenza:

0x7E 0x04 0x41 0x00 0x01 0xEF
  • start
  • seguono 4 bytes (comando, byte alto e byte basso dell’indice, stop)
  • comando “Play Index”
  • byte alto dell’indice della canzone (essendo l’indice 0x0000, il byte alto è 0x00)
  • byte basso dell’indice della canzone
  • stop

Quindi capite che il comando semplice PLAY da solo non esegue nulla. E’ necessario aver prima “iniettato” una canzone con il comando 0x43 e poi eseguire il play. Oppure si può eseguire il play di una specifica canzone direttamente con il comando 0x41.

Ci sono altri comandi speciali come il repeat e il play in sequenza fino a 15 canzoni delle quali si specifica l’indice, ma alcuni non sono riuscito a capirli/farli funzionare e altri non mi servono, ma nella libreria li ho implementati.

Libreria per Arduino IDE

La libreria che ho scritto per questo modulo serve per Arduino IDE. I più affezionati si chiederanno perchè non l’ho scritta per picmicro: questo modulo mi serve accoppiato ad un modulo ESP-01 per il progetto di cui parlavo ad inizio articolo ecco il perchè della scelta, tenete anche conto che man mano che l’età avanza sia per me che per i miei figli, i tempi si restringono sempre di più (dovrò aspettare la pensione e i figli grandi per potermi dedicare a tempo pieno a queste cose!). Ad ogni modo ho prolungato di molto l’articolo descrivendo i comandi (che con la libreria non vi servono perchè fa tutto lei!) proprio per permettervi di scrivere da voi una libreria per la mcu di vostro gradimento.

La mia libreria l’ho testata su Arduino Duemilanove, Arduino Leonardo e su un modulo ESP-01. Fa utilizzo della seriale Hardware. I più scaltri volendo possono modificarla per farla funzionare con la seriale software e quelli più bravi ancora possono ricavare in pochi minuti la libreria per picmicro utilizzando la UART/USART.,

E’ necessario scaricare l’archivio dal mio Github a questo indirizzo o la libreria in formato zip in fondo all’articolo ed estrarla nella cartella Libraries personale di Arduino IDE (quella che si trova nei documenti, non quella che si trova nella cartella dell’applicazione). Con le nuove versioni di Arduino IDE la cosa è più semplice, una volta ottenuto il file zip della libreria , avviate Arduino IDE e dal menù “Sketch” selezionate “#include libreria” e quindi “Aggiungi libreria da file zip”. Nella finestra che segue, puntate al file zip che avete scaricato e il gioco è fatto:

La libreria contiene già un esempio semplice. Prima di provarlo mettete un file (wav o mp3) sulla scheda SD. Essendoci un solo file, quando andrete a dire “esegui il file con indice 1”, chiaramente eseguirà sicuramente quello! Ma se ne mettete tanti, ricordatevi della questione dell’ordinamento.

Bisogna, per prima cosa, includere la libreria:

#include <mp3serial_JQ8400TF.h>

Quindi istanziare l’oggetto con il nome che preferiamo:

mp3Serial mp3(0); // initialize library on serial port 0 (for Arduino duemilanove)

nel mio esempio istanzio la libreria chiamandola semplicemente “mp3”. Ho messo lo zero tra parentesi per indicare che voglio utilizzare la sola porta seriale presente sull’arduino duemilanove o sull’ESP-01. Se usiamo Arduino Leonardo metteremo 1 tra parentesi per indicare che vogliamo utilizzare la Serial1 (quella non utilizzata dalla porta USB). La serial 1 è presente anche su Arduino Mega, o ancora 2 o 3 se vogliamo usare la Serial 2 o la Serial 3 presenti su Arduino Mega. Non ho previsto Arduino DUE e il Teensy perchè non ho trovato un elenco fatto bene di macro che mi permettono di identificare le varie schede, ma in realtà non ne avevo tempo/voglia.

Nella funzione di Setup inizializzo il modulo:

mp3.begin(); // init module

In pratica questa funzione inizializza la porta seriale scelta a 9600bps e da i comandi al modulo per selezionare la Trans-Flash e impostare il volume al massimo.

Nel setup stesso eseguo il play della prima canzone:

mp3.playIndex(1); // play first song

Il loop nell’esempio l’ho lasciato vuoto. Bisogna tenere a mente che dopo aver dato il play di una canzone, dovremmo aspettare che termina prima di dare il play della successiva o quanto meno aspettare una manciata di millisecondi, altrimenti il modulo si impalla e dall’altoparlante escono suoni sgradevolissimi.

Nella libreria ci sono anche tutti i comandi:

comandi da 1 byte, da richiamare con le parentesi vuote, es.: mp3.play():

play(), pause(), next(), prev(), volumeup(), volumedown(), forward(), rewind(), stop()

e comandi da 2/3 bytes da richiamare con i parametri:

playIndex(uint16_t index);
setVolume(uint8_t volume);
playWithVolume(uint8_t volume, uint8_t index);
injectSong(uint16_t index);

Si potrebbero implementare sistemi per determinare il termine del play di una canzone. In particolare il pin 4 del chip, identificato come “busy” (collegato al led di play) dovrebbe servire proprio a quello. In aggiunta il modulo trasmette anche: sul manuale non ci sono indicazioni, ma giocherellandoci un po’ sul pc è possibile vedere che dopo ogni comando, il modulo fornisce una risposta che segue la stessa struttura dell’invio. In particolare dopo ogni comando fornisce una risposta di Acknowledgment, tipo:

7E 02 00 EF

Dove è facile individuare start (7E), seguono 2 bytes (02), la risposta che presumo sia OK (00) e byte di fine (EF). Quando invece la canzone termina fornisce una serie di risposte che non so interpretare:

7E 04 3D 00 01 EF 
7E 04 3D 00 02 EF

Si potrebbe, ad esempio, leggere il buffer seriale e capire che la canzone è terminata quando dopo il byte di start (e l’indicazione di 4 bytes) ci arriva un byte col valore 3D. In realtà per la mia applicazione (ma credo anche per un qualsiasi player) non ho molto bisogno di capire quando è terminato un play, ma vedremo. Nel frattempo vi ho fornito tutti i miei appunti.

Downloads

Links

Se questo articolo ti è piaciuto, condividilo su un social:
Se l'articolo ti è piaciuto o ti è stato utile, potresti dedicare un minuto a leggere questa pagina, dove ho elencato alcune cose che potrebbero farmi contento? Grazie :)