Arduino controlled DFPlayer Mini

About the post

In my last post I had explained how to deal with the YX5300. In this post, I will focus on another MP3 player, the DFPlayer Mini, and how to control it with the Arduino.

  • Technical data and pinout
  • SD card file structure
  • Circuit for serial control with Arduino
  • The DFRobotDFPlayerMini library
  • A sketch with menu navigation
  • Control via pushbuttons
  • DFPlayer Mini vs. YX5300 module
DFPlayer Mini: front and back
Small but mighty, the DFPlayer Mini

Specifications / Features of the DFPlayer Mini

Overview

The DFPlayer Mini is available for 5-10 euros from Amazon or other online shops. Very impressive is the small size of the module, because it is hardly larger than the Micro SD card slot. No less impressive I find that there is even space for an amplifier on this device, so that you can connect loudspeakers up to 3 watts directly. A data sheet for the DFPlayer Mini can be found on the internet e.g. here. Here are some basic data:

Power supply 3.2 – 5.0 V
Current consumption (standby)~ 20 mA
Supported file typesMP3 and WAV
Supported SD cardsMicro SD(HC) up to 32 GB
FormatFAT16 / FAT 32
Communication Seriell RX/TX, baud rate: 9600
USB portUSB 2.0 (Flashdrive / PC)
Audio outputsLoudspeaker – up to 3W (amplifier on board)
DAC (for headphones or amplifiers)

Pinout

Pinout and pin functions of the DFPlayer Mini
Pinout of the DFPlayer Mini
Pinout and pin functions of the DFPlayer Mini

It should be noted that you have to put a 1 kOhm resistor before the RX input, otherwise you produce a very unsightly, loud hum. 

The Adkeyx and IOx connectors are a pretty ingenious thing that allow you to control the DFPlayer Mini largely with buttons. More on that further down. 

Folder and file structure of the SD card

The DFPlayer Mini expects the folder and file names in a specific format. The rules for file naming and the maximum number of files per directory depend on the type of directory. 

Note: If there are problems with the SD card, check if you have multiple partitions there. Sometimes there is a small boot partition on the SD card that can cause problems. How to fix the problem, I described in my last post.  

1. Main directory

The main folder of the SD card can contain up to 3000 wav or mp3 files. They must be called 0001.mp3 (or 0001.wav), 0002.mp3 …. 3000.mp3. Here, however, there is a strange issue that the files have to be copied in exactly the order of their names. If you tell the module it shall play 0001.mp3, but 0007.mp3 was copied first, then 0007.mp3 will be played. Personally, I would advise to not copy files to the main folder. Other folders do not have this issue. 

2. Standard folders

You can create up to 99 standard folders, which need to be named according to the scheme 01, 02, 03 …. 99. Up to 3000 files fit into each folder, but only the first 255 can be addressed directly via the serial commands. This means that a command like “play file number 627” is not possible in the standard directories. You would need to go there with “next” instructions, which is not very convenient. The file names must have the format 001xxxxx.mp3 (or wav), 002xxxxx.mp3, ….. 255xxxxx.mp3. “xxxxx” is freely selectable and can have more than the 5 digits indicated here. Spaces are also allowed. 

3. Special folder “MP3”

This folder must be named exactly as “MP3.   Up to 3000 files with the name 0001.mp3 (or wav), 0002.mp3, ….. 3000.mp3 fit into this folder. Unlike the main folder, all files are directly accessible and there are no problems with the order. 

4. Special folder “ADVERT”

The same rules apply as for the MP3 directory. The ADVERT directory has a special function. If you play a song from one of the other directories and call a file from the ADVERT directory, the former song is only interrupted. After the ADVERT play is finished, the former song continues. It’s like an advertisement and that’s how the name of the directory already suggests it.

The circuit for serial operation

The circuit for operation via the serial interface is relatively simple. Note that a 1 kOhm resistor is put before the RX input of the DFPlayer module.

Note: In my example circuit, I supply the DFPlayer with power from the Arduino. When using larger loudspeakers up to the max. 3 watts the total power consumption of the Arduino should be considered and not exceed 500 mA.  

