Driver library for the DFPlayer Mini (MP3-TF-16P) MP3 audio player module. Depending on the module or version the main decoder IC can vary. Mine has the MH-ET LIVE MH3028M-24SS IC that is also compatible with ICs such as YX5200-24SS, YX5300, YX5300, YX6300.
The DFPlayer Mini includes an integrated audio decoder chip, a mono 8002A audio amplifier and an Micro SD card socket. The IC can decode WAV and MP3 formats and is used in serial-controlled audio players. It can be used as a standalone module together with an AD (Analog-to-Digital) keypad or driven by a microcontroller using serial commands. Even though the audio amplifier is mono, the module also has two pins that break-out the internal stereo DAC that can be connected to an external stereo audio amplifier or headphones.
The original board design was created by DFRobot, a well-known robotics and open-source hardware vendor based in Shanghai.
Contents
- Library characteristics
- DFPlayer Mini characteristics
- DFPlayer Mini pinout
- Wiring
- Controlling the DFPlayer module using I/O mode
- Controlling the DFPlayer module using AD mode
- External headphone circuit
- Serial Interface
- Serial Control Protocol
- Library
- Class constructor
- Public methods
- Initialization
- Read BUSY pin
- Play track by index
- Play next
- Play previous
- Play folder track
- Play folder track large
- Play MP3 folder
- Play advert
- Stop advert
- Stop play
- Play
- Pause
- Set volume
- Increase volume
- Decrease volume
- Set EQ
- Set playback source
- Sleep mode
- Exit sleep mode
- Reset
- Check event
- Query status
- Query software version
- Query EQ
- Query volume
- Query playback mode
- Query total SD files
- Query current SD track
- Code example
- Links
Library characteristics
- Language: C++
- Supported devices: AVR. Developed on ATmega328PB. Supports Class 1 AVR (UDPI) devices.
- Dependencies: UART library for serial interface.
DFPlayer Mini characteristics
- Sampling rates (kHz): 8/11.025/12/16/22.05/24/32/44.1/48.
- Supported Formats: MP3, WAV, WMA.
- DAC output: 24-bit, support for dynamic range 90dB, SNR support 85dB.
- File system support: Micro SD (up to 2GB) and Micro SDHC (up to 32GB) formatted in FAT16 or FAT32, support 32G USB disk, 64M bytes NORFLASH.
- Control interfaces: IO, Serial Port (RX/TX), AD Key.
- Special functions: the audio can be suspended by an advert then automatically resumed when advert is over.
- Volume and EQ: 30 level adjustable volume, 6-level EQ presets (Normal, Pop, Rock, Jazz, Classic, Base).
- Power supply: DC 3.2~5V.
- Current: Sleep mode < 10mA, Playback 500mA max .
- Output Power: 3W (5V Power Supply).
- Size: 20mm x 20mm.
DFPlayer Mini pinout
|
| Source: https://wiki.dfrobot.com/dfr0299 |
Tip: the module can be used on a breadboard placed in the middle but pins one one side must be pushed towards the center with some pliers.
VCC: input voltage. DC 3.2-5V. Recommended 5V.
RX: UART serial input. Add a 1kΩ resistor between MCU TX and DFPlayer RX for signal conditioning. Internally DFPlayer Mini operates at ~3.3V and when MCU uses 5V the resistor helps with level compatibility and reduces noise.
TX: UART serial output. Connects to MCU RX.
DAC_R and DAC_L: DAC audio output right and left channels are broken out directly to the module header pins for driving high-impedance loads (e.g., headphones or external audio amplifiers like an AUX line-in). Internally on the PCB, DAC_L and DAC_R are also mixed down to a mono signal and fed into the input of the 8002A (a Bridge-Tied Load / BTL mono power amplifier). The differential outputs of the 8002A go directly to SPK_1 and SPK_2.
SPK_1 (+) and SPK_2 (-): Outputs from the onboard 8002A mono audio amplifier. Direct connection for a passive speaker (≤ 3W output). You can connect either an 8 Ω or 4 Ω speaker. An 8 Ω speaker (3W) is usually the safest and most efficient choice. With a 4 Ω speaker it will deliver closer to the maximum 3W output, but it draws significantly more peak current (up to ~500mA–800mA). If you use a 4 Ω speaker, ensure your power supply can handle the higher current surges without causing the AVR microcontroller or the DFPlayer to brown out.
Warning: Because the 8002A uses a Bridge-Tied Load (BTL) output, neither SPK_1 nor SPK_2 is connected to Ground (GND). Never connect SPK_1 or SPK_2 to an external powered amplifier or to system ground, or you will short out the 8002A output drivers. Use DAC_L, DAC_R, and GND for external amplification.
GND: power ground.
BUSY: playing status. Low means playing, High means idle. Optionally, it can be connected to an MCU digital pin.
USB- and USB+: The USB- (D-) and USB+ (D+) pins serve two distinct functions depending on how they are configured:
USB Host (Reading USB Flash Drives): If you connect a standard USB Type-A female port (with 5V power) to these pins, the decoder chip acts as a USB Host. It can read and play MP3 audio files directly from an external USB flash drive instead of the MicroSD card.
USB Device (PC Card Reader / Sound Card Mode): If you connect these pins directly to a PC's USB port, the module presents itself to the computer as a USB Mass Storage Device (allowing you to write files directly to the MicroSD card over USB without removing it) or as an External USB Audio Device.
ADKEY_1 and ADKEY_2: DFPlayer Mini can operate in a standalone
mode using resistive ladder button matrices (AD Key Mode) without needing UART
commands. The module has two analog key inputs: ADKEY_1 and ADKEY_2.
Each
ADKEY pin supports a series of push-buttons connected through different
resistor values to Ground. When a button is pressed, the voltage divider tells
the module which "Segment" group action to execute:
Segment 1 (ADKEY_1 Group): controls actions and playback triggers for the first set of 10 pre-defined
tracks/folders (e.g., direct-trigger tracks 1 through 10 depending on which
resistor/button is pressed).
Segment 5 (ADKEY_2 Group): controls
actions for the fifth set/group of tracks (e.g., direct-trigger tracks 11
through 20 or higher folder groups depending on the module firmware
matrix).
When controlled via software over UART these can be left
floating/unconnected.
IO_1: trigger port 1. Short press to play previous. Long press to decrease the volume.
IO_2: trigger port 2. Short press to play next. Long press to increase the volume.
Wiring
Controlling the DFPlayer module using I/O mode
|
| Source: https://wiki.dfrobot.com/dfr0299 |
Short time press means prev/next, and long time press means vol- , vol+.
Controlling the DFPlayer module using AD mode
|
| Source: https://wiki.dfrobot.com/dfr0299 |
They also sell the AD keypad as a module here.
External headphone circuit
|
| Source: YX5200-24SS datasheet |
Serial Interface
Interface with the audio decoder IC is done using TX/RX UART pins. UART must be configured as follows:
Asynchronous mode, 9600 baud rate, data bits: 1, checkout: none, flow control: none.
Serial Control Protocol
Every frame sent to or received from the DFPlayer Mini consists of 10 bytes:
| Byte | Field | Description / Value |
|---|---|---|
| 0 | Start Byte | 0x7E |
| 1 | Version | Always 0xFF. Not really used. |
| 2 | Length |
0x06. Number of payload bytes that follow, excluding
checksum & end byte.
|
| 3 | Command |
CMD byte (e.g., 0x3F, 0x42,
0x03)
|
| 4 | ACK |
0x01 (Request reply frame) or 0x00 (No reply
required)
|
| 5 | Param High |
High byte of 16-bit argument ((param >> 8) & 0xFF)
|
| 6 | Param Low |
Low byte of 16-bit argument (param & 0xFF)
|
| 7 | Checksum High | (checksum >> 8) & 0xFF |
| 8 | Checksum Low | checksum & 0xFF |
| 9 | End Byte | 0xEF |
Checksum Calculation Formula
The 16-bit checksum is calculated by taking the 1's complement of the sum of bytes 1 through 6:
Checksum = 0 - Version + Length + CMD + ACK + Param_H + Param_L
Serial control commands
| CMD | Description | Parameter |
|---|---|---|
| 0x01 | Play next | |
| 0x02 | Play previous | |
| 0x03 | Play track by FAT index. Commands 0x01, 0x02, 0x03 uses FAT indexing which means it doesn't read the file number but it uses the order in FAT table that depends on which order the files were copied. | |
| 0x04 | Increase volume by 1 | |
| 0x05 | Decrease volume by 1 | |
| 0x06 | Set volume | 0-30 |
| 0x07 | Set EQ | 0-5 (Normal, Pop, Rock, Jazz, Classic, Bass) |
| 0x08 |
Playback mode. Configures global loop mode policies. E.g.,
automatically repeat the whole SD card, repeat a single folder, or
play randomly). Note: This command and other similar is not implemented by the library because on some modules like the one I have, the function is confusing or not supported. For example Shuffle/Random command will also play files in ADVERT folder. The most reliable way to repeat a track or a folder is to do it on the microcontroller. |
0-3 (Repeat, Folder Repeat, Single Repeat, Random) |
| 0x09 |
Playback sources. U (0x00 / 0x01): USB Flash Drive (plugged into USB+ / USB-). SD (0x02): MicroSD Card (TransFlash card). AUX (0x03): External Analog Line-In audio mode. SLEEP (0x04): Low-power standby mode. On YX5200 chips, this unmounts active media (SD/USB) and puts the drive interface to sleep. However, on many JL/Jieli clone chips, changing the source to 0x0004 often fails or gets ignored if no active playback source was running. FLASH (0x05): On-board USB SPI-Flash memory chip (if populated on board). |
1-5 (U, SD, AUX, SLEEP, FLASH) |
| 0x0A | Standby. Goes to sleep for low power consumption | |
| 0x0B |
Normal Operation / Wake Up. Exit Low Power / Sleep mode and return to normal working state. Release Standby : If the player was put into standby mode, 0x0B resumes standard operation without performing a full hardware reboot (unlike reset command 0x0C). |
|
| 0x0C | Reset. | |
| 0x0D | Play. Resumes playback. | |
| 0x0E | Pause. | |
| 0x0F |
Play using folder and file name. The chip hardcodes its directory
parsing rules to look for two-digit decimal string names: 01 through
99. |
Folder: folders 01-99. File name format must be 3 digits in length. E.g.: 001.mp3. Valid range: folders 1-99, tracks 1-255. Combines folder (01-99) into High Byte and track (001-255) into Low Byte |
| 0x10 |
Analog gain trimming / volume normalization. |
DH (Data High / Byte 5): Acts as an Enable/Disable switch. - DH = 1 (0x01): Enables manual gain adjustment overriding master volume. - DH = 0 (0x00): Disables manual gain adjustment. DL (Data Low / Byte 6): Sets the fine gain level from 0 to 31. For standard audio volume control, ignore command 0x10 and use Command 0x06 (Set Volume 0-30) instead. |
| 0x11 |
Single-Track Repeat Toggle Immediately forces the currently playing track to repeat continuously. |
1 = loop current file, 0 = stop looping current file |
| 0x12 | Play files located inside a folder named /MP3/. File names must be 4 digits in length. E.g.: 0001.mp3. | Valid range: tracks 1-9999. |
| 0x13 | Play an interruptive advertisement file from /ADVERT/ folder (0001.mp3 - 9999.mp3). Pauses current playback, plays advert, and auto-resumes original track when finished. A track must currently playing for the advert to play. | Valid range: tracks 1-9999. |
| 0x14 |
Play large folder. Folder number can be any integer from 1 to 15. Track number can be any integer from 1 to 4095. File names must be 4 digits in length. E.g.: 0001.mp3. |
Top 4 bits = Folder (1-15), Bottom 12 bits = Track (1-4095) |
| 0x15 | Manually stop the advertisement early and return to main track playback. |
|
| 0x16 | Stop all audio playback. |
|
| 0x17 | Continuously play a folder. Not widely supported. | Folder number [01-99]. |
| 0x18 | Shuffle. Not widely supported. |
|
| 0x19 | Single cycle play. Not widely supported. | 0: start play. 1: stop play. |
| 0x1A | Set DAC. | 0: start up DAC output. 1: DAC no output. |
Serial query commands
| CMD | Description | Parameter |
|---|---|---|
| 0x3F |
Send initialization parameters. On non-YX5200 modules, the 0x3F is ignored when sending and is sent by the module only on power-up or on reset. When sent to the module (Query Online Storage): Sending 0x3F (with arg = 0x0000) forces the module to return a bitmask of all currently available storage media. When received from the module (Initialization Notification): When the DFPlayer Mini boots up or resets, it spontaneously transmits 0x3F with a parameter mask indicating online storage devices. |
0x01 = USB Flash Drive detected. 0x02 = MicroSD Card detected. 0x03 = Both USB and SD detected. |
| 0x40 | Incoming error frame sent from the DFPlayer. The parameter low byte (Byte 6) indicates the error code. |
0x01 = Module busy 0x02 = Sleep mode 0x03 = Checksum error 0x04 = File not found |
| 0x41 | ACK (Acknowledge) response. |
|
| 0x42 | Query status. |
Parameter High: 0x00: Stopped / Idle (Ready for new commands) 0x01: Playing 0x02: Paused |
| 0x43 | Query volume. |
|
| 0x44 | Query EQ. |
|
| 0x45 | Query playback mode. |
|
| 0x46 | Query software version. |
|
| 0x47 | Query the total number of U-disk files. |
|
| 0x48 | Query the total number of TF card files. |
|
| 0x49 | Query the total number of TF flash files. |
|
| 0x4A |
Queries the total number of tracks inside a specific folder. Not
widely supported. The High Byte is 0x00 and the Low Byte is the target folder number (e.g., parameter 0x0001 queries folder 01). |
Returns a frame with command 0x4A where the 16-bit parameter represents the total file count in that specific folder. |
| 0x4B | Query the current track of U-disk. |
|
| 0x4B | Query the current track of U-disk. |
|
| 0x4C | Query the current track of TF card. |
|
| 0x4D | Query the current track of TF flash. |
|
Library
Class constructor
DFPlayer(UARTstruct_t* uartInstance, volatile uint8_t* busyPORT, uint8_t pinBit); DFPlayer(UARTstruct_t* uartInstance, volatile PORT_t* busyPORT, uint8_t pinBit);
uartInstance
UART object such as &uart0 to use UART module 0 or &uart1 for UART1.
busyPORT
Port where the BUSY pin is. E.g. &PORTC. If not used pass nullptr.
pinBit
Pin number on the port, e.g. PC0. If not used set it to 0.
Public methods
Initialization
bool init(uint8_t* playbackDevices)
Initialize UART and verify module readiness with up to 3 retries.
playbackDevices
Pointer to an 8-bit variable to store detected playback devices. 0x01=USB, 0x02=SD, 0x03=SD and USB.
Return
True on success.
Read BUSY pin
bool isBusy()
Read the BUSY pin on DFPlayer Mini. LOW = Playing, HIGH = Idle. Must be used after the command has been transmitted by the UART and the ACK has been received since only then the pin will be LOW.
Return
Pin state as true or false.
Play track by index
void playTrack(uint16_t trackNumber)
Global Track Player (CMD 0x03)
- Folder: root.
- File names must be
4 digits in length. E.g.: 0001.mp3.
- Valid range: tracks 1-2999.
Play
the specified track number. Uses FAT indexing which means it doesn't read the
file number but it uses the order in FAT table that depends on which order the
files were copied. Same with playNext() (0x01) and
playPrevious() (0x02) they are all global cluster navigators.
trackNumber
Track number can be any integer from 1 to 2999.
Play next
void playNext(void)
Play next track.
Play previous
void playPrevious(void)
Play previous track.
Play folder track
void playFolderTrack(uint8_t folder, uint8_t track)
Standard Folder (CMD 0x0F)
- Folder: folders 01-99.
- File name
format must be 3 digits in length. E.g.: 001.mp3.
- Valid range: folders
1-99, tracks 1-255.
Play a track by filename number in the
specified folder.
folder
Folder number can be any integer from 1 to 99.
track
Track number can be any integer from 1 to 255.
Play folder track large
void playFolderTrackLarge(uint8_t folder, uint16_t track)
Large Folder (CMD 0x14)
- Folder: folders 01-15.
- File names must
be 4 digits in length. E.g.: 0001.mp3.
- Valid range: folders 1-15,
tracks 1-4095.
Play track from folder using 4-digit filenames
(0001.mp3 - 4095.mp3).
folder
Folder number can be any integer from 1 to 15.
track
Track number can be any integer from 1 to 4095.
Play MP3 folder
void playMP3Folder(uint16_t track)
MP3 Folder (CMD 0x12)
- Folder: /MP3/.
- File names must be 4 digits
in length. E.g.: 0001.mp3.
- Valid range: tracks 1-9999.
track
Track number: 1-9999.
Play advert
void playAdvert(uint16_t track)
Play an interruptive advertisement file from /ADVERT/ folder (0001.mp3 -
9999.mp3). Pauses current playback, plays advert, and auto-resumes original
track when finished.
A track must currently playing for the
advert to play.
track
Track number: 1-9999.
Stop advert
void stopAdvert()
Manually stop the advertisement early and return to main track playback.
Stop play
void stopPlay()
Stop all audio playback.
Play
void play()
Resume playback.
Pause
void pause()
Pause playback.
Set volume
void setVolume(uint8_t volume)
Set volume.
volume
Integer from 0 to 30.
Increase volume
void volumeIncrease()
Increase volume by 1.
Decrease volume
void volumeDecrease()
Decrease volume by 1.
Set EQ
void setEQ(uint8_t eq)
Set EQ preset.
eq
Integer from 0 to 5 or one of following macros:
DFP_EQ_NORMAL DFP_EQ_POP DFP_EQ_ROCK DFP_EQ_JAZZ DFP_EQ_CLASSIC DFP_EQ_BASS
Set playback source
void setPlaybackSource(uint8_t source)
Set playback source.
U (0x00 / 0x01): USB Flash Drive (plugged
into USB+ / USB-).
SD (0x02): MicroSD Card (TransFlash card).
AUX (0x03): External Analog Line-In audio mode.
FLASH (0x05): On-board USB
SPI-Flash memory chip (if populated on board).
source
Integer from 1 to 5 (U, SD, AUX, SLEEP, FLASH) or one of following macros:
DFP_PLB_DEVICE_USB_FLASH DFP_PLB_DEVICE_SD_CARD DFP_PLB_DEVICE_AUX DFP_PLB_DEVICE_SPI_FLASH // if present on board
Sleep mode
void enterSleep()
Puts the audio decoder IC into low-power standby/sleep mode.
Exit sleep mode
void exitSleep()
Exit standby and resume normal operation without performing a full reboot.
Reset
void reset()
Reset IC.
Check event
bool checkEvent(DFPEventData_t* eventData)
Universal non-blocking event handler that can be used in the main loop. Polls UART for spontaneous notifications (Track finished, Card inserted/removed, Errors).
eventData
Pointer to a structure that will be populated with event details.
Return
True if a valid event occurred, false otherwise.
Query status
uint16_t queryStatus()
Query current playback state.
Return
0 = Idle, 1 = Playing, 2 = Paused, 0xFFFF = Query Failed.
Query software version
uint8_t querySoftwareVersion()
Return
Version number. E.g. 8.
Query EQ
uint8_t queryEQ()
Return
Preset number.
Query volume
uint8_t queryVolume()
Return
Number representing current volume from 0 to 30.
Query playback mode
uint8_t queryPlaybackMode()
Return
0-3 (Repeat, Folder Repeat, Single Repeat, Random). Not widely supported.
Query total SD files
uint16_t queryTotalFilesSD()
Query total number of files on the SD card.
Return
Number of files.
Query current SD track
uint16_t queryCurrentTrackSD()
Query current track playing from SD card.
Return
Track number.
Code example
This example include UART debugging outputs that should be removed/commented out during production. UART0 is used to program the microcontroller over bootloader while UART1 is connected to DFPlayer RX/TX pins.
#include "DFPlayer.h" // Define F_CPU in project settings to be globally accessible and easier to maintain. // See: https://www.programming-electronics-diy.xyz/2024/01/defining-fcpu-in-microchip-studio.html #ifndef F_CPU #warning "F_CPU not defined. Define it in project properties." #elif F_CPU != 16000000 // replace with your actual frequency #warning "Wrong F_CPU frequency!" #endif int main(void) { // Local variables uint8_t ret_code = 0; uint8_t current_folder = 1; uint8_t current_track = 1; uint8_t max_tracks_in_folder = 10; // Track count for current folder uint8_t playback_devices = 0; // uint8_t status = 0; DFPEventData_t eventData; // Create player DFPlayer player(&uart1, &PORTC, PC0); // On UPDI devices // DFPlayer player(&uart1, &PORTC, PIN0_bp); // or 0 // Initialize player ret_code = player.init(&playback_devices); // Fetch static meta-data at startup uint8_t version = player.querySoftwareVersion(); uint16_t totalFiles = player.queryTotalFilesSD(); uint8_t currentEQ = player.queryEQ(); uint8_t currentVolume = player.queryVolume(); uint8_t playbackMode = player.queryPlaybackMode(); // Print info if (ret_code) { UART_sendString(&uart1, "Module initialized!\n"); UART_sendString(&uart1, "Detected playback devices:\n"); if (playback_devices == 0x01) { UART_sendString(&uart1, "- USB\n"); } else if (playback_devices == 0x02) { UART_sendString(&uart1, "- SD Card\n"); } else if (playback_devices == 0x03) { UART_sendString(&uart1, "- SD Card & USB\n"); } else { UART_sendString(&uart1, "- None\n"); } UART_sendString(&uart1, "Version: "); UART_sendInt(&uart1, version); UART_sendString(&uart1, "\n"); UART_sendString(&uart1, "Files: "); UART_sendInt(&uart1, totalFiles); UART_sendString(&uart1, "\n"); UART_sendString(&uart1, "EQ: "); UART_sendInt(&uart1, currentEQ); UART_sendString(&uart1, "\n"); UART_sendString(&uart1, "Volume: "); UART_sendInt(&uart1, currentVolume); UART_sendString(&uart1, "\n"); UART_sendString(&uart1, "Playback Mode: "); UART_sendInt(&uart1, playbackMode); UART_sendString(&uart1, "\n"); } else { UART_sendString(&uart1, "Module initialization failed!\n"); } // Wait for UART to finish sending info UART_isSending(&uart1, F_CPU, 9600); player.setVolume(20); player.playFolderTrack(3, 8); // Volume fade in effect // for (uint8_t i = 0; i < 26; i++) { // _delay_ms(50); // player.volumeIncrease(); // } while (1) { // Query player status // status = player.queryStatus(); // if (status == DFP_STATUS_IDLE) { // // Module is idle // } else if (status == DFP_STATUS_PLAYING) { // // Track is currently playing // } else if (status == DFP_STATUS_PAUSED) { // // Track is currently paused // } // Universal non-blocking event loop if (player.checkEvent(&eventData)) { switch (eventData.event) { case DFP_EVENT_TRACK_FINISHED: UART_sendString(&uart1, "Track finished playing!\n"); // Wait for UART to finish sending UART_isSending(&uart1, F_CPU, 9600); // Auto-play next track or update app state here current_track++; if (current_track > max_tracks_in_folder) { //current_track = 1; // Loop or advance folder } else { player.playFolderTrack(current_folder, current_track); } break; case DFP_EVENT_CARD_ONLINE: UART_sendString(&uart1, "Card inserted\n"); break; case DFP_EVENT_CARD_OFFLINE: UART_sendString(&uart1, "Card removed\n"); break; case DFP_EVENT_ERROR: UART_sendString(&uart1, "DFPlayer Error received!\n"); if (eventData.errorType == DFP_ERR_BUSY) { UART_sendString(&uart1, "Module is busy\n"); } else if (eventData.errorType == DFP_ERR_SLEEP) { UART_sendString(&uart1, "Module is sleeping\n"); } else if (eventData.errorType == DFP_ERR_CHECKUSM_ERROR) { UART_sendString(&uart1, "Checksum mismatch\n"); } else if (eventData.errorType == DFP_ERR_FILE_OUT_BOUNDS) { UART_sendString(&uart1, "File not found globally\n"); } else if (eventData.errorType == DFP_ERR_FILE_MISMATCH) { UART_sendString(&uart1, "Track index mismatch\n"); } else if (eventData.errorType == DFP_ERR_FOLDER_OUT_BOUNDS) { UART_sendString(&uart1, "Track index does not exist inside the specified folder\n"); } else if (eventData.errorType == DFP_ERR_SD_FAIL) { UART_sendString(&uart1, "SD card read/write failure or card removed during operation\n"); } else if (eventData.errorType == DFP_ERR_SLEEP_ENTRY) { UART_sendString(&uart1, "Error entering low-power sleep mode\n"); } break; default: break; } } } return (0); }
Links
|
Link includes: - DFPlayer.h, DFPlayer.cpp - uart.h, uart.c - utils.h, utils.c |
|
| v1.0 | DFPlayer |
| Other links | |
| uart | |
| Changelog | |
| v1.0 |
12-09-2026 Public release under GNU GPL v3 license. |




