WAV Player con Arduino MKR Zero

In questo articolo vi parlo dell’Arduino MKR Zero : una scheda di sviluppo appartenente alla famiglia MKR, dal prezzo contenuto, pensata per applicazioni che non richiedono connettività wireless, hanno bisogno di utilizzare e caricare una batteria e salvare o leggere dati da una scheda microSD. Dopo aver parlato della MKR Zero, faremo un esempio di un WAV Player.

Sponsor

L’Arduino MKR Zero, oggetto dell’articolo, è stato gentilmente offerto da Arduino. Le opinioni qui riportate sono del tutto personali e non influenzate in alcun modo dal fornitore del prodotto.

La famiglia MKR

Quello che si legge un po’ in giro è che la Famiglia MKR (che sta per Maker) nasce per fornire un supporto semplice e rapido alle esigenze IOT dei Makers fornendo un ecosistema compatto, dotato di possibilità di funzionare a batteria, con tutte le board aventi a bordo lo stesso microcontrollore e fornendo quindi lo stesso pinout nonchè una grande disponibilità di shields e carrier boards per aggiungere funzionalità extra quali, per citarne alcune, connettività RS485, CAN, GPS, controllo motori, collegamento di termocoppie ecc.

In realtà tutto questo è vero tranne che per il fatto che la serie MKR sia nata (intendo sin da subito) con l’idea dell’IOT. Difatti tra le prime schede presentate c’era la MKR Zero, oggetto di questo articolo, che non è dotata di connettività. L’idea di dotare la serie MKR di connessioni esterne è nata sicuramente dopo e la Zero è rimasta quindi l’unica a non avere a bordo possibilità di connessioni wireless, ma possiamo aggiungere altri tipi connettività, tipo ethernet, con shields aggiuntive.

La caratteristica principale che hanno in comune tutte le boards della serie MKR è il microcontrollore: usano tutte un ATSAMD21 (Cortex M0+) che abbiamo già incontrato nel dettaglio nell’articolo predente sulla Nano 33 IOT. Altra caratteristica comune è la possibilità di alimentare le boards a batteria con un circuito che esegue automaticamente lo switch tra tensione applicata esternamente (sui pin Vin o sulla porta USB) e batteria nonchè carica della stessa dove è stato previsto l’utilizzo di batterie ricaricabili.

L’utilizzo della batteria, infatti, non segue lo stesso schema per tutte le schede della famiglia: alcune possono essere alimentate con normali batterie alcaline (quindi non c’è possibilità di ricarica), altre con batterie LiPo, altre ancora sia con LiPo che con Li-ION ricaricabili: in questi ultimi due casi la gestione della batteria comprende anche la ricarica, per cui la batteria eventualmente collegata diventa anche una fonte di backup in caso di mancanza di alimentazione primaria.

Le specifiche per le batterie ricaricabili utilizzabili, poi, sono diverse per le varie schede in base alla capacità minima richiesta: alcune board assorbono di più e quindi richiedono una capacità maggiore. Per tutte le batterie ricaricabili è richiesto comunque che la batteria sia 1S : ovvero singola cella, per cui non è assolutamente consigliato mettere più batterie in parallelo per avere capacità maggiori perchè può essere pericoloso in fase di ricarica, dato che le batterie dovrebbero essere caricate in maniera bilanciata (ovvero separatamente).

Nella tabella seguente ho fatto un riassunto delle principali differenze che ci sono tra una board e l’altra della famiglia MKR:

BoardConnettivitàModulo RadioElemento SicurezzaTipo batteriaPrezzoNote
MKR 1000 WiFiWiFiWINC1500SILiPo 1S, min 700mAh€ 30.99(1)
MKR Vidor 4000WiFi, Bluetooth 4.2u-blox NINA-W102SILiPo 1S. min 1024mAh€ 62.90(2)
MKR WiFi 1010WiFi, Bluetooth 4.2u-blox NINA-W102SILiPo 1S, min. 1024mAh€ 27.90
MKR Wan 1300LoRaMurata CMWX1ZZABZNO2 Alcaline AA/AAA€ 35.00(3)
MKR Wan 1310LoRaMurata CMWX1ZZABZSILiIon ricaricabile o LiPo 1S, min 1024mAh€ 33.00
MKR GSM 1400GSM, 3Gu-blox SARA-U201SILiPo 1S, min. 2500mAh€ 59.90(4)
MKR NB 1500Narrow Band (LTE, EGPRS)u-blox SARA-R410M-02BSILiPo 1S, min. 1500mAh€ 66.90
MKR Fox 1200SigfoxMicrochip® Smart RF ATA8520NO2 Alcaline AA/AAA€ 35.00
MKR ZeroNONONOLiPo 1S, min. 700mAh€ 20.90(5)