Fritzing: DFPlayer Mini control with the Arduino - circuit using a breadboard
DFPlayer Mini control with the Arduino – the circuit
Foto: Control of the DFPlayer Mini with an Arduino
And this is what the circuit looks like on the breadboard

Control via the library
DFRobotDFPlayerMini

The DFPlayer Mini control with Arduino is not difficult, as there are a number of libraries on Github. I use the DFRobotDFPlayerMini library, but that doesn’t mean the others are bad. I just tried it first and stayed with it. 

As usual, you install the library by downloading the zip file and unpacking it in the “Arduino-libraries” folder. The included sample sketch “FullFunction.ino” provides a good overview of all functions. I modified it a little so that you can call the commands via the serial monitor. Here is the result:

/***************************************************
 Modified (by Wolfgang Ewald) Version of the FullFunction.ino example sketch of the DFRobotDFPlayerMini library:
 
 DFPlayer - A Mini MP3 Player For Arduino
 <https://www.dfrobot.com/product-1121.html>
 
 ***************************************************
 This example shows the all the function of library for DFPlayer.
 
 Created 2016-12-07
 By [Angelo qiao](Angelo.qiao@dfrobot.com)
 
 GNU Lesser General Public License.
 See <http://www.gnu.org/licenses/> for details.
 All above must be included in any redistribution
 ****************************************************/

/***********Notice and Trouble shooting***************
 1.Connection and Diagram can be found here
<https://www.dfrobot.com/wiki/index.php/DFPlayer_Mini_SKU:DFR0299#Connection_Diagram>
 2.This code is tested on Arduino Uno, Leonardo, Mega boards.
 ****************************************************/

#include "Arduino.h"
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"

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

void setup()
{
  mySoftwareSerial.begin(9600);
  Serial.begin(9600);
  
  Serial.println();
  Serial.println(F("DFRobot DFPlayer Mini Demo"));
  Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)"));
  
  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);
  }
  Serial.println(F("DFPlayer Mini online."));
  printHelp();
  
  myDFPlayer.setTimeOut(500); //Set serial communictaion time out 500ms
  
  //----Set volume----
  myDFPlayer.volume(10);  //Set volume value (0~30).
 // myDFPlayer.volumeUp(); //Volume Up
 // myDFPlayer.volumeDown(); //Volume Down
  
  //----Set different EQ----
  myDFPlayer.EQ(DFPLAYER_EQ_NORMAL);
//  myDFPlayer.EQ(DFPLAYER_EQ_POP);
//  myDFPlayer.EQ(DFPLAYER_EQ_ROCK);
//  myDFPlayer.EQ(DFPLAYER_EQ_JAZZ);
//  myDFPlayer.EQ(DFPLAYER_EQ_CLASSIC);
//  myDFPlayer.EQ(DFPLAYER_EQ_BASS);
  
  //----Set device we use SD as default----
//  myDFPlayer.outputDevice(DFPLAYER_DEVICE_U_DISK);
  myDFPlayer.outputDevice(DFPLAYER_DEVICE_SD);
//  myDFPlayer.outputDevice(DFPLAYER_DEVICE_AUX);
//  myDFPlayer.outputDevice(DFPLAYER_DEVICE_SLEEP);
//  myDFPlayer.outputDevice(DFPLAYER_DEVICE_FLASH);
  
  //----Mp3 control----
//  myDFPlayer.sleep();     //sleep
//  myDFPlayer.reset();     //Reset the module
//  myDFPlayer.enableDAC();  //Enable On-chip DAC
//  myDFPlayer.disableDAC();  //Disable On-chip DAC
//  myDFPlayer.outputSetting(true, 15); //output setting, enable the output and set the gain to 15
  

}

void loop(){
  if(Serial.available()){
    readCommand();
  }
 
  if (myDFPlayer.available()) {
    printDetail(myDFPlayer.readType(), myDFPlayer.read()); //Print the detail message from DFPlayer to handle different errors and states.
  }
}

