Utilizzo modulo VS1053b

In realtà ho preso il VS1053b di Adafruit proprio perché aveva lo slot SD integrato e credevo che il marchio mi avesse aiutato in quanto più conosciuto e rinominato…
Stamperò il millis e farò qualche altro tentativo poi passiamo al montaggio per ora dividerò il tempo sperando che il tutto regga… alla mala ho sempre un buon relè meccanico che stacca tutto :joy:

Io utilizzo la versione con "flash" invece che con "SD" (la trovo più comoda ed affidabile, anche se di capaicta più ridotta ... comunque 8 MBytes sono un bel po' per effetti e messaggi :wink:) in uno dei miei progetti (lo SpeakingClock la cui descrizione trovi su QUESTO numero di "Elettronica In") e mi ci trovo piuttosto bene, semplice da usare, discreta qualità audio, si comanda molto bene con l'apposita libreria ... prova a dargli un'occhiata :wink:

Guglielmo

Si è vero che c'è lo slot, ma è sempre il microcontrollore a cui attacchi la shield che si deve occupare di leggere ed inviare al decoder. Il DFMiniPlayer invece se la gestisce da solo, lato microcontrollore nemmeno la vedi la SD.

Comunque secondo me è possibile fare tutto anche con quanto già hai ovvero la Nano Every e la shield VS1053b.

La modalità con interrupt di cui accennava @Maurotec mi sembra quella migliore e non dovrebbe impedire al micro di fare altro in parallelo.

Considerate le specifiche di funzionamento che hai descritto e la scelta di usare la libreria JC_Button, secondo me l'algoritmo può essere semplificato evitando di usare tutte quelle variabili boolean usando i metodi già previsti nella libreria.
Potresti eventualmente rendere un po' più immediato e leggibile lo switch/case raccogliendo le istruzioni associate alle transizioni di stato in delle funzioni specifiche void playOn(), void playOff() etc etc

Appena possibile lo vado a vedere subito! Purtroppo per le mie idee non ce la facevo con la memoria interna :grin:

Si infatti tutto quel miscuglio non piace neanche a me ma ci sono stato davvero molto per raggiungerlo e c’era l’idea di ripulirlo… la libreria ho visto che non pesa neanche molto quindi credo di utilizzarla a prescindere… ma per quello che riguarda gli interrupt io lo uso già infatti il codice non si blocca ma il problema è che cambia il tempo… oggi se riesco stampo il millis prima e dopo

Non ho provato il tuo sketch ma credo anche io che il problema è che chiami in continuazione il metodo startPlayingFile() che disabilita/abilita gli interrupt a livello globale compreso quello che fa avanzare millis() (cosa che secondo me non è nemmeno necessaria usando l'interrupt sul pin come nel tuo caso).

Devi fare in modo che il metodo venga chiamato solo una volta quando necessario e poi basta (se provi lo sketch simulato) puoi vedere che i Serial.println() vengono eseguiti solo quando c'è una transizione tra uno stato ed il successivo.

In che senso? Io lo chiamo solo quando la condizione viene a verificarsi… il comando start play c’è solo una volta, intendi che viene richiamato più volte per via di come è scritto il codice?

Questa condizione rimane vera fintanto che il pulsante è premuto e quindi continui a chiamare il metodo almeno per un secondo di fila, dopodiché buttonEnabled diventa false e smetti. In questo secondo però la libreria ogni volta ha disabilitato/abilitato gli interrupt interferendo con la funzione millis()

Per averne conferma, prova ad aggiungere un Serial.println("no interrupt") a scopo di debug.

JC button ha due metodi isPressed e wasPressed.

void loop() {
    playBtn.read();
    if(playBtn.wasPressed()) {
        Serial.println(".");
    }

Stampa un punto soltanto quando è stato premuto il pulsante.

Che è molto simile al tuo tranne per lo switch case, bene e dice che con questo codice ha sempre il problema, i 3 secondi gli diventano 9.

Ciao.

È una libreria che conosco poco, ma se le cose stanno così allora il malfunzionamento che riscontra non ha senso... C'è qualcosa che ci sta sfuggendo :fearful:.

Che a pensar male si fa presto, cioè il problema è tra la sedia e la tastiera? :smiley:

Io però sulla libreria ne so poco, non ho contezza di ciò che fa e dove lo fa.
Nel loop non vedo metodi ::run() per fare cose in polling, e allora penso che leggere e scrivere i 32 byte sia fatto nella ISR ma sono supposizioni.

Ciao.

Si è cosi infatti.
Il problema è che anche nella ISR disattiva e riabilita gli interrupt a livello globale...
Di fatto la ISR è questa (i 32 byte sono inviati nel metodo feedBuffer_noLock()) :

void Adafruit_VS1053_FilePlayer::feedBuffer(void) {
  noInterrupts();
  // dont run twice in case interrupts collided
  // This isn't a perfect lock as it may lose one feedBuffer request if
  // an interrupt occurs before feedBufferLock is reset to false. This
  // may cause a glitch in the audio but at least it will not corrupt
  // state.
  if (feedBufferLock) {
    interrupts();
    return;
  }
  feedBufferLock = true;
  interrupts();

  feedBuffer_noLock();

  feedBufferLock = false;
}

Io 'sta cosa fatico a comprenderla, al massimo disattiva solo l'interrupt che stai usando se proprio devi!!!
Per curiosità mi sono andato a vedere anche il codice dell'altra libreria che si trova nel repository per questo modulo MP3.

L'approccio è più o meno lo stesso: l'utente imposta se usare un interrupt esterno oppure generato con un timer e nella ISR viene fatto il "refill" del buffer, però in questa seconda libreria non si va ad interferire con gli interrupt globali nel caso in cui a "comandare" sia l'interrupt esterno (ovvero la modalità di funzionamento di default).

@gaquilano io proverei a dargli una chance e vedere come va.

Eccomi, finalmente sono riuscito a riaccendere un pò il pc... Intanto grazie per le tantissime informazioni e risposte che mi avete dato!
Ho provato a stampare il millis()
Mettendolo prima e dopo in questo modo:

Serial.println("play track002.mp3");
Serial.println(millis());
musicPlayer.startPlayingFile("/track002.mp3");
Serial.println(millis());

Ottengo questo su monitor

play track002.mp3
21957
22307
Stop track002.mp3

Il tempo in questo caso è sempre quello iniziale ovvero i 3 secondi che diventano 9 e sto utilizzando il codice di @Maurotec ad inizio discussione post#15.
Ho notato anche che senza la libreria JC_Button, se aggiungo un testo a scopo di debug, questo viene ripetuto finche il pulsante rimane premuto e/o fino allo scadere dei 3 secondi.
Con la libreria no, il testo a scopo di debug come vedete anche nella stampa di millis viene visualizzato una volta sola quando va in play e una volta sola quando va in stop.
Non ho ancora avuto modo di provare la libreria * Arduino_Library-vs1053_for_SdFat*
Non ho capito bene il discorso dei byte, comunque il file attuale che sto utilizzando ha una dimensione di 470kb circa e un bitrate di 320kbps.

Ok, puoi fare copia ed incolla del codice, così per aggiornare la situazione.

Interessante se la matematica non è una opinione 22307 - 21957 = 350 vuole dire che la chiamata a funzione impiega 350ms per essere eseguita.

Si è normale ed è dovuto al metodo wasPressed, che è da interpretare come "e stato premuto" quando il loop ricomincia esegue la read() su quel pulsante e poiché lo ha già notificato che è stato premuto alla seconda chiamata restituisce false. Mentre se usi il metodo isPressed() si comporta coma una digitalRead().

Ciao.

Eccomi, ho cronometrato il tempo dalla pressione del pulsante e quindi la partenza del brano al termine del brano. Passano circa 8 secondi impostando "interval a 2000".
Il brano in totale dura circa 12 secondi per questo sono sceso a 2000 in quanto 3000 poteva confondermi con la fine del brano.
Ho inserito come vedete nel codice alcune stampe di millis (come se non ci fosse un domani) e noto che dalla pressione del pulsante alla fine del brano segna matematicamente 2000. Quindi il problema non stà nel millis che viene conteggiato in maniera giusta da che vedo ma nel modo in cui il tempo trascorre durante questo play ...
Ecco il codice:

#include <JC_Button.h>
#include <SPI.h>
#include <Adafruit_VS1053.h>
#include <SD.h>

//Define Pin to use VS1053
#define CLK 13
#define MISO 12
#define MOSI 11
#define BREAKOUT_RESET 7
#define BREAKOUT_CS 10
#define BREAKOUT_DCS 8
#define CARDCS 4
#define DREQ 3

Adafruit_VS1053_FilePlayer musicPlayer = Adafruit_VS1053_FilePlayer(BREAKOUT_RESET, BREAKOUT_CS, BREAKOUT_DCS, DREQ, CARDCS);

int x;
int x_min = 30;                             // Set min value pwm
int x_max = 250;                            // Set max value pwm

Button playBtn(2);
const int led = A6;
const int pwm = 6;

byte playState = 0;
uint32_t saveMillis;
uint16_t interval;

void setup() {
  Serial.begin(9600);

  //Setting for VS1053
  if (!musicPlayer.begin()) {
    Serial.println("VS1053 Error");
    while (1);
  }

  if (!SD.begin(CARDCS)) {
    Serial.println("VS1053 SD Error");
    while (1);
  }

  musicPlayer.setVolume(0, 0);
  musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT);
  //End setting to VS1053

  pinMode(pwm, OUTPUT);
  pinMode(led, OUTPUT);

  playBtn.begin();

  delay(10);
}

void loop() {
  playBtn.read();
  if ((playState == 0) && playBtn.wasPressed()) {
    playState = 1;
    interval = 2000;
    saveMillis = millis();
    digitalWrite(led, HIGH);
    Serial.println("play track002.mp3");
    Serial.println("tempo alla pressione del pulsante ");
    Serial.println(millis());
    musicPlayer.startPlayingFile("/track002.mp3");
    Serial.println("tempo inizio play ");
    Serial.println(millis());
  }
  if (playState == 1) {
    if (playBtn.isReleased()) {
      Serial.println("tempo rilascio pulsante ");
      Serial.println(millis());
      digitalWrite(led, LOW);
      Serial.println("Stop track002.mp3"); 
      musicPlayer.stopPlaying();
      Serial.println("tempo fine play ");
      Serial.println(millis()); 
      
      playState = 0;
    } else {
      if (millis() - saveMillis >= interval) {
        digitalWrite(led, LOW);
        interval = 5000;
        saveMillis = millis();
        playState = 2;
        Serial.println("Stop track002.mp3");
        musicPlayer.stopPlaying();
        Serial.println("tempo fine play ");
        Serial.println(millis());   
      }
    }
  }
  if (playState == 2) {
    if (millis() - saveMillis >= interval) {
      playState = 0;
    }
  }
}

Risultato a monitor:

play track002.mp3
tempo alla pressione del pulsante 
26578
tempo inizio play 
26929
Stop track002.mp3
tempo fine play 
28579

Secondo le stampe di millis la riproduzione è durata 28579 - 26929 = 1650 (1,65 secondi).

Se non corrisponde alla realtà il contatore di millis non viene incrementato ogni millesimo di secondo ma ogni tanto troppo non viene incrementato.

Non sono sicuro ma con una scheda su cui c'è montata una MCU ARM questo non dovrebbe accadere. Stessa cosa su ESP32.

Ciao.

In realtà se prendiamo in considerazione il millis dalla pressione del pulsante allo stop sono esattamente 2000 ovvero il tempo impostato… il problema è che questi che lui conteggia come 2000 in realtà sono circa 8 secondi da cronometro…
Comunque 350 + o 350 - in qualche modo il
Conteggio viene falsato, probabilmente dall’interrupt utilizzato. Ho provato anche senza ma alla pressione del pulsante il
Brano parte e si spegne al suo termine e non quando rilascio il pulsante

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.