Last Updated: 21/12/2022

DFmini player & MP3-T-16P v3.0

Components >> DFmini player & MP3-T-16P v3.0

DFmini player & MP3-TF-16P v3.0 Player


This is a tutorial to deal with the differences between a DFmini player and a MP3-TF-16P v3.0 mpy player.

This tutorial came about after I needed another DFplayer on a model railway project, ordered one, and it didn't work. Ordered a second...and it didn't work. ordered a 3rd and yet again failure. I would plug in the replacement, power light would flash and then nothing.

All 3 had come from different suppliers, 2 in UK, the other from AliExpress....what is going on?

Well it seems that not all DFmini players are the same.

DFPlayer Mini HW-247A v MP3-TF-16P v3.0

On the left is my existing, working DFmini player, on the right is a new one...sold as a DFmini player on numerous sites. They look identical apart from the writing on them.
Left version says: DFPlayer Mini HW-247A
Right side is: MP3-TF-16P v3.0

So the look the same until you turn them over.

DFPlayer Mini HW-247A v MP3-TF-16P v3.0

The one on the left is the original DFplayer, the one on the right is the MP3-TF-16P. At a quick glance they look the same but then notice the top chip is a different form factor with a different number of legs, also a different number of resistors. So these boards may look alike but are not the same.

Model Chip numbering  
DFPlayer Mini HW-247A MH2024K-24SS 220920  
MP3-TF-16P v3.0 GT3200B 210824679F  

Looking at the specs both boards have the same pin out so a straight swap would be expected.

Looking at the data sheets they also seem to have the same instruction sets.

DFPlayer Mini HW-247A & MP3-TF-16P v3.0 pinout

I managed to get some sound out of the MP3-TF-16P v3.0 by connecting VCC to 5V, Both GND's to GND and touching IO_1 to GND. Once I knew the unit would play I then randomly touched ADKey_2 and ADKey_1 and IO_2 as well as IO_1 to GND and track seemed to play and stuff happened.
Although this was great for those using push buttons, I wanted control via RX/TX as mine is driven by ESP32's and Arduinos.

The manual seems to be the same for both units so this is a link to one of them. MANUAL

Fortunately I had written my own code to control my DFplayer instead of using a library so the script is very simple.

For intial testing I used an Arduino Mega 2560 using Serial3, this helped to make sure software serial was not an issue.

At the end of my testsing I had both types of modules working with the same code and circuit...apart from 1 genuine DFPlayer that was actually damaged as I suspected!!

Problem Found?

After writing the scripts below and getting both boards working I still found that I could not swap between boards with a sketch for my model railway.

It's possible that the sketch shows a slight difference between the performance of the boards.

original DFMini player code.


 
  
  changeVolume(masterVolume * 3);//set volume
  playTrack(22);//compressor
  
  
This code would not work with the MP3-TF-16P v3.0, instead I had to put in a 1 second delay. I need to do some further tests to see if it's possible to put in a smaller delay(). I finally found something in the manual in section 3.3.2 that talks about having a delay of 100 milliseconds so this may be closer to what is required.
 
  
  changeVolume(masterVolume * 3);//set volume
  delay(1000)
  playTrack(22);//compressor
  
 

   

It would seem that the DFPlayer can handle commands at a faster rate than the MP3-TF-16P v3.0. This could mean that the DFPlayer has a slightly bigger buffer but if you are having problems sending multiple commands try a small delay() between them.

Circuit

In this circuit I have connected both GNDs and have a 1K resistor on the TX and RX lines. I have had both boards working without the 1K resistors but if you get stuck give it a try. It works with both types of DFPlayer board and with UNO/Mega2560 and ESP32.

Connect the TX/RX pins to your Arduino/ESP32 board.

DFMini circuit

Example 1: Arduino Mega 2560 TestScript1.ino


Click to Download code: TestScript1.ino

Written to run on Arduino Mega2560 Using Serial3

This is some very quick and dirty code and contains delay() so is best avoided in any project but will test your board connections and shows the simplicity of sending commands such as "Play Next Track", "Play Selected Track" and "Set Volume".

 
/* DFPlayerMegaV2
   MP3-TF-16P
  21/12/2022
  running on Mega2560 Serial3
  simple sketch just playing through the card, 2 secs of each track. This checked that ciruit was working

*/

