ESP32 C3 浅谈I2S DAC 与 TF卡数字音频MP3 FLAC 播放器-Arduino中文社区 - Powered by Discuz! Archiver

cqcqwind 发表于 2022-5-25 11:46

ESP32 C3 浅谈I2S DAC 与 TF卡数字音频MP3 FLAC 播放器

新来论坛, 各位多指教。


通过ARDUINO+IDF开发的esp32c3的T卡 数字音频播放器测试基本完成了,为了获取论坛成长:lol,把开发过程记录下来,请坛友们多指正:

实际效果在B站https://www.bilibili.com/video/BV1uB4y1R76d?spm_id_from=333.337.search-card.all.click

https://www.bilibili.com/video/BV1uB4y1R76d?spm_id_from=333.337.search-card.all.click


一为什么关注esp的音频播放功能:
    不少坛友的esp帖子中,谈到了ESP的音频播放功能,一个重要的因素就是esp的系列iot mcu,提供了i2s接口(spdif输出接口我们先不谈)。这样,如果ESP对数字音源文件做了解码,如果解码过程没有损失,那么通过数字接口i2s输出的就是数字信号,后接一个i2s的音频dac,将数字信号转为模拟信号,输出直接驱动扬声器,或者传递给后级功放。整个过程中我们看到, 只要保证无损的解码过程,esp就能输出无损的数字信号,只要后续的i2s前级和后级放大器足够好,不到10元的esp就可以承担起无损音乐的解码任务! 而且可以充分利用现有的成熟i2s dac模块。这个在DIY HIFI领域一根线动则成百上千的领域,真是一个价廉物美的数字信号源。或者抛开HIFI不谈,单从DIY小物品出发,用I2S音频系统也能做出一些和声音相关的小玩意,让你的小工具能够发出声音,的确比较有意思。
    特别值得一提的,嵌入式领域的软解码方案中,MP3多用的libmad库,或者helix的解码库,因为嵌入式MCU多数没有浮点处理器FPU,故大多采用了整数解码算法。尽管MP3本来就是有损压缩,整数解码还是显得有些遗憾。不过幸运的是,对于无损压缩格式FLAC而言,无需浮点数解码,因此, 大量的高清FLAC音源,ESP就可以直接拿来使用,提供真正的无损信号输出。

二 常见的esp音频解码方案
市面上涉及esp音频的开源方案中,多采用下述三种形态:
   1)esp + 外挂音频处理模块方案: 这个方案中,esp只是作为mcu来使用, 音频通过外挂的模块,如dfplayer mini等处理。esp与音频模块间通过串口或者spi等机制通讯,根据用户的输入,触发音频模块执行播放、暂停、定位等动作。这种方案好处是实现相对简单,对于公交报站、定点有限内容语音提醒、固定格式音频播放等特定应用来说很方便。外挂的音频模块往往自带TF存储,可以提供大容量的音乐存储空间。不过这个方案在略复杂的应用方面存在扩展性不佳的缺点, 例如要显示音乐频谱,或者是控制频率变换实现变音,或者是多种不同协议混杂(例如flac/ape/aac/amr),已经定死功能的外部模块无法与mcu进行大数据量音频sample级别的数据交互,实现上述功能有些困难。
   2) esp 直接音频处理方案: 在这个方案中,esp不是作为简单的mcu来控制外部模块,而是直接参与音频数据的解码,可以得到音频sample级别的数据并加以处理,根据输出的变化,又有两个方案:
         a)esp + 内置DAC超采样输出方案: 这个方案无需外部dac,直接超采样,使用软件实现的delta-sigma dac完成音频输出功能。参见https://github.com/earlephilhower/ESP8266Audio github库中的说明。此种情况下,外部接线(输出)相对简单,8266audio库的作者建议的一种接线方法如下:
                            2N3904 (NPN)
                            +---------+
                            |         |   +-|
                            | EBC |    / S|
                            +-|--|--|-+    | P|
                              ||+------+ E|
                              ||         | A|
ESP8266-GND ------------------+|+------+ K|
                                 ||      | E|
ESP8266-I2SOUT (Rx) -----/\/\/\--+|      \ R|
                                    |       +-|