void readCommand(){
  char cmd = ' ';
  int value1, value2 = 0;
  cmd = Serial.read();
  value1 = Serial.parseInt();
  value2 = Serial.parseInt();
 
  switch(cmd){
    case 'h': 
      printHelp();
      break;
      
    case '>':
      myDFPlayer.next();
      break;
      
    case '<':
      myDFPlayer.previous();
      break;
      
    case 'p':
      if(value2 == 0) myDFPlayer.play(value1);
      else if(value1 != 0) myDFPlayer.playFolder(value1, value2);
      break;

    case 'P':
      if(value2 == 0) myDFPlayer.playMp3Folder(value1); 
      else if(value1 != 0)myDFPlayer.playLargeFolder(value1, value2);
      break;
    
    case '+':
      myDFPlayer.volumeUp(); 
      break;
      
    case '-':
      myDFPlayer.volumeDown();
      break;
      
    case 'v':
      myDFPlayer.volume(value1);
      break;
      
    case 'b':
      myDFPlayer.pause();
      break;

    case 's':
      myDFPlayer.start();
      break;
          
    case 'z':
      myDFPlayer.sleep();
      break;
      
    case 'L':
      if(value1 == 0) myDFPlayer.enableLoopAll();
      else myDFPlayer.loopFolder(value1);
      break;
    
    case 'l':
      if(value1 == 0) myDFPlayer.disableLoopAll();
      else myDFPlayer.loop(value1);
      break;
    
    case 'A':
      myDFPlayer.advertise(value1);
      break;
    
    case 'a':
      myDFPlayer.stopAdvertise();
      break;
    
    case 'q':
      if(value1 == 1) Serial.println(myDFPlayer.readState()); 
      else if(value1 == 2) Serial.println(myDFPlayer.readVolume());
      else if(value1 == 3) Serial.println(myDFPlayer.readEQ());
      else if(value1 == 4) Serial.println(myDFPlayer.readFileCounts());
      else if(value1 == 5) Serial.println(myDFPlayer.readFolderCounts());
      else if(value1 == 6) Serial.println(myDFPlayer.readCurrentFileNumber());
      break;
    default:
      Serial.println("Ungültiges Kommando");
      break;
  }

}

void printHelp(){
  Serial.println("DFPlayer Commands:");
  Serial.println(" h - help");
  Serial.println(" > - next ");
  Serial.println(" < - previous");
  Serial.println(" p3 - play");
  Serial.println(" p3,5 - play folder 3, file 5");
  Serial.println(" P3,5 - play large folder 3, file 5");
  Serial.println(" P3 - play file 3 in MP3 folder"); 
  Serial.println(" + - volume up");
  Serial.println(" - - volume down");
  Serial.println(" v10 - set volume to 10");
  Serial.println(" b - Pause");
  Serial.println(" s - start ");
  Serial.println(" z - sleep ");
  Serial.println(" L - enable loop all");
  Serial.println(" l - disable loop all");
  Serial.println(" L3 - loop folder 3");
  Serial.println(" l3 - loop file 3");
  Serial.println(" A3 - advertise file 3");
  Serial.println(" a - stop advertise "); 
  Serial.println(" qx - query No. x");
  Serial.println("     x = 1 - read state");
  Serial.println("     x = 2 - read volume");
  Serial.println("     x = 3 - read equalizer");
  Serial.println("     x = 4 - read file counts");
  Serial.println("     x = 5 - read current file number");
  Serial.println("     x = 6 - read file counts in folder");
  Serial.println("     x = 7 - read folder counts");
}

