While browsing eBay looking for a module to play extended sound effects (MP3 and WAV files), I came across these modules that looked like they would fit my purpose. The module has been around for a few years and is based on the YX5300 IC. As it turns out they are easy to use and produce a good sound in a small package.
The downside is that there is not a huge lot of documentation for the board and the original is in Chinese. A copy of the official documentation I was able to find can be reached through this link.
While it is easy to make the board play a sound, there are no examples (that I could find) of ‘advanced’ control of the board in a system multitasking other control tasks. So I decided to write a control library that would provide me with the interface I thought was needed. The library (MD_YX5300) can be found in my code repository.
Hardware Specifications
The YX5300 supports 8kHz to 48kHz sampling frequency MP3 and WAV file formats. The audio files are stored on a micro SD card that plugs into a TF card socket on the back of the board.
The MCU controls the device playback by sending serial commands through a TTL level UART control interface (GND, VCC, TX, RX). Pins are connected GND to MCU ground, VCC to 5V power supply, YX5300 TX (transmit) to the designated RX (receive) pin for the library, YX5300 RX to TX. The MCU RX/TX can be hardware serial pins or a software controlled serial port.
Sound is output through a headphone jack to headphones or an external amplifier. The board has a playback indicator LED that blinks during playback and is steady otherwise.
The TF card socket on the PCB reverse side is for plugging in the micro SD card with MP3/WAV files. The micro SD card should be formatted as FAT16 or FAT32 and songs must be prefixed with a unique 3 digit index number (for example, 001xxx.mp3, 002xxx.mp3, 003xxx.mp3, etc, where xxx is an arbitrary optional name. Songs may also be grouped in folders named ’01’, ’02’, ’03’, etc. An example folder and file structure on the micro SD card might look like:
+-+- 01 | + 001-Happy_Dance.mp3 | + 002-O_Sole_Mio.mp3 | +- 02 | + 003-Humpty_Dumpty.mp3 | + 004-Incy_Wincy_Spider.mp3 | + 005-Grand_Duke.mp3 | +- 03 + 006-Fernando.mp3 + 007-Mamma_Mia.mp3
Songs are referenced by folder and by song ‘index’, although it seems that the numeric index is sometimes ignored and the songs played in the order they are stored in the SD card. The documentation is unclear on this and seems to imply both situations. So, even if you plan only one playlist, it is better to keep them in a ’01’ folder and save all the songs to the SD card at the same time.
Communicating with the Module
Communications is via asynchronous serial RS232 at 9600 bps, 8 data bits, No parity, 1 stop bit, no hardware flow control. Flow control is implemented using a request/response protocol with data packets in the following byte format:
where the fields have the following meaning:
- Start (0x7e) and End (0xef) mark the start and end of the serial packet. A receiver should synchronize on the start byte and read the packet to the end.
- Version is always 0xff. I assume this is to cater for future changes in the protocol and would allow comms software to adjust dynamically.
- Length is the number of bytes between the Start byte and Checksum. In this implementation it is always 6 bytes (the lighter colored boxes).
- Cmd (Command) in a request message is the control function code and in a response is error/status code.
- Fback (Feedback) is set to 1 to receive a request acknowledgement, or 0 for no acknowledgement.
- DataHi and DataLo are the high and low bytes of the command modifier or the status/error code. They are set to suit the Cmd byte (see the tables below).
- ChkHi and ChkLo are the checksum high and low bytes. The checksum is optional and can be omitted from requests messages, but a response from the device always includes the checksum field. The checksum is calculated as the two’s complement of the 16-bit sum of the bytes between Start and Checksum (ie, the same as those counted in Length).
The module can also initiate sending a message to the MCU when certain events occur (an ‘unsolicited’ message). These are received and processed without a matching prior request.
Device Commands
The interesting elements of the protocol message are the Cmd and Data fields.
The Cmd field allows us to control the module. The official English documentation provides a set of valid command codes and the Chinese documentation provides an additional set of codes. All the commands I have discovered are collated in the table below. Where the data field is required this is noted, otherwise it is set to zero and ignored.
NEXT_SONG | 0x01 | Play next song. |
PREV_SONG | 0x02 | Play previous song. |
PLAY_WITH_INDEX | 0x03 | Play song with index number. Data is the index of the file. |
VOLUME_UP | 0x04 | Volume increase by one. |
VOLUME_DOWN | 0x05 | Volume decrease by one. |
SET_VOLUME | 0x06 | Set the volume to level specified. Data is the volume level [0..30]. |
SET_EQUALIZER | 0x07 | Set the equalizer to specified level. Data is [0..5] – 0=Normal, 1=Pop, 2=Rock, 3=Jazz, 4=Classic or 5=Base. |
SNG_CYCL_PLAY | 0x08 | Loop play (repeat) specified track. Data is the track number. |
SEL_DEV | 0x09 | Select file storage device. The only valid choice for data is TF (0x02). |
SLEEP_MODE | 0x0a | Chip enters sleep mode. |
WAKE_UP | 0x0b | Chip wakes up from sleep mode. |
RESET | 0x0c | Chip reset. |
PLAY | 0x0d | Playback restart. |
PAUSE | 0x0e | Pause playback. |
PLAY_FOLDER_FILE | 0x0f | Play the file with the specified folder and index number |
STOP_PLAY | 0x16 | Stop playback. |
FOLDER_CYCLE | 0x17 | Loop playback within specified folder. Data is the folder index. |
SHUFFLE_PLAY | 0x18 | Playback shuffle mode. Data is 0 to enable, 1 to disable. |
SET_SNGL_CYCL | 0x19 | Set loop play (repeat) on/off for current file. Data is 0 to enable, 1 to disable. |
SET_DAC | 0x1a | DAC on/off control (mute sound). Data is 0 to enable DAC, 1 to disable DAC (mute). |
PLAY_W_VOL | 0x22 | Play track at the specified volume. Data hi byte is the track index, low byte is the volume level [0..30]. |
SHUFFLE_FOLDER | 0x28 | Playback shuffle mode for folder specified. Data high byte is the folder index. |
QUERY_STATUS | 0x42 | Query Device Status. |
QUERY_VOLUME | 0x43 | Query Volume level. |
QUERY_EQUALIZER | 0x44 | Query current equalizer (disabled in hardware). |
QUERY_TOT_FILES | 0x48 | Query total files in all folders. |
QUERY_PLAYING | 0x4c | Query which track playing |
QUERY_FLDR_FILES | 0x4e | Query total files in folder. Data is the folder index number. |
QUERY_TOT_FLDR | 0x4f | Query number of folders. |
The error/Status values returned from the device are also listed below. The Data field usually contains the status value or data requested.
TF_INSERT | 0x3a | TF Card was inserted (unsolicited message). |
TF_REMOVE | 0x3b | TF card was removed (unsolicited message). |
FILE_END | 0x3d | Track/file has ended (unsolicited message). Data is the index number of the file just completed. |
INIT | 0x3f | Initialization complete (unsolicited message). Data is the file store types available (0x02 for TF). |
ERR_FILE | 0x40 | Error file not found. Data is error code (no definition). |
ACK_OK | 0x41 | Message acknowledged ok |
STATUS | 0x42 | Current status. Data high byte is file store (2 for TF); low byte 0=stopped, 1=play, 2=paused. |
VOLUME | 0x43 | Current volume level. Data is volume level [0..30]. |
EQUALIZER | 0x44 | Equalizer status. Data is equalizer mode types 0=Normal, 1=Pop, 2=Rock, 3=Jazz, 4=Classic or 5=Base. |
TOT_FILES | 0x48 | TF Total file count |
PLAYING | 0x4c | Current file playing |
FLDR_FILES | 0x4e | Total number of files in the folder. Data is the number of files. |
TOT_FLDR | 0x4f | Total number of folders. Data is the number of folders. |
So why use a Library?
The MD_YX5300 library encapsulates each of the command messages as a class method. At its most basic, the library allows the processing of messages in the background while the application goes about its other business. This is done with a polling mechanism (check()) called once per loop() cycle.
The library can operate in synchronous or asynchronous mode. In synchronous mode, a call sending a request message will include waiting for the response before returning, allowing a simple flow in the main application provided it can tolerate the delays. This would satisfy most of the applications that I was able to find as examples.
Alternatively, asynchronous mode can be used, where the response can be processed by the application at a later stage. This is triggered by check() returning value signalling a message (response or unsolicited) is waiting.
Additionally, by defining a callback function, the application will be ‘called back’, including response status, when any message is been received. The callback approach particularly suits applications implemented as Finite State Machines.
Having this flexibility to tailor the programmer’s approach greatly simplifies handling the relatively slow serial comms link without losing efficiency in the rest of the application.
Updates:
52 replies on “YX5300 Serial MP3 Player (Catalex Module)”
Hi Marco,
Thanks for the post, really great. I have a question regards song start delay? I’m working on footswitch looper project. Currently using MH2024K-24SS module. But I really have issue when I click play button, the song starts with noticable dalay around one secund. Which is totally not acceptable for live music. For this reason I’m looking for an alternative. Would YX5300 behave better?
LikeLike
I am trying to find a serial mp3 module that is not limited to 255 songs.
this one https://www.banggood.com/Serial-Port-Control-Voice-Module-MP3-Player-Voice-Broadcast-Support-TF-Card-U-Disk-Insert-Function-p-1589685.html?cur_warehouse=CN&rmmds=search seems to do ” Supports playback of any segment of voice, audio data is sorted by folder, supports 100 folders, and each folder can be assigned 1000 songs;”
I am not sure it supports stereo analog output or if i need to use the DAC L+R for that.
The listing includes a rar file which has a pdf but it’s all in Chinese. Maybe it’s fairly similar and the API can be adapted.
LikeLike
Maybe it is or maybe it isn’t compatible. I cannot work it out as EVERYTHING, including the code, is in Chinese and that is a language I do not speak or read. Maybe you can do an internet search for this product name. Someone else may have used this before and will be able to help you.
LikeLike
Really neat board and library!
Thank you!
I have been trying to play mp3 with an arduino with an mp3 shield that uses SPI and the experience was not pleasant. Using a simple serial interface is much nicer.
The biggest limitation seems to be that the maximum number of tracks is 256
At https://majicdesigns.github.io/MD_YX5300/class_m_d___y_x5300.html#af9a464f2cdbd272be42aac185283a755 playTrack takes a uint8_t
My project is to use rfid cards to select which album to play and I would like to support more than 256 songs.
I tried using playFolderRepeat hoping that it would be limited to 256 folders but inside it would let me use files with numbers over 255 but I have not been able to get it to run (i can’t get playFolderRepeat to work so maybe it works but i have not found the right way to call it yet!)
LikeLike
The YM5300 serial protocol only allows one byte for song number and one byte for folder number, so that’s what we have to work with.
LikeLike
I think I have the files set correctly on card with folder 01 with files 001-songname.mp3 002-othername.mp3 then folder 02 with songs 003-name.mp3 etc.
Playspecific works well though I don’t get why the folder number is needed as the song name is unique. Playfolderrepeat does not work for me and gives err_file with codes 05 and 06.
Also is it possible to play and album tracks once. (not repeat nor shuffle) play all tracks once and stop?
Thanks
LikeLike
You can play a track and then once that is finished play the next but it is under program control. All the commands for this device that have public documentation are implemented, so if you cannot find a command for what you want to do, it does not exist. If you find a new command documented somewhere, let me know.
LikeLike
Sir Is it possible to play file with file name from Sd card root directory using this module?
I know how to play file with file name from folder. Thanks.
LikeLike
Hi Sir!
Sir how can i play a mp3 file from specific time, not from beginning ?
Thanks.
LikeLike
With this module that is not possible.
LikeLike
Is there any way to use famous tmrpcm library with this module, as there is a function that states:
audio.play(“filename”,30); // plays a file starting at 30 seconds into the track
LikeLike
The answer does not change no matter how you ask the question. No, you cannot do this because the hardware does not support it. Maybe you should find hardware that supports what you want to do instead of focusing on this module.
LikeLike
Hi, Thankyou for the library. I week ago I had the mp3 player working fine. Now none of my code works. To test I started running your test code. Every time I run the mp3_test.ino code after every command the serial prints “command ?”. What could be wrong.
LikeLike
Check the line ending on the serial monitor.
LikeLike
Hi it just prints the timeout error after it prints “command ?”.
I was also wondering if its possible to set variables as soon as the player finishes playing a track.
LikeLike
You probably need to explain your setup and what you are trying to do. This is not the right format for this conversation. Please raise an post on the Arduino forum (https://forum.arduino.cc/index.php?board=8.0), That is better for a discussion and others will contribute also.
LikeLike
Great library. Thank you! I really liked the sample files.
I don’t know if you’re ever thinking about expanding the functionality, but a fade would be nice.
LikeLike
Thank you for providing this library – had no problems incorporating it into a project I am working to interface to a jukebox wallbox selector. I bought my first Mega 2560 this week as I’ve always just used the Uno in the past, and see there are 4 hardware serial ports. If I wanted to use the Mega board for my application, is there an advantage in not using the SoftwareSerial library and use on of the additional built in serial ports as far as code size/speed? Thank you.
LikeLike
Definitely use the hardware ports instead of SoftwareSerial. The speed won’t change as it is relatively slow to the device at 9600 bps, but there is one less library to take up code space and the reliability of the hardware will be will be higher.
LikeLike
Hi marco_c, I posted a reply asking how to get the hardware serial ports to work because by changing the line:
#define USE_SOFTWARESERIAL 1
to:
#define USE_SOFTWARESERIAL 0
did not work.
I then started to examine the library and think there is an error in the lines just below the define:
#define _S Serial2 ///< Native serial port – can be changed to suit
should be:
#define _Serial Serial2 ///< Native serial port – can be changed to suit
Now it works.
Thanks for the library, I am still trying to understand how it works with my limited programming experience.
LikeLike
Fixed and uploaded library update.
LikeLike
[…] the case of my mod, I will be replacing the electronics with an Arduino Nano, a Catalex MP3 board, a lipstick style phone power bank, and sundry audio hardware. Because I don’t want to have […]
LikeLike
As a beginner, even after two nights I find it impossible to convert the example with the serial input into something I can use in my project to build a kids mp3 player.
I try to query the number of tracks, but a code like
tracksinfolder = mp3.queryFolderFiles(2);
does not work. There is an “mp3.check();” in the loop but I have no idea how to get the code that appears on serial.
What would be the easiest way to query the number of files in a folder?
Problem two (related) is, how can I quickly check if a file has stopped playing already, or what the status is?
The serial monitor example works great, but it is highly frustrating that I can’t translate it into a code that runs without any serial monitor input. Can you provide an example for a simple status query or how to detect if a file has stopped playing?
LikeLike
The serial monitor ‘example’ is the test code the library and gives a clue as to how each functions should work. It is not meant to be something that people start from as it is essentially code fragments in a case statement.
There is extensive documentation about how the library works in the docs folder – have you read this? I expect that you are being confused by the asynchronous nature of the response to your request if you don’t get how mp3.check() works – the result comes in the callback function. This is explained in the library reference.
You are given a message when the song stops playing – again this should come through the callback function.
LikeLike
Can it shows the name of the song? Or can we get the information and put it in to a variable or something to write it out to the serial?
regards,
Daniel
LikeLike
The module can tell you the number of the song playing but it won’t give you the ‘name’ of the song.
LikeLike
I’am using an BY-8001 module to play mp3- and wav-files.
mp3-files are played correctly with the BY-8001, but wav-files are not.
Question:
Does a YX5300 play wav-files?
LikeLike
Documentation says it does but I have not tried it.
LikeLike
I think that I have everything wired in and setup properly (checked 4 times)
When I run the sample application I get “Cback status: STS_TIMEOUT, 0x0” for every call.
Any ideas of what might be wrong?
LikeLike
Just try swapping Rx and Tx and see if that makes a difference.
LikeLike
I ran into the same issue when I went from the UNO to a Mega2560 board using softwareserial. To make that work, I changed the Rx pin to 10 on the Mega2560 – not all pins are supported for Rx on the Mega2560. Even better, if you have the Mega2560, use one of the additional native ports on the board.
LikeLike
Does it provide a stereo sound ?
LikeLike
The connector is stereo, but I honestly can’t say if the output is stereo.
LikeLike
Will IT work with ESP 32? Do i need 3.3v to 5v converter?
LikeLike
It should work with the ESP32. The easiest is to try and compile without downloading and see if there are any errors in the compile.
I would try without the converter and see if it works. SD cards are generally 3.3V. As you are using the lower voltage you should be damaging anything. At worst it will not work.
LikeLike
Can it play 16 bit wav files
LikeLike
Manual says “It can support 8k Hz ~ 48k Hz sampling frequency MP3 and WAV file formats.” No idea if that means 16 bit WAV files. Maybe Google it?
LikeLike
So I have managed to get this to work, but I have unearthed a bug.
Getting a STS_FILE_END status code to trigger playing the next file isn’t always reliable. Sometimes it will trigger it twice in a row, other times only once. Sometimes the code just throws a response “7E FE 40 EF -> 2 Ver error” response.
I have no way of knowing if it’s a bug in the library or in the player. The serial link is soldered directly onto a nano with the header pins, with a decoupling cap on the Vin, so there shouldn’t be a noise issue between player and Arduino.
LikeLike
You can set the debug flag in the library and it will print to Serial the flow of message between the devices. If it receives the message twice, it is not in the library.
#define LIBDEBUG 1 ///< Set to 1 to enable Debug statement in the library
Library issues should be raised in the github repository under the 'issues' tab so they can be tracked properly.
LikeLike
I found the same thing happening with my MP3 board so what I did is compared the millis() value on the last STS_FILE_END code received and disregard it if it is less than 1000mS apart. Of course if you have MP3 files that are shorter than 1 second in length (sound effects for example), you may need to use a different value than 1000mS. My application plays MP3 files based on selections made on a jukebox wallbox so it’s more than adequate.
LikeLike
Can you give some examples for how to get the number of files and folders and store them in a variable? I’ve made an mp3 player using your library but can’t seem to figure out how to get the information from a query to use in code. I’m using buttons to send the appropriate command. The shuffle function doesn’t work and I would like to make my own thanks.
LikeLike
Don’t the QX and QY from the library test example work?
LikeLike
Yes, but I’m not sending commands in a terminal. I hooked up buttons to an arduino. And call mp3.playtrack(i), I would like to randomize “i” but need to know how to get and store mp3.querytotalfiles into a variable. Then I could do something like
Mp3.playtrack(Random(0,totalfiles));
Thanks
LikeLike
You are missing the point of the test example. It is to test the library AND provide examples of how it is used. If the test gives you back the wrong numbers for folders (ie the library does not work) then I need to find out what is wrong. If the test gives back the right numbers then you need to look at the example code, and/or read the library documentation, to work out how you use it in your code.
LikeLike
It does print the correct numbers in the terminal when I send the query. I’m very new at programming and don’t understand how to get the numbers to use. I can play,pause and skip tracks just fine I just need help understanding how to get the data returned by a query.
And thank you for the great library!
LikeLike
Ok, then you need to read the sections on message flow management, the role of the cbData structure and the entries for methods queryFolderCount() and queryFilesCount() in the documentation.
LikeLike
I am totally here with you on this! You need to be able to load the number of files in a variable to call random() with the proper range.
I get where the dev is coming from, but trying to get a real world example of that nested serial interface is frustrating for someone who doesn’t code every day! A good ‘random player’ as an example would be marvelous for the example(s) directory!
So far all I have managed to get from this is an MP3 player that requires another microcontroller or computer to send commands and a very large headache!
LikeLike
Hi Marco,
Many thanks for the comprehensive guide, you have included a few more commands than I found in the manual and your explanation of the status messages will be very helpful. I haven’t tested your library yet but will do so shortly – I have automated a pinball backboard with motion sensor (IR beam), lighting, sound and a servo to open the doors on a castle feature in the backboard.
I am using the YX5300 to play the mp3s which is mostly working well however I am having issues when copying several songs to the card. When I copy the files to the SD card (2Gb, FAT formatted) I receive the warning “Are you sure you want to copy the files without its properties?”, presumably because I am copying from NTFS drive to FAT (16). When I insert the SD card into the YX5300, the songs which showed the warning on copying cannot be played. When I remove the card and insert into my laptop, the files which showed warnings have either disappeared or have been corrupted so they cannot be played in Windows (VLC, etc.).
Have you experienced similar issues? Do I need to format the songs in a specific way?
LikeLike
I used to get this sometimes on other applications. If you haven’t already done so, try formatting the SD card with this utility https://www.sdcard.org/downloads/formatter_4/ instead of Windows or ‘operating system’ level format.
LikeLike
Many thanks for writing this library.
Unfortunately I am just a beginner to Arduino and can’t seem to get it to work. I have added the library to the arduino and loaded the test sketch but when I upload it to the arduino and open up the serial monitor I just get boxes and random characters. Entering in commands gets no response from the speakers.
Using another users original test sketch will allow me to play a mp3 track. I have also tried other sketches and they work .
such as
http://www.amazingtips247.co.uk/2015/11/how-to-play-sound-tracks-with-catalex.html
I am looking forward to getting your library and test sketch working as it looks very thorough and robust.
I just need to spend time understanding the code.
Thanks again.
regards,
Martin
LikeLike
Sounds like you need to set the serial monitor to the right bits per second to match the one in the Serial.begin() call in the code.
LikeLike
Thank you. 🙂
LikeLike