USB 5V -----------------------------+

         不过需要提醒,上述方法可能存在直流成分对喇叭的伤害,可考虑加入一定的直流阻隔。
         b)显然,上述方案的音质存在明显局限性,HIFI就不用考虑了。因此,对于音质有一定要求的场景下,一般采用esp + 外置I2S DAC的方案了,就是esp解码,i2s方式数字输出到外部声卡。这种方案的灵活性非常好,成本可根据声卡选型控制,也不是特别高,在功能、性能、成本等方面可以获得很好的平衡。建议采用这样的方案。


三ESP系MCU的选型考虑
   乐鑫家的esp系列, 主流的区分8266和32, 32里头常用的,包括32, 32c3, 32s2, 和32s3,以及后期要推出的32c2.   如果按照市场定位的角度, 老大哥esp8266和 esp32c3的市场定位是接近的,单核, 一般4M的flash,不带PSRAM。其中,c3的sram为400k,比8266的大。至于其他32,提供了大flash和psram,以及双核处理能力,更多的PIN脚接入,市场定位是偏高端一些的。反应在价格上, 就是8266和c3的开发板都是10元级别的, 而其他32一般是15-35元级别的(好像实际差别不大啊,只对产品量产有影响)   本人有8266, c3, esp32 和 32s3. 其中32是自己买的16M + 8M的模块焊接的底板, S3买的aithinker家的s3-12k, c3买的合宙家的9.9元网红c3开发板。最终选择的是c3来做试验。因为这块板子做的比较精致,虽然是单核,但s3之类另外一个核是ulp的,对于MP3/FLAC这个级别的解码,C3 160MHZ CPU加带cache的指令、数据处理,C3应对起来绰绰有余。加之arduino写代码多核处理稍显麻烦,为了充分利用9.9元,就拿他上手了。 8266和c3比略有缺陷,根据8266audio库作者提示:播放flac时,flac音源的压缩level应当控制在2以下,否则8266可能播放时内存不足。

四DIY常用I2S声卡选型
    作为轻度diy玩家和手残党,本人没有焊接i2s声卡的能力,就在淘宝上购买常见成品i2s声卡吧,那到底选那款呢? 根据datasheet,找下如下信息:

    DAC采样位数输入电压输出采样频率动态范围/SNR后级淘宝价格
MAX9357AMaxim16/24/32 bit3.5-5.5单声道8-96Khz105/ PSRR77@1KHZ输出3W,直推4欧3w小喇叭12.5
CJMCU UDA1334ANXP 2020已停产<= 24bits3.5-5.5立体声16-100Khz/100db@44.1Khz后级功放阻抗3 KΩ;或耳机32欧14
PCM5102ATI16/24/32立体声8-384Khz112/112DB后级功放阻抗>1KΩ;或推耳机20-50


    我们一般使用的flac音源,存储的是44.1khz, 16bit的无损压缩过的wav数据。就是说,三款声卡都可以比较完美的支持。稍微较真一点,高品质24bit 母带级flac音源,也在上述处理范围之内。测试时带耳机麻烦,挂个小喇叭比较方便,虽然是单声道。 最后选择的是9357A和1334A,一个测试,一个用来真的听一下.其实很馋5102a的参数,但是这伙计淘宝价格差异太大,不知真假(单dac购买的价格是7元左右),所以没敢下手。最后发现,1334推一般的耳机,不做增益调试,实在是声音太大了(用了45欧的原道耳塞和SONY的MDR 7506都试过了)。而且1334不加静音控制的话,启动时会有一点电流杂音,启动后效果还可以。 建议各位diyer买9357A玩玩就可以。上述声卡都自带锁相环,无需独立的MCLK信号,一般接线只需LRC/MSEL,din,BCLK三线,加电源输入即可。
    能力强的小伙伴们就可随意发挥,自己买个1,2元的I2S DAC芯片焊个板子就好了。


后面继续。。。


Highnose 发表于 2022-5-25 13:51

先赞了,谢谢分享与解读

coloz 发表于 2022-5-25 15:36

期待更新

cqcqwind 发表于 2022-5-26 09:22

五硬件环境简单一览

      附图是测试用的硬件环境,可以看到各个元件的大小。楼主因为是手残党不会画板子和焊接SOP封装原件,只能采用最原始的面包板+杜邦线方式连接(多亏I2S是数字信号输出啊,杜邦线不会对信号有任何劣化)。图中98357是测试时使用的,直接推小喇叭。试听时换上1334加mdr 7506耳机。 240x320的TFT IL9341显示是之前把网红项目小电视移植到C3上用的。 T卡模块拍这个记录的时候还没买,后面买的。第一阶段实际测试的器件其实只涉及esp32c3, max98357,和小喇叭。 第二阶段涉及到完整的T卡播放,和播放器显示,就需要TF卡和TFT屏了。
      

      成本简单罗列:
      