//this function sends the actual command
//It receives the command byte and ParData is optional info such as track number or volume depending on the command
void sendDFCommand(byte Command, int ParData) {
  byte commandData[10]; //This holds all the command data to be sent
  byte q;
  int checkSum;
  Serial.print("Com: ");
  Serial.print(Command, HEX);
  //Each command value is being sent in Hexadecimal
  commandData[0] = 0x7E;//Start of new command
  commandData[1] = 0xFF;//Version information
  commandData[2] = 0x06;//Data length (not including parity) or the start and version
  commandData[3] = Command;//The command that was sent through
  commandData[4] = 0x01;//1 = feedback
  commandData[5] = highByte(ParData);//High byte of the data sent over
  commandData[6] = lowByte(ParData);//low byte of the data sent over
  checkSum = -(commandData[1] + commandData[2] + commandData[3] + commandData[4] + commandData[5] + commandData[6]);
  commandData[7] = highByte(checkSum);//High byte of the checkSum
  commandData[8] = lowByte(checkSum);//low byte of the checkSum
  commandData[9] = 0xEF;//End bit
  for (q = 0; q < 10; q++) {
   Serial3.write(commandData[q]);
  }
  Serial.println("Command Sent: ");
  for (q = 0; q < 10; q++) {
    Serial.println(commandData[q],HEX);
    
  }
  Serial.println("End Command: ");
  delay(100);
}

//play a specific track number
void playTrack(int tracknum){
  Serial.print("Track selected: ");
  Serial.println(tracknum);
  sendDFCommand(0x03, tracknum);
}

//plays the next track
void playNext(){
  Serial.println("Play Next");
  sendDFCommand(0x01, 0);
}

//volume increase by 1
void volumeUp() {
  Serial.println("Vol UP");
  sendDFCommand(0x04, 0);
}
//volume decrease by 1
void volumeDown() {
  Serial.println("Vol Down");
  sendDFCommand(0x05, 0);
}

//set volume to specific value
void changeVolume(int thevolume) {
  sendDFCommand(0x06, thevolume);
}


void setup() {
  Serial.begin(9600);
  Serial.println("DFPlayerMegaV2");
  Serial3.begin (9600);//start the softwareSerial to DF player
  delay(3500);//let everything initialise
  changeVolume(20);//set volume to 20
  
}

int q = 5;

void loop() {
  //Uncomment just to play through tracks one after another.
  //playNext();
  //delay(2000);

  //Uncomment to play through a set of tracks
  for(q=5;q<15;q++){
    playTrack(q);
    delay(2000);
  }
}

Example 2: Arduino Mega 2560 TestScript2.ino


Click to Download code: TestScript2.ino

Written to run on Arduino Mega 2560 using Serial3
This sketch has a lot more interaction between the player and the Arduino.
It is reading the returned status and waiting for a track to finish before starting the next track.
I have left a lot of extra commenting in to try and help show what is happening and when.
Run the project with the serial monitor running to see the information.

In the setup() there are a couple of lines

changeVolume(20);//set volume to 20....30 is very loud even on small speaker.
delay(100);
playTrack(4);

The delay may need to be slightly longer if you are using the MP3-T-16P v3.0 as I found sending multiple command quickly could cause issues.

 
/* Test script 2...trying to get feedback from module.
   MP3-TF-16P
  21/12/2022
  running on Mega2560 Serial3
  simple sketch just playing through the card, 2 secs of each track. This checked that ciruit was working

*/

//this function sends the actual command
//It receives the command byte and ParData is optional info such as track number or volume depending on the command
void sendDFCommand(byte Command, int ParData) {
  byte commandData[10]; //This holds all the command data to be sent
  byte q;
  int checkSum;
  Serial.print("Com: ");
  Serial.print(Command, HEX);
  //Each command value is being sent in Hexadecimal
  commandData[0] = 0x7E;//Start of new command
  commandData[1] = 0xFF;//Version information
  commandData[2] = 0x06;//Data length (not including parity) or the start and version
  commandData[3] = Command;//The command that was sent through
  commandData[4] = 0x01;//1 = feedback
  commandData[5] = highByte(ParData);//High byte of the data sent over
  commandData[6] = lowByte(ParData);//low byte of the data sent over
  checkSum = -(commandData[1] + commandData[2] + commandData[3] + commandData[4] + commandData[5] + commandData[6]);
  commandData[7] = highByte(checkSum);//High byte of the checkSum
  commandData[8] = lowByte(checkSum);//low byte of the checkSum
  commandData[9] = 0xEF;//End bit
  for (q = 0; q < 10; q++) {
   Serial3.write(commandData[q]);
  }
  Serial.println("Command Sent: ");
  for (q = 0; q < 10; q++) {
    Serial.println(commandData[q],HEX);
    
  }
  Serial.println("End Command: ");
  delay(100);
}

//play a specific track number
void playTrack(int tracknum){
  Serial.print("Track selected: ");
  Serial.println(tracknum);
  sendDFCommand(0x03, tracknum);
}

//plays the next track
void playNext(){
  Serial.println("Play Next");
  sendDFCommand(0x01, 0);
}

