Phát nhạc từ thẻ SD qua I2S trên ESP32: luồng dữ liệu, nghẽn SPI và lý do WAV dễ giật hơn MP3
Bài viết phân tích luồng dữ liệu từ thẻ SD qua buffer RAM và giải mã tới I2S/DAC trên ESP32, tính băng thông 1,41 Mbit/s của WAV 16-bit/44,1 kHz và giải thích vì sao WAV dễ giật hơn MP3 khi thẻ nối qua SPI so với SDMMC 1-bit/4-bit.
Mục lục
- Luồng dữ liệu từ thẻ nhớ tới loa
- Băng thông WAV cần lớn hơn MP3 bao nhiêu?
- Ví dụ: cùng buffer 32 KB, WAV và MP3 chịu được thẻ khựng bao lâu?
- Nghẽn cổ chai ở giao tiếp thẻ: SPI so với SDMMC
- Ví dụ: một bus SPI vừa nuôi màn hình vừa nuôi WAV
- Vì sao phát WAV dễ giật hơn MP3 trên SPI?
- Làm thế nào để phát từ thẻ ổn định hơn?
- Bảng khoanh vùng lỗi thường gặp
- Câu hỏi thường gặp
- ESP32 phát WAV từ thẻ SD qua SPI có được không?
- SDMMC 4-bit nhanh hơn SPI bao nhiêu?
- Tăng buffer có chữa hết giật khi phát WAV không?
- Đọc file theo khối bao nhiêu là hợp lý?
Phát nhạc từ thẻ SD (thẻ nhớ microSD lưu file nhạc) qua I2S (Inter-IC Sound — chuẩn truyền âm thanh số giữa các IC bằng BCLK, WS và DATA) trên ESP32 khả thi với cả WAV lẫn MP3, nhưng hai định dạng gây áp lực rất khác nhau lên đường truyền từ thẻ. Điểm nghẽn thường không nằm ở I2S mà ở giao tiếp với thẻ: nếu thẻ nối qua SPI (Serial Peripheral Interface — bus nối tiếp dùng chung cho nhiều ngoại vi) hoặc phải chia sẻ bus, WAV rất dễ giật trong khi cùng hệ thống đó phát MP3 lại êm. Bài này đi theo luồng dữ liệu, tính băng thông bằng số liệu cụ thể và chỉ cách khoanh vùng khi tiếng vấp. Bức tranh tổng thể nằm ở bài trụ cột kiến trúc và giới hạn xử lý âm thanh số của ESP32.
Luồng dữ liệu từ thẻ nhớ tới loa
Hệ thống gồm bốn chặng:
- Đọc file từ thẻ: chương trình mở file trên hệ thống file FAT (định dạng phân vùng phổ biến của thẻ nhớ) và đọc từng khối vào RAM.
- Đệm trong RAM: dữ liệu thô nằm tạm trong buffer (vùng nhớ đệm giữ dữ liệu chờ xử lý) để san bằng độ trễ không đều của thẻ.
- Giải mã nếu là MP3: WAV đã là PCM (Pulse Code Modulation — âm thanh số chưa nén, gồm các mẫu biên độ lấy đều theo thời gian) nên đi thẳng; MP3 phải giải nén từng khung thành mẫu PCM mới phát được.
- Đẩy ra I2S bằng DMA: DMA (Direct Memory Access — cơ chế phần cứng tự chuyển dữ liệu giữa RAM và ngoại vi, CPU không phải chép từng mẫu) liên tục lấy mẫu PCM từ vùng đệm I2S và phát ra DAC (Digital-to-Analog Converter — bộ chuyển số sang tương tự) theo nhịp clock cố định. Chặng này không chờ ai: thiếu mẫu là nghe thấy ngay.
Điểm mấu chốt: I2S tiêu thụ dữ liệu đều như đồng hồ, còn việc đọc thẻ cấp dữ liệu theo từng đợt không đều. Buffer ở giữa hấp thụ chênh lệch đó, nhưng chỉ hữu ích khi tốc độ cấp trung bình cao hơn tốc độ tiêu thụ.
Băng thông WAV cần lớn hơn MP3 bao nhiêu?
Công thức tốc độ dữ liệu của PCM chưa nén:
Tốc độ dữ liệu (bit/giây) = sample rate × độ sâu bit × số kênh
Với WAV chất lượng CD 16-bit/44,1 kHz stereo: 44.100 × 16 × 2 = 1.411.200 bit/giây, tức khoảng 1,41 Mbit/giây hay 176,4 KB/giây phải chảy liên tục không nghỉ từ đầu tới cuối bài hát.
| Định dạng | Tốc độ dữ liệu | Dung lượng 1 phút nhạc |
| WAV 16-bit/44,1 kHz stereo | 1.411 kbit/giây (176,4 KB/giây) | Khoảng 10,6 MB |
| WAV 16-bit/48 kHz stereo | 1.536 kbit/giây (192 KB/giây) | Khoảng 11,5 MB |
| MP3 320 kbit/giây | 320 kbit/giây (40 KB/giây) | Khoảng 2,4 MB |
| MP3 128 kbit/giây | 128 kbit/giây (16 KB/giây) | Khoảng 0,96 MB |
WAV 44,1 kHz cần băng thông gấp khoảng 11 lần MP3 128 kbit/giây. Mọi độ trễ ở khâu đọc thẻ đều bị WAV phơi ra nhanh hơn MP3 đúng theo tỉ lệ đó. Cần phân biệt nghẽn cấp dữ liệu ở đây với buffer DMA của I2S bị cạn, đã phân tích trong bài buffer DMA I2S và hiện tượng âm thanh bị giật.
Ví dụ: cùng buffer 32 KB, WAV và MP3 chịu được thẻ khựng bao lâu?
Ví dụ: giả sử chương trình dành 32 KB RAM làm buffer dữ liệu thô và thẻ bỗng ngừng cấp dữ liệu vì bận xử lý nội bộ. Thời gian buffer còn nuôi được tiếng bằng dung lượng chia cho tốc độ tiêu thụ:
- WAV 176,4 KB/giây: 32 / 176,4 ≈ 0,18 giây. Thẻ khựng hơn 180 mili giây là buffer rỗng, tiếng đứt.
- MP3 128 kbit/giây (16 KB/giây): 32 / 16 = 2 giây. Cùng lần khựng 180 mili giây chỉ ăn chưa tới một phần mười buffer.
Đây là tính toán lý thuyết với giả định tốc độ tiêu thụ không đổi và buffer đang đầy; thực tế thời gian chịu đựng còn ngắn hơn. Muốn phát WAV ổn định qua đường thẻ chậm, hoặc phải tăng buffer rất nhiều, hoặc phải làm khâu đọc thẻ nhanh và đều hơn.
Nghẽn cổ chai ở giao tiếp thẻ: SPI so với SDMMC
ESP32 có hai cách nói chuyện với thẻ SD. Cách thứ nhất mượn bus SPI thông thường: ít chân, thư viện nào cũng hỗ trợ, nhưng dữ liệu chỉ đi trên một đường dữ liệu. Cách thứ hai dùng ngoại vi SDMMC chuyên dụng với giao thức SD gốc, bus 1-bit hoặc 4-bit, tức truyền song song trên một hoặc bốn đường dữ liệu.
Theo tài liệu ESP-IDF của Espressif, host SDMMC có các mức clock quen thuộc là 20 MHz (mặc định) và 40 MHz (high-speed). So sánh thô ở cùng một mức clock cho thấy chênh lệch do độ rộng bus:
| Giao tiếp | Đường dữ liệu | Băng thông thô tại 20 MHz | Ghi chú |
| SPI | 1 | 20 Mbit/giây | Chưa trừ chi phí lệnh, chờ thẻ và chia sẻ bus |
| SDMMC 1-bit | 1 | 20 Mbit/giây | Đường riêng cho thẻ, không tranh ngoại vi khác |
| SDMMC 4-bit | 4 | 80 Mbit/giây | Cần đủ 4 chân DAT0–DAT3 và điện trở kéo lên theo khuyến nghị |
Băng thông thô 20 Mbit/giây nghe có vẻ thừa cho WAV 1,41 Mbit/giây, nhưng đó là con số trần khi bus truyền liên tục không nghỉ. Băng thông hiệu dụng thực tế bị ăn mòn bởi bốn yếu tố:
- Đọc theo khối nhỏ: mỗi lần đọc kèm lệnh, thời gian chờ thẻ sẵn sàng và xử lý hệ thống file; đọc từng 512 byte thì tỉ lệ thời gian không truyền dữ liệu nhạc rất cao.
- Chia sẻ bus: bus SPI thường còn gánh màn hình hoặc module khác; thiết bị khác giữ bus thì việc đọc thẻ phải đứng chờ.
- Clock thực tế thấp: nhiều module thẻ và mạch dây rời chỉ chạy ổn ở clock SPI thấp hơn khả năng của ESP32, nhất là khi dây dài.
- Độ trễ không đều của thẻ: thẻ giá rẻ đáp ứng dao động mạnh; tốc độ trung bình đủ vẫn gây đứt tiếng nếu một lần khựng vượt sức chịu của buffer.
Ví dụ: một bus SPI vừa nuôi màn hình vừa nuôi WAV
Ví dụ: máy nghe nhạc DIY dùng chung bus SPI cho thẻ SD và một màn hình màu nhỏ, clock SPI 10 MHz (băng thông thô 10 Mbit/giây). WAV cần 1,41 Mbit/giây, tưởng như chỉ chiếm 14% bus. Nhưng mỗi lần vẽ lại một khung hình 320 × 240 điểm ảnh 16-bit màu cần đẩy 320 × 240 × 16 = 1.228.800 bit, mất khoảng 0,12 giây truyền liên tục — lúc đó thẻ không được đọc thêm byte nào. Buffer 32 KB của WAV chỉ chịu được 0,18 giây, nên một lần vẽ màn hình chồng thêm một lần thẻ khựng nhẹ là tiếng vấp. Với MP3 128 kbit/giây, cùng buffer đó chịu được 2 giây nên gần như không nhận ra. Đây là kịch bản tính toán theo giả định nêu trên, không phải kết quả đo trên board cụ thể.
Vì sao phát WAV dễ giật hơn MP3 trên SPI?
- Tốc độ tiêu thụ cao gấp nhiều lần: WAV rút buffer nhanh gấp khoảng 11 lần MP3 128 kbit/giây, nên cùng một độ khựng, WAV chạm đáy trước.
- MP3 có đệm giải mã tự nhiên: bộ giải mã làm việc theo từng khung nén với buffer đầu vào riêng; dữ liệu nén nhỏ nên mỗi lần đọc thẻ nạp được vài giây nhạc, rồi nhả mẫu PCM đều đặn trong lúc lần đọc tiếp theo diễn ra.
- WAV không có gì che chắn độ trễ đọc: dữ liệu đọc được bao nhiêu phát gần như bấy nhiêu theo thời gian thực, không có bước nén nào giúp một lần đọc nuôi nhiều giây.
Nói cách khác, MP3 đổi băng thông thẻ lấy tải CPU giải mã, và trên nền SPI chậm thì thương vụ đó rất có lợi. Ngược lại, nếu đã dùng SDMMC 4-bit và đọc khối lớn, WAV lại đơn giản và nhẹ CPU nhất. Khi chuyển sang lấy nhạc từ mạng, bài toán buffer còn khắt khe hơn, như trong bài ESP32 stream nhạc qua WiFi làm internet radio.
Làm thế nào để phát từ thẻ ổn định hơn?
- Ưu tiên SDMMC 4-bit khi phần cứng cho phép: băng thông thô gấp bốn lần ở cùng clock và không tranh bus.
- Đọc file theo khối lớn: mỗi lần vài KB tới vài chục KB thay vì 512 byte; đây thường là thay đổi hiệu quả nhất trên đường SPI.
- Tách task đọc thẻ riêng với độ ưu tiên hợp lý, không để việc vẽ giao diện hoặc xử lý mạng chặn đứng nó quá lâu.
- Tăng buffer theo định dạng: với WAV qua SPI, chọn dung lượng chịu được ít nhất vài trăm mili giây khựng theo công thức ở ví dụ trên; MP3 cần ít hơn.
- Hạn chế thiết bị nặng chung bus: giảm tần suất vẽ lại màn hình khi phát WAV, hoặc chuyển màn hình sang bus SPI còn lại của ESP32.
- Dùng thẻ chất lượng ổn định: nếu đã tối ưu phần mềm mà vẫn vấp ngẫu nhiên, thử một thẻ khác trước khi nghi ngờ code.
Bảng khoanh vùng lỗi thường gặp
| Triệu chứng | Nguyên nhân có thể | Cách kiểm tra | Hướng xử lý |
| WAV giật nhưng MP3 cùng thẻ phát êm | Băng thông hiệu dụng của đường thẻ không đủ đều cho WAV | Tăng buffer tạm thời; thử đọc khối lớn hơn | Đọc khối lớn, tăng buffer, cân nhắc SDMMC 4-bit |
| Giật đúng lúc màn hình cập nhật | Bus SPI dùng chung bị màn hình chiếm lâu | Tắt cập nhật màn hình khi phát để đối chứng | Giảm vẽ lại, tách bus hoặc tăng buffer |
| Cả WAV và MP3 đều vấp ngẫu nhiên | Độ trễ thẻ dao động lớn hoặc tiếp xúc khe thẻ kém | Thử thẻ và file khác; kiểm tra nguồn module thẻ | Thay thẻ, vệ sinh tiếp xúc, ổn định nguồn 3,3 V |
| Giật đều đặn theo chu kỳ ngắn | Buffer I2S quá nhỏ hoặc task nạp bị chặn định kỳ | Xem cấu hình DMA và các tác vụ chạy đồng thời | Tăng đệm I2S, tách task, giảm việc nặng song song |
Câu hỏi thường gặp
ESP32 phát WAV từ thẻ SD qua SPI có được không?
Được, vì 1,41 Mbit/giây vẫn thấp hơn nhiều so với băng thông thô của SPI. Điều kiện là đọc file theo khối đủ lớn, buffer đủ sức chịu khựng và bus không bị thiết bị khác chiếm lâu.
SDMMC 4-bit nhanh hơn SPI bao nhiêu?
Ở cùng mức clock, bus 4-bit truyền song song bốn đường dữ liệu nên băng thông thô gấp khoảng bốn lần: tại 20 MHz là 80 Mbit/giây so với 20 Mbit/giây, chưa trừ chi phí giao thức mỗi phía.
Tăng buffer có chữa hết giật khi phát WAV không?
Không. Buffer chỉ giúp sống sót qua các lần khựng ngắn hơn thời gian đệm. Nếu tốc độ đọc trung bình thấp hơn tốc độ phát, buffer dù lớn cũng cạn dần và tiếng vẫn đứt muộn hơn.
Đọc file theo khối bao nhiêu là hợp lý?
Không có con số đúng cho mọi dự án; nguyên tắc là giảm số lần đọc nhỏ trong giới hạn RAM. Nhiều dự án DIY chọn khối đọc vài KB tới vài chục KB trên đường SPI — hãy thử tăng dần và nghe kiểm chứng.
Nếu bạn đang dựng máy nghe nhạc hoặc loa DIY quanh ESP32 và cần tham khảo module DAC, ampli phù hợp, có thể xem tại Cimo.vn.