硬件ESP32C398357喇叭QVGA TFTTF卡槽其他
价格9.912.54.5303.8T卡耳机杜邦线面包板
说明要焊排线 前期不需要前期不需要这个是以前就买的


   注意一点是ESP32C3这个开发板送了排针,但没焊接。焊接排针这个正好在楼主极限之类,于是拿了黄花烙铁、锡丝、助焊膏焊好了,比想象中容易。98357买不焊排针的省2元,楼主买了这个。 万事具备,下面就要开始敲代码了。


cqcqwind 发表于 2022-5-27 09:54

六开发环境搭建

    先预告下后面的源代码例子:
    示例一:   C3使用最简单的PROGMEM(即数组)中MP3音乐片段的播放例子与代码。(FLAC也一样,C3 4M FLASH和400K内存支持多种音频协议,性价比完美)
    示例二:   C3通过WIFI实现HTTP流式MP3播放 ,家有OPENWRT或者NAS的音乐爱好者福音(直接联网能力是IOT MCU和传统MCU如STM相比巨大的突破 )
    示例三:   C3通过TFT显示播放歌曲的名称(也可扩展到显示LRC歌词)
    示例四:   C3通过TF卡直接播放MP3和FLAC(没有NAS也没关系,自己做一个播放器吧)

    软件开发阶段,首先要搭建esp32c3的开发环境。帖子给出的代码理论上arduino IDE开发环境也能使用,但楼主选择了vscode + platformio插件形式做前期开发。platformio从今年初的版本好像就直接支持expressif平台对arduino框架的支持了,比较好用。 安装这个环境唯一的缺陷就是: 需要搭建不可言说的事务。这里特别提醒,搭建的事物必须是全局事务,因为platformio在初次创建工程或者直接下载expressif平台时,使用了http, git和python。这三种不同的工具/协议并不尊从同一个代理设置。即使在vscode环境中设置好了http代理, GIT和python也不会使用,这将导致国内网络下创建(下载工具、库源码等)失败。其中,python建议自行更新pip源设置到国内ali或者清华源,下载会更快,通过事物获取反而慢。
       选择vscode而非arduino本身的ide,除了楼主没用过arduino的ide外,还有一个重要的原因就是jtag调试支持。 熟悉ios或者android嵌入式开发的坛友应当都很清楚,在这两个平台上开发,就像在pc上开发一样,可以设置断点、单步调试!这个对于应用层开发来说帮助太大了。在单片机领域, 例如STM,调试往往需要通过外接的jlink等硬件来完成,而神奇的esp32c3,和esp32s3一样,内置了jtag功能! 合宙的这块9,9网红版,和它推出的AIR 105之类不一样,没有阉割或者隐藏jtag功能! 这样只需引出2根数据线+1跟GND线,外接一个USB小接口,就可以以近乎0的成本,在platformio里头执行jtag调试啦! 断点、单步、查看变量值、查看内存、功能非常丰富。这比stm动辄几十,贵则上百的jlink之类硬件实在是要实惠的多。
   安装好vscode和platform后,
   1)进入platformio主页,选择New Project(新建工程)
      
    2)弹出的对话框中, 输入你想做的程序工程名称,这里填的是c3mp3test,在board(开发板)中选择espressif ESP32-C3-DevKitM-1,FrameWork(开发框架)选择arduino framework,下面的工程存放位置选择缺省即可,也可自行指定位置;
    3)会出现一个wait的等待界面,如果是初次使用,platformio会下载c3 esp arudino需要的所有开发资源,例如工具链、esp arduino代码等等。没有不可言说事物的话,这一步可能失败。如果等的不耐烦,可以打开资源监视器,看看后台有没有下载任务, 没有的话, 就得自己想办法了。。。
    4)一切顺利,或者非初次使用,会出现新建的工程,这样就可以开始正式编码了:下次正式进入实例和代码一。

Highnose 发表于 2022-5-27 21:23

牛B卡拉斯,期待更新

cqcqwind 发表于 2022-6-6 10:25

本帖最后由 cqcqwind 于 2022-6-6 10:56 编辑

