Overview
The MP3-TF-16P — the module the world knows as the DFPlayer Mini — is a complete MP3 player on a postage stamp: microSD slot, MP3/WAV decoder, DAC, and a 3W class-D amplifier that drives a small speaker directly. Your microcontroller sends short serial commands ("play track 7", "volume 20") and the module does everything else, streaming audio with zero load on your code.
That architecture is why it powers half the talking props on the internet: Halloween decorations, museum exhibit buttons, doorbells with custom chimes, talking clocks, model railway sound effects, toy voice boxes, and accessibility devices. Load numbered MP3 files onto a FAT32 card, wire two UART pins (9600 baud), connect a 4-8 ohm speaker across SPK_1/SPK_2 — done. It can even run standalone with buttons on the ADKEY pins, no microcontroller at all.
Beyond the basics it offers folder-based organization (playing "folder 3, track 12" for multi-category sound boards), a BUSY pin that reports playback state without polling, stereo line-level DAC outputs for feeding an external amplifier like the PAM8406, and volume/EQ control from code. It runs from 3.2-5V and is happiest at 5V with a decent capacitor when driving a speaker hard.
At a Glance
Specifications
| Parameter | Value |
| Module | MP3-TF-16P (DFPlayer Mini compatible) |
| Formats | MP3 (8-320 kbps), WAV; 11-48 kHz sample rates |
| Storage | microSD (TF) up to 32 GB, FAT16/FAT32 |
| Control | UART 9600 8N1 command set; ADKEY resistor buttons; IO_1/IO_2 short-press keys |
| Amplifier | ~3W into 4 ohm (5V) on SPK_1/SPK_2 — speaker floats, no ground! |
| DAC Output | Stereo line-level on DAC_L / DAC_R (24-bit DAC) |
| Volume / EQ | 30 volume steps; 6 EQ presets |
| BUSY Pin | LOW while playing, HIGH when idle |
| Supply | 3.2 - 5.0V; ~20 mA idle, peaks ~200 mA+ at loud playback |
| File Naming | 0001.mp3, 0002.mp3… in root or /01-/99 folders (001.mp3…) |
| Size | 21 x 21 mm, 16 pins |
Pinout Diagram
Left side: VCC, RX, TX, the stereo DAC pair, SPK_1, GND, SPK_2. Right side: BUSY, the USB data pair, the two ADKEY resistor-button inputs, IO_2, GND, IO_1. For microcontroller use you'll touch VCC, GND, RX, TX, the speaker pair, and optionally BUSY — the rest can stay unconnected.
Wiring Guide
Two universal rules: put a 1k resistor in series with the module's RX pin (tames 5V logic and the noise-injection quirk), and wire the speaker ONLY across SPK_1/SPK_2 — never to ground.
Arduino Wiring
| Module Pin | Arduino Pin | Details |
|---|---|---|
| VCC / GND | 5V / GND | 100-470 uF cap helps at volume |
| RX | D11 via 1k | Commands in |
| TX | D10 | Replies out |
| SPK_1 / SPK_2 | Speaker 4-8 ohm | Across the pair only |
| BUSY | D7 (optional) | LOW = playing |
ESP32 Wiring (UART2)
| Module Pin | ESP32 Pin | Details |
|---|---|---|
| VCC / GND | VIN (5V) / GND | |
| RX | GPIO 17 (TX2) via 1k | 3.3V drive works fine |
| TX | GPIO 16 (RX2) | Module TX is ~3.3V level |
| SPK_1 / SPK_2 | Speaker |
Raspberry Pi Wiring (UART0)
| Module Pin | Pi Pin | Details |
|---|---|---|
| VCC / GND | Pin 2 (5V) / Pin 6 | |
| RX | Pin 8 (GPIO 14, TXD) via 1k | |
| TX | Pin 10 (GPIO 15, RXD) | |
| SPK_1 / SPK_2 | Speaker |
Raspberry Pi Pico Wiring (UART0)
| Module Pin | Pico Pin | Details |
|---|---|---|
| VCC / GND | VBUS (5V) / GND | |
| RX | GP0 (UART0 TX) via 1k | |
| TX | GP1 (UART0 RX) | |
| SPK_1 / SPK_2 | Speaker |
Code Examples
Card prep first: FAT32 format, files named 0001.mp3, 0002.mp3… copied one at a time in order. Arduino/ESP32 use the DFRobotDFPlayerMini library; Pi and Pico send the 10-byte command frames directly — same protocol, no dependencies.
Arduino
// MP3-TF-16P / DFPlayer Mini - Arduino Example
// TX->D10, RX->D11 via 1k | Library: "DFRobotDFPlayerMini"
#include <SoftwareSerial.h>
#include <DFRobotDFPlayerMini.h>
SoftwareSerial mp3Serial(10, 11); // RX, TX
DFRobotDFPlayerMini player;
void setup() {
Serial.begin(115200);
mp3Serial.begin(9600);
if (!player.begin(mp3Serial)) {
Serial.println("DFPlayer not responding - check card and wiring");
while (1);
}
player.volume(20); // 0-30
player.play(1); // play 0001.mp3
Serial.println("Playing track 1");
}
void loop() {
// next track every 10 seconds as a demo
delay(10000);
player.next();
Serial.println("Next track");
}
ESP32 (Arduino IDE) — sound-effect button
// MP3-TF-16P - ESP32 sound-effect trigger
// TX->GPIO16, RX->GPIO17 via 1k, button GPIO 0 (BOOT) plays a random clip
#include <DFRobotDFPlayerMini.h>
DFRobotDFPlayerMini player;
const int NUM_TRACKS = 5; // 0001.mp3 .. 0005.mp3 on the card
void setup() {
Serial.begin(115200);
Serial2.begin(9600, SERIAL_8N1, 16, 17);
pinMode(0, INPUT_PULLUP);
if (!player.begin(Serial2)) {
Serial.println("DFPlayer not responding");
while (1) delay(10);
}
player.volume(22);
Serial.println("Press BOOT for a random sound");
}
void loop() {
if (digitalRead(0) == LOW) {
int track = random(1, NUM_TRACKS + 1);
player.play(track);
Serial.printf("Playing %04d.mp3\n", track);
delay(400); // debounce
}
}
Raspberry Pi (Python, raw protocol)
#!/usr/bin/env python3
# MP3-TF-16P - Raspberry Pi Example (raw 10-byte frames)
# TX->GPIO15, RX(via 1k)->GPIO14 | Install: pip3 install pyserial
import serial, time
port = serial.Serial("/dev/serial0", 9600)
def cmd(command, param=0):
hi, lo = (param >> 8) & 0xFF, param & 0xFF
frame = [0x7E, 0xFF, 0x06, command, 0x00, hi, lo]
checksum = -sum(frame[1:]) & 0xFFFF
frame += [(checksum >> 8) & 0xFF, checksum & 0xFF, 0xEF]
port.write(bytes(frame))
time.sleep(0.2)
cmd(0x3F) # init
time.sleep(1)
cmd(0x06, 20) # volume 20 (0-30)
cmd(0x03, 1) # play track 0001.mp3
print("Playing track 1 for 15 s...")
time.sleep(15)
cmd(0x0E) # pause
print("Paused. Next track...")
time.sleep(1)
cmd(0x01) # next
time.sleep(10)
cmd(0x16) # stop
print("Done.")
Raspberry Pi Pico (MicroPython, raw protocol)
# MP3-TF-16P - Pico MicroPython Example (raw frames + BUSY pin)
# TX->GP1, RX(via 1k)->GP0, BUSY->GP2
from machine import UART, Pin
import time
uart = UART(0, baudrate=9600, tx=Pin(0), rx=Pin(1))
busy = Pin(2, Pin.IN, Pin.PULL_UP) # LOW while playing
def cmd(command, param=0):
hi, lo = (param >> 8) & 0xFF, param & 0xFF
frame = [0x7E, 0xFF, 0x06, command, 0x00, hi, lo]
checksum = -sum(frame[1:]) & 0xFFFF
frame += [(checksum >> 8) & 0xFF, checksum & 0xFF, 0xEF]
uart.write(bytes(frame))
time.sleep_ms(200)
cmd(0x3F) # init
time.sleep(1)
cmd(0x06, 18) # volume
cmd(0x03, 1) # play 0001.mp3
print("Playing...")
while busy.value() == 0: # wait until the track finishes
time.sleep_ms(100)
print("Track finished - playing track 2")
cmd(0x03, 2)