Note

  1. Su questa board, il micro principale e il modulo WiFi sono inglobati in un unico modulo ATSAMW25. Predere in considerazione la MKR WiFi1010 che costa meno ed è più nuova (ha anche il Bluetooth)
  2. Questa board possiede anche una FPGA progammabile dall’utente
  3. Prendere in considerazione la MKR Wan 1310, che è più aggiornata e supporta le batterie LiPo.
  4. Richiede un’antenna GSM da acquistare a parte. Arduino vende un bundle, più conveniente, che include l’antenna e una Sim Card.
  5. Questa board possiede uno slot per una scheda di memoria microSD

Vedete che alcune schede sono in realtà sostituite da altre più aggiornate, come la WiFi 1000, rimpiazzata dalla WiFi 1010, e la WAN 1300, rimpiazzata dalla WAN 1310. La disponibilità di connessioni wireless c’è tutta, a parte, chiaramente, sulla MKR Zero. La Zero, tra l’altro non possiede nemmeno l’elemento di sicurezza che sarebbe potuto tornare utile nel caso in cui, ad esempio, l’avessimo utilizzata in accoppiata al MKR ETH shield, che consente di collegare la board ad una rete LAN (anche se nei casi di rete cablata il problema dello sniffing del traffico è forse meno sentito).

Se guardate lo schema elettrico della MKR Zero, il chip di crittografia è riportato, ma in realtà sul PCB non viene montato: insomma ci sono i pad ma non sono popolati. In gergo si dice che quei pad sono DNP (Do Not Populate).

Lo Slot per microSD

La Zero, dicevamo, possiede lo slot per la MicroSD che può tornare utile per leggere/scrivere qualsivoglia tipo di dati e quindi creare anche dei logger. E’ vero: è possibile implementare uno slot MicroSD anche sulle altre schede della serie MKR utilizzando l’ MKR SD Protoshield, per cui, acquistando, ad esempio, una MKR WiFi 1010 più l’SD Protoshield, avremmo lo stesso sistema ma dotato di connettività WiFi.

La differenza, però, nell’utilizzare la MKR Zero rispetto ad un’altra MKR con l’SD Protoshield sta nel fatto che la microSD sulla MKR Zero è collegata al bus SPI 1 (SERCOM2, pins da PA13 a PA15) che non ha sbocco all’esterno, per cui nessun pin degli headers è occupato, utilizzando invece l’SD Protoshield la microSD viene collegata al bus SPI 2 (SERCOM1) occupando almeno 4 pin degli headers.

Possibilità di alimentazione

E’ possibile collegare una batteria LiPo da almeno 700mAH al connettore JST che si trova sulla sinistra (considerando il connettore USB posto in alto). E’ necessario un connettore tipo JST PHR2. La batteria viene caricata dalla stessa scheda con una corrente di 350mAH.

Sono quindi disponibili 3 diverse sorgenti per alimentare la scheda: la batteria, la porta USB o il pin VIN. Tutte e 3 le sorgenti di alimentazione vengono inviate ad un regolatore di tensione a basso dropout AP7215-33 (600mA). Tale regolatore accetta già in ingresso 3.3V (fino a 5.5V), per cui anche alimentando a batteria abbiamo sempre i 3.3V necessari a far funzionare la board. La tensione di 3.3V viene anche resa disponibile all’esterno sul pin contrassegnato come VCC.

Oltre alla batteria, quindi, la board si può quindi alimentare esternamente sia dalla porta USB che fornendo una tensione di 5 (max 5.5V) sul pin VIN: in quest’ultimo caso se è collegato anche il cavo USB, la tensione dalla porta USB viene scollegata in automatico. Il pin 5V presente sull’header riporta all’esterno la tensione dalla porta USB o quella applicata sul pin VIN, quindi attenzione: se alimentate la scheda a 5.5V, su quel pin vi ritrovate 5.5V. La linea dei 5V, oltre ad essere inviata al regolatore a 3.3V viene anche utilizzata anche per la carica della batteria. Quando non sono collegati sorgenti a 5V e la scheda viene alimentata esclusivamente dalla batteria, su VIN sarà presente la tensione di batteria.

