DFPlayer Mini gets stuck when interrupted

I have two buttons, one for reset (because power-on-reset doesn't work for some reason) and one for the "Stop what is playing now, and if nothing is playing, play next song" function. The button responsible for controlling the playback status is tied to an interrupt routine with software debouncing. It seemed to work fine (with minor glitches) for two units using the MH2024K-24SS version of the DFPlayer Mini-compatible module. However, I bought a new module using the JL Tech chip AA1838CJ691F (its logo looks like the Pi symbol). It's causing me woes. Test codes work well. All modules play nicely when in standalone or if I let it play all the way through without interruption. The symptom appears and disappears depending on the SD card being used and if I press the Stop/Next button before the song ends, but all of them eventually get stuck on something and the playback stops. The code is as written below.

#include <DFRobotDFPlayerMini.h>
#include <SoftwareSerial.h>

SoftwareSerial mySoftwareSerial(10, 11);
DFRobotDFPlayerMini myDFPlayer;
void printDetail(uint8_t type, int value);

int songIndex = 1;

// This is the amount of songs on your SD card, greeting inclusive.
const int maxSongCount = 41;

// This will be the playback button
const int button = 2;
// If you want to use other pins for status detection, change this.
const int statusPin = A0;
volatile bool stopped = false;
volatile bool state = false;
volatile bool led = false;

// If you want to use other pins, change this.
const int ledPin = LED_BUILTIN;

unsigned long pm = 0;

// Change this to change how frequently the motor changes the direction
const long interval = 1000;

void setup() {
  pinMode(button, INPUT_PULLUP);
  pinMode(statusPin, INPUT);
  pinMode(LED_BUILTIN, OUTPUT);

  mySoftwareSerial.begin(9600);
  Serial.begin(115200);
  Serial.println();
  Serial.println(F("Loki v1.1 starting up..."));
  delay(2000);
  if (!myDFPlayer.begin(mySoftwareSerial)) {  //Use softwareSerial to communicate with mp3.
    Serial.println(F("Unable to begin:"));
    Serial.println(F("1.Please recheck the connection!"));
    Serial.println(F("2.Please insert the SD card!"));
    while (true) {
      delay(0); // Code to compatible with ESP8266 watch dog.
    }
  }
  Serial.println(F("DFPlayer Mini online."));
  myDFPlayer.setTimeOut(1500);
  myDFPlayer.volume(30);  //Set volume value. From 0 to 30
  myDFPlayer.playMp3Folder(1);  //Play the first mp3
  delay(250);
  while (digitalRead(statusPin) == LOW) {
    // Wait while the track finishes playing
  }
  EIFR = 1;
  delay(7000);
  attachInterrupt(digitalPinToInterrupt(button), playbackCtrl, FALLING);
  Serial.println("Ready");
}

void loop() {

  unsigned long cm = millis();
  if (cm - pm >= interval) {
    pm = cm;
    led = !led;
  }
  digitalWrite(ledPin, led);
  if (state == true) {
    Serial.print("Attempting to play index ");
    Serial.print(songIndex);
    Serial.println(" file");
    myDFPlayer.playMp3Folder(songIndex);
    delay(50);
    while (digitalRead(statusPin) == LOW) {
      //Serial.println("playing ");
    }
    state = false;
  }
  if (state == false) {
    delay(50);
    if (stopped != true) {
      Serial.println("Finished, stopping");
      myDFPlayer.stop();
      stopped = true;
    }
  }
}

void playbackCtrl() {
  static unsigned long lit = 0;
  unsigned long inttime = millis();
  if (inttime - lit > 1500) {
    if (state == true) {
      myDFPlayer.stop();
      state = false;
      stopped = true;
    }
    if (state == false) {
      myDFPlayer.stop();
      state = true;
      stopped = true;
    }
    songIndex++;
    if (songIndex > maxSongCount || songIndex < 2) {
      songIndex = 2;
    }
  }
  lit = inttime;
}

I'm pretty sure I messed something up during programming, so any pointers will be appreciated. Thank you in advance!

It's a very bad idea to call a SoftwareSerial method inside an interrupt handler. As SoftwareSerial depends on interrupts to be working, it won't work inside an interrupt handler where interrupts are disabled.

Just set a flag in the interrupt handler and react on that in the loop to do what you actually want to do.

Of course you have to eliminate the while loop in your loop() as this freezes the whole sketch.

1 Like

The interrupt portion is this part.

void playbackCtrl() {
  static unsigned long lit = 0;
  unsigned long inttime = millis();
  if (inttime - lit > 1500) {
    if (state == true) {
      myDFPlayer.stop();
      state = false;
      stopped = true;
    }
    if (state == false) {
      myDFPlayer.stop();
      state = true;
      stopped = true;
    }
    songIndex++;
    if (songIndex > maxSongCount || songIndex < 2) {
      songIndex = 2;
    }
  }
  lit = inttime;
}

Strange thing is, this code did work on other units, just not this one for some unknown reason.
I'll just take them out and see if they work or not (they were there just to make it absolutely sure that it is stopped)

Also, the while loop is there so it won't attempt to go to the next part of the code while the BUSY pin is not in an idle state; As soon as it returns to the idle state, it will move down.

Aha! Turns out ignoring the hardware status was the answer!
Before:

    myDFPlayer.playMp3Folder(songIndex);
    delay(50);
    while (digitalRead(statusPin) == LOW) {
      Serial.println("playing ");
    }

After:

    myDFPlayer.playMp3Folder(songIndex);
    delay(50);
    while (stopped == false) {
      Serial.println("playing");
    }

Note that all of the myDFPlayer.stop(); calls inside the interrupt has been removed too.

That change probably fixed it.

Did you compile the code for the other units with a recent version of the IDE too?

When I only changed the interrupt, it wouldn't go past the first track (after intro). It is when I made it ignore the hardware input it finally registered the button presses successfully. After some testing and fixing I probably will share the full build instructions on the project share hub.

No, I am still using 1.8.12. Forgot to add this to the email.

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