//volume increase by 1
void volumeUp() {
  Serial.println("Vol UP");
  sendDFCommand(0x04, 0);
}
//volume decrease by 1
void volumeDown() {
  Serial.println("Vol Down");
  sendDFCommand(0x05, 0);
}

//set volume to specific value
void changeVolume(int thevolume) {
  sendDFCommand(0x06, thevolume);
}


void setup() {
  Serial.begin(9600);
  Serial.println("DFPlayer Test Script 2");
  Serial3.begin (9600);//start the softwareSerial to DF player
  delay(3500);//let everything initialise
  changeVolume(20);//set volume to 20....30 is very loud even on small speaker.
  delay(100);
  playTrack(4);
}

int q = 5;
byte returnCodes[10];
byte returnByteCounter;

void loop() {
  byte readByte;
while (Serial3.available()) {
  

    readByte = Serial3.read();
    Serial.print(readByte,HEX);
    Serial.print(" Count: ");
    Serial.println(returnByteCounter);
    
    if(returnByteCounter == 0){
      if(readByte == 0x7E){
        returnCodes[returnByteCounter] = readByte;
        returnByteCounter++;
      }
    }else{
        returnCodes[returnByteCounter] = readByte;
       returnByteCounter++; 
    }
    
    if(returnByteCounter > 9){
      Serial.println("Code String");
      for(int w = 0;w<10;w++){
        Serial.print(returnCodes[w],HEX);  
        Serial.print(" ");  
      }
      Serial.println(" ");
      if(returnCodes[3] == 0x3D){//track finished
         Serial.println("Play Next Track");
       playNext();//play next track 
      }
      returnByteCounter = 0;
    }

 

   
  }
 
  
}


Example 3: Arduino UNO Software Serial UnoSoftSerialTestScript2.ino


Click to Download code: UnoSoftSerialTestScript2.ino

Written to run on ArduinoUNO using Software Serial

 
/* Test script 2...trying to get feedback from module.
   MP3-TF-16P
  21/12/2022
  rcoded for software serial on UNO
  
*/
#include 
 SoftwareSerial mySerial(2, 3);//RX/TX

//this function sends the actual command
//It receives the command byte and ParData is optional info such as track number or volume depending on the command
void sendDFCommand(byte Command, int ParData) {
  byte commandData[10]; //This holds all the command data to be sent
  byte q;
  int checkSum;
  Serial.print("Com: ");
  Serial.print(Command, HEX);
  //Each command value is being sent in Hexadecimal
  commandData[0] = 0x7E;//Start of new command
  commandData[1] = 0xFF;//Version information
  commandData[2] = 0x06;//Data length (not including parity) or the start and version
  commandData[3] = Command;//The command that was sent through
  commandData[4] = 0x01;//1 = feedback
  commandData[5] = highByte(ParData);//High byte of the data sent over
  commandData[6] = lowByte(ParData);//low byte of the data sent over
  checkSum = -(commandData[1] + commandData[2] + commandData[3] + commandData[4] + commandData[5] + commandData[6]);
  commandData[7] = highByte(checkSum);//High byte of the checkSum
  commandData[8] = lowByte(checkSum);//low byte of the checkSum
  commandData[9] = 0xEF;//End bit
  for (q = 0; q < 10; q++) {
   mySerial.write(commandData[q]);
  }
  Serial.println("Command Sent: ");
  for (q = 0; q < 10; q++) {
    Serial.println(commandData[q],HEX);
    
  }
  Serial.println("End Command: ");
  delay(100);
}

//play a specific track number
void playTrack(int tracknum){
  Serial.print("Track selected: ");
  Serial.println(tracknum);
  sendDFCommand(0x03, tracknum);
}

//plays the next track
void playNext(){
  Serial.println("Play Next");
  sendDFCommand(0x01, 0);
}

//volume increase by 1
void volumeUp() {
  Serial.println("Vol UP");
  sendDFCommand(0x04, 0);
}
//volume decrease by 1
void volumeDown() {
  Serial.println("Vol Down");
  sendDFCommand(0x05, 0);
}

//set volume to specific value
void changeVolume(int thevolume) {
  sendDFCommand(0x06, thevolume);
}


void setup() {
  Serial.begin(9600);
  Serial.println("DFPlayer Test Script 2");

  mySerial.begin(9600);
  mySerial.begin (9600);//start the softwareSerial to DF player
  
  delay(3500);//let everything initialise
  changeVolume(20);//set volume to 20....30 is very loud even on small speaker.
  delay(100);
  playTrack(4);
}

int q = 5;
byte returnCodes[10];
byte returnByteCounter;