E’ possibile monitorare la batteria da software dato che la tensione della batteria è riportata, tramite un partitore di tensione, ad un pin analogico dedicato (quindi non riportato sugli headers) che lato sketch viene identificato dalla costante ADC_BATTERY. Per ulteriori informazioni su come leggere la tensione di batteria da un vostro programma potete dare uno sguardo allo sketch apposito

Il Bus I2S e la codifica PCM

A causa della presenza del bus I2S e dello slot MicroSD, che ci permette di caricare files audio in formato WAV, la MKR Zero viene pubblicizzata come adatta per applicazioni audio. In realtà il bus I2S è intrinseco del microcontrollore utilizzato, l’ATSAMD21, per cui tale caratteristica ce l’hanno TUTTE le board della serie MKR e anche alcune Nano (come la 33 IOT) e altre boards ancora: è che, avendola progettata con lo slot, l’idea di partenza era (credo) fare appunto un sistema economico, dedicato soltanto alla gestione dell’audio digitale.

Ma procediamo per gradi: cos’è questo bus I2S?

Si tratta di una periferica che comunica in maniera seriale sincrona, pensata appositamente per la ricetrasmissione dell’audio digitale. Il bus I2S consta di 3 linee: una linea di clock,  una linea di dati e una linea di Word Select che permette di dire alla periferica se i dati che si stanno ricevendo appartengono ad uno o all’altro canale (destro o sinistro in un sistema stereofonico). La velocità del clock del bus varia in funzione della frequenza di campionamento del segnale audio ed è pari a tale valore per il numero di bit per canale per il numero di canali. Se abbiamo quindi un file audio avente una frequenza di campionamento (affronteremo dopo il significato) di 44100Hz, 16bit, stereo, la frequenza di clock sarà pari a:

Il dato audio trasmesso è codificato in PCM; Immaginiamo di riportare un segnale audio analogico, sugli assi cartesiani: il valore in tensione si trova sull’asse Y, mentre sull’asse X si trova il tempo.

Esempio campionamento segnale audio – Immagine by Wikipedia (CC BY-SA 3.0)

Immaginiamo quindi di campionare (leggere) il valore in tensione del segnale ad intervalli di tempo regolari (ogni tot millisecondi, pallino blu sul grafico): questo intervallo di tempo rappresenta appunto la frequenza di campionamento. Il valore analogico letto nel punto di campionamento viene quindi riportato in un valore digitale che può essere ad esempio un numero ad 8 bit, a 16bit, a 24 ecc: questo rappresenta il numero di bit del campione (ad, esempio: 16bit). Chiaramente non potendo un numero digitale contenere qualsiasi valore numerico, il valore analogico letto viene approssimato al valore digitale più consono  (non necessariamente più vicino) tramite appositi algoritmi: questa è quella che viene chiamata quantizzazione.

Adesso abbiamo capito cosa vuol dire quando leggiamo che un file WAV è codificato in PCM, ha una frequenza di campionamento di 44100Hz e il campione è a 16bit. In particolare questi esatti valori numerici corrispondono a quella che viene chiamata Qualità CD e da tutta la storia sulla quantizzazione potete capire perchè c’è sempre una lotta continua tra i sostenitori dell’audio analogico e quelli dell’audio digitale: la trasformazione da analogico a digitale porta inevitabilmente alla perdita di piccolissimi pezzi dato che, appunto, un valore digitale non può contenere tutti i “numeri” esprimibili in analogico e in più c’è la frequenza di campionamento che lascia da parte il pezzo tra un campionamento e il successivo.

Io apprezzo entrambi i sistemi e ammetto candidamente di non riuscire spesso ad apprezzare le differenze tra un brano in qualità CD e uno in analogico: per queste cose sono richieste orecchie molto allenate e impianti audio d’eccellenza. La trasformazione in digitale, dal canto suo, permette però di eliminare disturbi, fruscii, schiocchi e tutto quello che musica non è (ma che magari molti apprezzano lo stesso).