七:Demo1   C3(8266也适用)使用最简单的PROGMEM(即数组)中MP3音乐片段的播放例子与代码

       这一个例子,我们使用开源的8266audio库,这个库提供了MP3, FLAC, AAC等多种音频解码,支持FLASH文件系统, FLASH数组,内存, HTTP等各种数据源,使用起来极其简单方便。 例子通过最简单的数组文件播放音乐, 就是把MP3片段做成一个数组,直接编译到项目里头去。(整个项目已经打包好放在附件里,不想一步步来的坛友可以直接用platformio下载编译)。      
      按照前述步骤,新建工程,命名c3MusicDemo1后, 在左边的资源管理器中会看到最下面有一个叫做platformio.ini的文件,


      打开这个文件,我们要做如下修改:

platform = espressif32
board = esp32-c3-devkitm-1
framework = arduino
; 设置串口监控速率
monitor_speed = 115200
; 合宙C3采用的2线SPI FLASH,所以要设置成dio模式,否则烧写后无法正常运行
board_build.flash_mode = dio
; 使用8266库,platformio会自动下载更新这个库
lib_deps = earlephilhower/ESP8266Audio@^1.9.6

    main.cpp的核心代码在这里:
#include <Arduino.h>
#ifdef ESP32
#include <WiFi.h>
#include "SPIFFS.h"
#else
#include <ESP8266WiFi.h>
#endif

#include "AudioFileSourceSPIFFS.h"
#include "AudioFileSourcePROGMEM.h"
#include "AudioFileSourceID3.h"
#include "AudioGeneratorMP3.h"
#include "AudioOutputI2S.h"

//音乐数组文件在这里
#include "show.h"

AudioGeneratorMP3       *mp3;
AudioFileSourcePROGMEM*file;
AudioOutputI2S          *out;
AudioFileSourceID3      *id3;

void setup()
{
//关闭wifi,可以减少干扰和电源扰动
WiFi.mode(WIFI_OFF);

Serial.begin(115200);
Serial.printf("Sample MP3 playback begins...\n");

//音频库内部日志输出
audioLogger = &Serial;
// PLEASE_NAME_ME是音乐数组的名称,放在show.h里头
file = new AudioFileSourcePROGMEM(PLEASE_NAME_ME, sizeof(PLEASE_NAME_ME));
// MP3 id3头过滤器
id3 = new AudioFileSourceID3(file);
//生成I2S驱动
out = new AudioOutputI2S();
//设置I2S PIN脚
#if defined(ESP32)
//如果按照本C3示例接线图接线,需要设置i2s的pin脚,因原8266audio库是按照esp32的PIN脚接线的
out->SetPinout(1, 0, 12);
#else
//如果是8266,而且按照标准建议引脚接了i2s声卡,就不用额外设置pin脚
#endif
//设置MP3解码器,它的输入是ID3过滤器,输出是I2S
mp3 = new AudioGeneratorMP3();
mp3->begin(id3, out);
}

void loop()
{
if (mp3)
{
    if (mp3->isRunning())
    {
      if (!mp3->loop())
      mp3->stop();
    }
    else
    {
      delete mp3;
      mp3 = NULL;
      Serial.printf("MP3 done\n");
      delay(1000);
    }
}
}
音乐数组文件show.h也请拷贝到工程源代码的src目录下,和main.cpp同级。 点击编译,成功后烧写到C3开发板,如果硬件连接没有问题,上述寥寥数十行简单代码,就可以听到美妙的音乐啦。
          因为8266audio这个库支持8266, esp32等比较全面的esp系,所以有其他板子也完全能够支持。以8266为例,只要按照8266audio文档里头的pin脚接好i2s声卡,在platformio.ini里头加入

platform = espressif8266
board = nodemcuv2
framework = arduino
lib_deps = earlephilhower/ESP8266Audio@^1.9.6
upload_speed = 3000000
monitor_speed = 115200       然后注意点击底部的开发板选择,设置成nodemcuv2, 即可为8266编译了,引脚对应的情况下,代码无需修改。   
         附件是代码,因为8266audio库太大超过附件大小1M要求,所以代码里头没有包含,编译时platformio应当会自动去下载。


dy008 发表于 2022-7-24 17:33

很有意思的研究,谢谢分享,希望能继续发布后续

dy008 发表于 2022-7-24 17:36

LZ,我怎么找不到MAX9357A的资料或者模块呢?

dy008 发表于 2022-7-24 17:46

问题找到了:应该是 MAX98357A:P
页: [1]
查看完整版本: ESP32 C3 浅谈I2S DAC 与 TF卡数字音频MP3 FLAC 播放器