void loop() {
  byte readByte;
while (mySerial.available()) {
  

    readByte = mySerial.read();
    Serial.print(readByte,HEX);
    Serial.print(" Count: ");
    Serial.println(returnByteCounter);
    
    if(returnByteCounter == 0){
      if(readByte == 0x7E){
        returnCodes[returnByteCounter] = readByte;
        returnByteCounter++;
      }
    }else{
        returnCodes[returnByteCounter] = readByte;
       returnByteCounter++; 
    }
    
    if(returnByteCounter > 9){
      Serial.println("Code String");
      for(int w = 0;w<10;w++){
        Serial.print(returnCodes[w],HEX);  
        Serial.print(" ");  
      }
      Serial.println(" ");
      if(returnCodes[3] == 0x3D){//track finished
         Serial.println("Play Next Track");
       playNext();//play next track 
      }
      returnByteCounter = 0;
    }



   
  }
 
  
}


Example 4: ESP32 using Serial2 ESP32lTestScript2.ino


Click to Download code: ESP32lTestScript2.ino

Written to run on ESP32 using Serial2

 
/* Test script 2...trying to get feedback from module.
   MP3-TF-16P
  21/12/2022
  Recoded for ESP32
  
*/
#define RXD2 16
#define TXD2 17

//this function sends the actual command
//It receives the command byte and ParData is optional info such as track number or volume depending on the command
void sendDFCommand(byte Command, int ParData) {
  byte commandData[10]; //This holds all the command data to be sent
  byte q;
  int checkSum;
  Serial.print("Com: ");
  Serial.print(Command, HEX);
  //Each command value is being sent in Hexadecimal
  commandData[0] = 0x7E;//Start of new command
  commandData[1] = 0xFF;//Version information
  commandData[2] = 0x06;//Data length (not including parity) or the start and version
  commandData[3] = Command;//The command that was sent through
  commandData[4] = 0x01;//1 = feedback
  commandData[5] = highByte(ParData);//High byte of the data sent over
  commandData[6] = lowByte(ParData);//low byte of the data sent over
  checkSum = -(commandData[1] + commandData[2] + commandData[3] + commandData[4] + commandData[5] + commandData[6]);
  commandData[7] = highByte(checkSum);//High byte of the checkSum
  commandData[8] = lowByte(checkSum);//low byte of the checkSum
  commandData[9] = 0xEF;//End bit
  for (q = 0; q < 10; q++) {
   Serial2.write(commandData[q]);
  }
  Serial.println("Command Sent: ");
  for (q = 0; q < 10; q++) {
    Serial.println(commandData[q],HEX);
    
  }
  Serial.println("End Command: ");
  delay(100);
}

//play a specific track number
void playTrack(int tracknum){
  Serial.print("Track selected: ");
  Serial.println(tracknum);
  sendDFCommand(0x03, tracknum);
}

//plays the next track
void playNext(){
  Serial.println("Play Next");
  sendDFCommand(0x01, 0);
}

//volume increase by 1
void volumeUp() {
  Serial.println("Vol UP");
  sendDFCommand(0x04, 0);
}
//volume decrease by 1
void volumeDown() {
  Serial.println("Vol Down");
  sendDFCommand(0x05, 0);
}

//set volume to specific value
void changeVolume(int thevolume) {
  sendDFCommand(0x06, thevolume);
}


void setup() {
  Serial.begin(9600);
  Serial.println("DFPlayer Test Script 2");

  Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2);
  Serial.println("Serial2. started...");

  
  
  delay(3500);//let everything initialise
  changeVolume(20);//set volume to 20....30 is very loud even on small speaker.
  delay(100);
  playTrack(4);
}

int q = 5;
byte returnCodes[10];
byte returnByteCounter;

void loop() {
  byte readByte;
while (Serial2.available()) {
  

    readByte = Serial2.read();
    Serial.print(readByte,HEX);
    Serial.print(" Count: ");
    Serial.println(returnByteCounter);
    
    if(returnByteCounter == 0){
      if(readByte == 0x7E){
        returnCodes[returnByteCounter] = readByte;
        returnByteCounter++;
      }
    }else{
        returnCodes[returnByteCounter] = readByte;
       returnByteCounter++; 
    }
    
    if(returnByteCounter > 9){
      Serial.println("Code String");
      for(int w = 0;w<10;w++){
        Serial.print(returnCodes[w],HEX);  
        Serial.print(" ");  
      }
      Serial.println(" ");
      if(returnCodes[3] == 0x3D){//track finished
         Serial.println("Play Next Track");
       playNext();//play next track 
      }
      returnByteCounter = 0;
    }


   
  }
 
  
}


Additional Resource Links

Lesson 2: "Hello World" Basics of printing to Serial Window 17/07/2021

Comments


This site has been designed to be child friendly, this means that comments cannot be added to videos or directly to the site.
To add a comment or ask a question please email the address in this image: and use DFmini player & MP3-T-16P v3.0 as a reference.