Un File WAV quindi, è abbastanza semplice da gestire proprio perchè contiene i dati codificati direttamente in PCM, che come abbiamo visto è una codifica davvero semplice concettualmente e che ci permette di inviare i dati direttamente ad un DAC (Digital to Analog Converter) per ricostruire l’audio da ascoltare. Se siete curiosi, potete guardare in questa pagina come sono organizzati i dati in un file WAV. Una periferica I2S a bordo di un microcontrollore, in parole povere non fa altro che ricevere o trasmettere un file WAV ed elaborarlo.

Quando la periferica trasmette l’audio in formato I2S è necessario, a valle, un sistema capace di decodificare i valori trasmessi e ritrasformarli in un segnale analogico perchè l’orecchio umano possa ascoltare, dirigendoli anche verso il canale opportuno.

PCM vs PWM

Se la codifica del segnale audio fosse stata in PWM, la conversione sarebbe stata molto più semplice, utilizzando un semplice filtro passa-basso RC. Un segnale PWM ha una frequenza fissa e un duty cycle variabile: la larghezza dell’impulso, tramite il filtro, viene trasformata in un valore di tensione pari a:

Dove D è il valore di tensione del livello logico alto stabilito dal sistema (ad esempio 5V o 3.3V) e DutyCycle rappresenta l’ampiezza dell’onda quadra in percentuale rapportata alla frequenza. Capite quindi che per avere un buon range di tensioni in uscita sono necessari valori elevati di frequenza nonchè una certa disponibilità, da parte del microcontrollore, a generare tanti valori di duty cycle (che sono quantizzati anch’essi, essendo definiti in registri interni del micro) e a fare tutto questo anche con una certa velocità.

Si potrebbe, ad esempio, decodificare il file WAV a volo da codice (oppure includerlo già nella ROM in un formato più semplice da gestire) e quindi trasmetterlo all’esterno in PWM per poi passarlo ad un amplificatore: esistono numerosi esempi come questo per Arduino, ma la qualità generalmente è più bassa e inadatta per applicazioni tipicamente musicali.

Sappiamo che gli amplificatori in classe D si basano proprio sulla trasformazione del segnale audio analogico in PWM, ma in questa sede stiamo parlando di applicazioni su microcontrollori che non sono, in genere, devices prettamente adibiti a scopi audio.

Avendo una buona uscita DAC, invece, non è necessario nemmeno il filtro dato che è possibile generare in uscita direttamente un valore di tensione analogico. Spesso questa soluzione non è conveniente in quanto le periferiche DAC sui microcontrollori hanno una risoluzione molto bassa.

L’ATSAMD21 ha invece un ottimo DAC a 10bit e sul sito di Arduino c’è anche un esempio di play di un file WAV, preso da SD, e trasmesso via DAC ad un amplificatore, qui. Questo esempio utilizza una libreria Arduino che semplifica di molto le cose, AudioZero, tra cui la gestione del DAC e la decodifica del file audio, ma vedete che il file WAV deve essere passato in forma inusuale: 88KHz mono e 8bit.

Qualora vorreste provare e avete già avuto esperienza di utilizzo sistemi audio su altre piattaforme, ne approfitto per aggiungere un’informazione in più riguardo all’utilizzo del DAC da Arduino IDE: per ESP32 (e solo per esso) in Arduino IDE esiste la funzione analogWrite() che genera un segnale PWM e dacWrite() che invece genera un valore di tensione. Ricordo però che l’implementazione di ESP32 in Arduino IDE non è una roba fatta da Arduino ma da terze parti per cui è normale trovare funzioni diverse, non utilizzate invece su schede Arduino ufficiali. Per l’ATSAMD21 non esiste la funzione dacWrite(), ma viene utilizzata ugualmente la analogWrite() dopo aver usato la funzione analogWriteResolution().

L’utilizzo dell’I2S garantisce una qualità migliore e una più semplice gestione del file audio PCM, anche perchè, in genere, gli IC che ricevono il dato sul bus, oltre a decodificarlo e convertirlo in analogico, hanno anche un amplificatore a bordo come vedremo tra poco.

Libreria Arduino Sound