void printDetail(uint8_t type, int value){
  switch (type) {
    case TimeOut:
      Serial.println(F("Time Out!"));
      break;
    case WrongStack:
      Serial.println(F("Stack Wrong!"));
      break;
    case DFPlayerCardInserted:
      Serial.println(F("Card Inserted!"));
      break;
    case DFPlayerCardRemoved:
      Serial.println(F("Card Removed!"));
      break;
    case DFPlayerCardOnline:
      Serial.println(F("Card Online!"));
      break;
    case DFPlayerUSBInserted:
      Serial.println("USB Inserted!");
      break;
    case DFPlayerUSBRemoved:
      Serial.println("USB Removed!");
      break;
    case DFPlayerPlayFinished:
      Serial.print(F("Number:"));
      Serial.print(value);
      Serial.println(F(" Play Finished!"));
      break;
    case DFPlayerError:
      Serial.print(F("DFPlayerError:"));
      switch (value) {
        case Busy:
          Serial.println(F("Card not found"));
          break;
        case Sleeping:
          Serial.println(F("Sleeping"));
          break;
        case SerialWrongStack:
          Serial.println(F("Get Wrong Stack"));
          break;
        case CheckSumNotMatch:
          Serial.println(F("Check Sum Not Match"));
          break;
        case FileIndexOut:
          Serial.println(F("File Index Out of Bound"));
          break;
        case FileMismatch:
          Serial.println(F("Cannot Find File"));
          break;
        case Advertise:
          Serial.println(F("In Advertise"));
          break;
        default:
          break;
      }
      break;
    default:
      break;
  }  
}

The only thing that doesn’t work yet, at least, are the queries (“q” commands in the menu). I think I’ve got to go deeper at a later stage. If you find that out, I’d be grateful for a hint.

In my last post I showed how to control the YX5300 MP3 module with your smartphone. This could be transferred to the DFPlayer Mini with relatively little effort.  

Does it work without a library?

Controlling the DFPlayer Mini with the Arduino without a library is no witchcraft, as the data sheet is quite easy to understand. This is the structure of the commands:

DFPlayer control with the Arduino - structure of serial commands

Each command sequence begins with “7E”. This is followed by VER (version), which is basically “FF”. “Len” is the command length in bytes. This does not count start bytes, end bytes, and checksum. Normally, this means six bytes remain. “CMD” is the actual command and there is a list in the data sheet for this. “Feedback” controls whether you get a response from the module. There is only “01” for feedback and “00” for no feedback. “para1” and “para2” are – not surprisingly – the command parameters. These are also listed in the data sheet. The check sum gives additional security, but you can also omit it. The data sheet explains how to calculate the checksum.

Here’s an example. To play a specific song in a standard folder, the command 0x0F is used. If you want to play song 002 in folder 01 and no feedback is required, the command sequence without checksum is:

7E FF 06 0F 00 01 02 EF

The bytes are transmitted individually via Serial.write(xth byte). “Serial” must be replaced by the defined SoftwareSerial. It’s quite hard to implement the commands, so you can be glad that there are libraries. But personally, I always aim to understand what is happening behind the scenes.

Control via pushbuttons

There is another option to control the DFPlayer Mini. As mentioned above, many functions can also be used via the Adkeyx and IOx connector pins 9, 11, 12 and 13. 

The IOx connectors are connected to GND via pushbuttons. Depending on whether you press short or long, the next song is played or the volume is increased or the previous file is played or the volume decreases. 

With the ADKEYx connectors, various functions can be controlled by adding additional resistors. I’ve tried it and it works perfectly.

By the way, “Segment X” means “play song No. X”. However, the order of copying the songs is again important, regardless of the type of folder (!). 

Circuit diagram for connection of pushbuttons to ADKEY and IO without resistors

Connection of pushbuttons to ADKEY and IO without resistors
Circuit diagram for connection of buttons to ADKEY with resistors
Connection of pushbuttons to ADKEY with resistors

DFPlayer Mini vs. YX5300

Now that I have tested both modules, I have to say that both are quite similar in terms of functionality. However, the DFPlayer Mini is much more flexible with its key functions compared to the YX5300 module. It’s an advantage of the DFPlayer Mini that it has pins for the speaker or amplifier connection. Added to this is the small size of the module. The advantage of the YX5300 module, on the other hand, is the jack plug socket, to which headphones or (active) speakers can be connected directly. If you don’t like to tinker, the YX5300 may be better the better choice.

Leave a Reply

Your email address will not be published.