La libreria Arduino Sound è fatta apposta per leggere i files WAV memorizzati su SDCard e farli elaborare dal modulo I2S: i 3 pin di IO del modulo vengono poi collegati ad un sistema in grado di decodificare il segnale e riprodurlo. Arduino Sound, quindi, include sia le funzioni di gestione del modulo I2S, sia le funzioni di gestione della SD card, per cui non è necessario includere le librerie SD. 

Questa libreria si installa dall’IDE come sempre, cercando semplicemente Arduino Sound. Tutte le informazioni e i metodi di questa libreria si trovano sul sito Arduino ufficiale. Dato che la libreria SD è inclusa in questo, torna utile anche la pagina di informazioni sulle funzioni della libreria SD. In particolare, riguardo all’utilizzo della SD sono consentiti i nomi di files in formato 8.3 (8 caratteri nome file, 3 caratteri estensione) per cui nomi di files più lunghi saranno visualizzati troncati con il segno di tilde seguito da un numero. La microSD, poi, deve essere formattata in FAT32. Normalmente, fino ad una capienza di 32GB, l’opzione di formattazione in FAT32 è presente quando col tasto destro sull’unità, in Windows, scegliamo Formatta. Da 64GB a salire non è possibile formattare direttamente in FAT32 dai menù di Windows ed è quindi necessario ricorrere a programmi di terze parti, come Fat32Format

Io normalmente utilizzo invece EaseUS Partition Manager, che permette di gestire anche le partizioni, ma è più complesso da utilizzare e se non smanettate abitualmente con partizioni, potete fare danni.

Ad ogni modo nell’elenco componenti più in basso vi ho lasciato un link dove acquistare microSD da 4GB, che costano pochi spicci e per queste applicazioni sono più che sufficienti.

Ultimo appunto: nella pagina di Arduino c’è scritto di includere <AudioSound.h> ma è sbagliato, bisogna includere <ArduinoSound.h>

Esempio WAV Player

In questo video è illustrato cosa verrà fuori da questo esempio:

Elenco componenti e Codice sorgente si trovano ai paragrafi successivi. Qui darò una breve spiegazione di come funziona questa demo.

Questo esempio deriva dall’esempio WavePlayback incluso con la libreria Arduino Sound, esempio al quale vi rimando sia come programma iniziale da provare, sia per vedere come eventualmente convertire i vostri files audio in WAV 44100Hz 16bit stereo utilizzando il programma free Audacity.

Lo schema da realizzare è il seguente (se non è chiaro, anche nel sorgente sono indicati i collegamenti):

Il display ILI9341 è collegato al bus SPI esterno che fa capo ai pin digital 10 (MISO), 9 (SCK) e 8 (MOSI), più altri due pin a piacere per il Chip Select (ho scelto 6) e Data/Command (7). Il pin di reset del display è tenuto alto collegandolo alla linea VCC, presa dalla MKR Zero, che riporta 3.3V, a questa linea va anche collegata l’alimentazione del display. Il pin LED del display va collegato alla linea dei 5V. Gli altri pin del display rimasti liberi sono quelli relativi al touch screen, che non utilizzeremo.

Come interfaccia utente viene utilizzato un encoder rotativo: le connessioni nel disegno sono relative a quelle breakout boards che vengono vendute su Amazon e che  hanno montato su un encoder rotativo cinese di bassa qualità con delle resistenze di pull-up: in questo caso, anche se c’è la possibilità di abilitare le resistenze di pull-up sui pin della MKR Zero, bisogna collegare comunque anche la 3.3V all’encoder pena comportamenti inaspettati dato che ci sono comunque le resistenze verso la linea di alimentazione che, in assenza di tensione sul pin +, metterebbero in comunicazione i pin tra di loro. Se invece utilizzate un encoder rotativo a se stante, non montato su breakout board, chiaramente non utilizzerete la VCC, ma solo GND e andranno bene le resistenze di pull-up integrate nei pin.  Vedete che ho messo dei condensatori da 1nF tra le linee dell’encoder e GND, questo per un minimo di debounce (che non andrebbe fatto in questo modo, ma funziona).

Per la gestione dell’audio viene utilizzata una breakout board che monta un MAX98357A che prende in ingresso i dati in formato PCM ed ha integrato un amplificatore in classe D. L’integrato in questione è mono, quindi accetta i dati su due canali sul bus e fa l’output su un solo canale. E’ necessario utilizzare un altoparlante che abbia una potenza di almeno 3W e un’impedenza tra 4 e 8Ω. Questa scheda viene alimentata a 5V: non comunica verso Arduino quindi non costituisce problema, è solo Arduino che invia segnali a 3.3V verso la scheda, e vengono interpretati correttamente. Si utilizzano soltanto 3 linee di comunicazione lasciando liberi gli altri pin della breakoutboard: 

  • LRC (collegato alla linea I2S_FS del SAMD21, corrispondente al pin digital 3 della MKR Zero). LRC sta per Left Right Clock, che serve a far capire all’integrato se i dati ricevuti sono relativi al canale destro o sinistro.
  • BCLK (collegato alla linea I2S_BCK, pin 2). BCLK sta per Bit Clock ed indica appunto il clock utilizzato per la trasmissione dei dati.
  • DIN (collegato alla linea I2S_SD0, pin 2). DIN = Data IN.

Quindi, in sostanza, oltre alla MKR Zero, abbiamo utilizzato 3 breakout boards: quella col display munito di controller ILI9341, quella con un encoder rotativo, e quella con il decoder/amplificatore I2S.

Quando si avvia il programma, compare la lista di files trovati sulla scheda (vengono mostrati solo files con estensione WAV) e la rotazione dell’encoder in un verso o nell’altro permette di scegliere un file specifico mentre la pressione permette di riprodurlo. Durante la riproduzione di un file, invece, la rotazione dell’encoder permette di impostare il volume, mentre la pressione stoppa e torna indietro alla lista files.

Se nella radice è presente un file TXT avente lo stesso nome del file WAV, il file di testo viene letto e scritto durante il play del file WAV stesso, per cui potete creare un file TXT per ogni WAV scrivendo dentro cose come titolo, descrizione ecc. 

Dato che lo scorrimento dei files sul display me lo sono inventato io, lascio qua un’immagine esplicativa di come funziona, con le variabili associate:

Ho in pratica definito una Finestra che imposta quanti files devono essere visualizzati sul display (MAX_FILES_ON_DISPLAY). Attualmente questa costante è calcolata in automatico in base alla grandezza del font scelto, tenendo conto che la libreria utilizzata usa un font standard scalandolo di multipli di 8 pixel in verticale e 5 in orizzontale (il font standard è 5×8). Tutti i nomi di files sono salvati in RAM con un proprio indice numerico a base zero.

Qui potevo fare di meglio utilizzando un array di char anzichè String specie perchè i nomi di files sono nel formato 8.3 e mi bastavano 13 caratteri per elemento. Ma confido in voi.

Quando si esegue la selezione, si tiene conto della posizione del cursore nella finestra (rowPos) e, in caso di pressione, si fa un calcolo per capire a quale file index corrisponde (fileIndexSelected): il calcolo viene fatto in base alla posizione attuale del cursore e all’indice di file visualizzato in cima alla finestra (fileIndexOnTop): quest’ultimo è un valore che viene aggiornato nel caso in cui il numero di files trovati supera la capacità dello schermo, per cui andando all’ultimo file e scorrendo verso il basso, la lista scorre anch’essa.

Gli aggiornamenti sul display sono lenti perchè la libreria utilizzata non usa framebuffer per cui ogni singola operazione di disegno viene convalidata e il display aggiornato, per cui è chiaro che noterete dei rallentamenti.

A volte durante il play di files WAV particolarmente grossi capita che, premendo l’encoder (che è gestito tramite interrupt), non si riesce ad uscire (il file continua a suonare) oppure si verifica una situazione di stallo: il display viene cancellato molto lentamente cercando di tornare alla selezione dei files ma ad un certo punto si blocca: non ho capito perchè accade questa cosa e il problema sarebbe da ricercare nella modalità in cui viene gestita la periferica I2S, per ora posso solo supporre si tratti di problemi relativi alla manipolazione della RAM. Se riuscite a trovare una spiegazione potete contattarmi.

Elenco componenti

Codice sorgente

Il codice sorgente si trova sul mio Github: se vi piace o vi torna utile, non dimenticate di mettere una stellina.

Links

Lascio dei links che possono tornare utili per approfondire l’argomento

 

 

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