ESP32と比較的安価なD級アンプ付きI2S対応DACモジュールMAX98357A、スピーカーでSPIFFS上のmp3ファイルやヘッダファイルに変換したPROGMEM上のwav音源を再生してみた話。
MEMS I2S対応マイクINMP441、I2S対応DAC MAX98357Aでインターフォンのみならず、ESP32-WROVER+OV2640カメラを加えてビデオドアフォンでもという道の途中経過。
とりあえず、INMP441の動作確認もできたところで紆余曲折あってやっと届いたMAX98357Aの動作確認の一環です。
当初、ESP32-audioI2Sライブラリでインターネットラジオ...と思ったら、PSRAMのないESP32だからか?どうにも音を出せず、ESP32との組み合わせは後回しにして、Raspberry Pi+MAX98357A+スピーカーでインターネットラジオなど音源再生を体験してみることにしました。
Raspberry Piでは、あっさり、成功体験できたので続いてESP32、メモリ(≒バッファ)不足が原因だとすれば、ESP32メモリ内にある短時間の音源ファイルなら再生できるだろう...というわけで以前、何度か使わせて頂いたESP8266Audioライブラリで目論見通りできました。
INMP441よりは、かなりマシですが、MAX98357Aも接触不良には要注意です。
尤もINMP441と違ってハンダ付けしたものは、ジャンパワイヤを挿しても安定してますが。
よってピンヘッダと端子台未ハンダのMAX98357Aのピンホールをブレッドボード上でジャンパワイヤを挿して動作確認する場合には、留意が必要ということですね。
自身は、MAX98357Aを3個買って1つはピンヘッダと端子台をハンダ付け、残る2つは未ハンダな状態で動作確認、後者は、基本、再生を開始、音源が出力されつつ、クリックノイズが出ない状態を探るべく、ジャンパワイヤを束ねたり、広げたり、プラグ部分を抑えたりする必要がありました。
そういう状況であれば、音源は長めなものが吉です。
ESP32 | MAX98357A |
---|---|
VDD* | Vin |
GND | GND |
- | SD |
- | GAIN* |
D22 | DIN |
D26 | BCLK |
D25 | LRC |
ESP32-I2S DroneBot Workshopによれば、ESP32とMAX98357Aの配線はこのような感じになるようです。
I2Sピンと括られマイコンとの通信に関わるDACであるMAX98357AのDIN/BCLK/LRCが、それぞれ、ESP32のGPIO 22/25/26であることに意味はあるのか気になり、調べてみたのですが...イマイチわからず...。
Digital To Analog Converter (DAC) by espressif.comによれば、ESP32は2つの8bitのDACチャネルを内蔵しており、それぞれGPIO 25(Channel 1)とGPIO 26(Channel 2)があり、各チャネルは、[out_voltage = Vref * digi_val / 255]として算出・変換され、[DAC周辺機器]は、指定電圧を継続出力する[Direct Mode]、DMAによりアナログ値を継続出力する[DMA Mode]、コサイン波生成器によってコサイン波を出力する[Cosine Mode]の3つのアナログ信号の出力をサポートするとのこと。
内蔵DACについての説明かと思いきや、[DAC周辺機器]とあり、これは、外部DACも含まれるのか...?
Pinouts/Adafruit MAX98357 I2S Class-D Mono Ampによれば、MAX98357AのDIN(Data IN)は実際の読み取りデータ、BCLK(Bit Clock)はDINにデータが読み込まれることをアンプに通知、LRC(Left/Right Clock)は、DINの読み取りデータが(仮にモノラルだったとしてもステレオの)右用か左用かを通知するI2S用のピンとのこと。
MAX98357Aも[DAC周辺機器]だと仮定すると...
これらのことから、アンプ付きDACであるMAX98357AをESP32に配線する場合、少なくとも(I2Sピンと括られマイコンとの通信に関わるDACであるMAX98357Aの)BCLKとLRC、DINの何れかは、GPIO 25とGPIO 26は外せない気がする...。
また、DINに対するESP32のGPIOには制限はなさ気ながら、自身が参照したサイト含め、GPIO 22を使っているケースが多く見えるのは、(I2Sではなく)I2CのSCL(シリアルクロック)ピンでもあり、I2SとI2Cは機能は別物ながら同じ方が考案、CPU同士が通信する仕組みという類似性からくる、粋な計らいなのか、洒落なのか、至極当然そうすべきものなのか...、でも、SCLピンというならBCLKピンで、というか、データと言うなら、Data INであるDINについては、むしろSDA(シリアルデータ)ピンの方が、何かとしっくり...。
と思いきや、巷の情報では、微妙に異なるバリエーションもあるようで何が正解なのか...。
前述のリンク先のRaspberry Piの方は、I2Sに使うDIN/BCLK/LRCの3ピンは、それぞれ特定のものに決まっていて悩む余地もなかったのですが。
音量 | 配線 | MAX98357A |
---|---|---|
15db | 抵抗100kΩを介しGND | GAIN |
12db | GND | |
9db | - | |
6db | 5V/Vin | |
3db | 抵抗100kΩを介し5V/Vin |
GAIN*は、配線しない9dbの他、配線方法によって計5段階、音量を変更することができるようになっています。
SDは、込み入っているのでリンク先参照して頂きたいですが、ただ、内部抵抗を持っている関係で5V以外の入力電源を使いたい場合、SDにその電圧に見合う抵抗をつける必要がある「かも」しれないとのこと。
よってESP32のVDD*は、MAX98357Aの動作電圧が2.2V-5.5Vなので3.3Vでも5Vでも可ですが、5Vを使うのが簡単かつ無難と言えそうです。
ここでは、古いデスクトップパソコンSOTEC e-one 500Aから部品取りしたスピーカーを使用して3.3Vでは再生できず、5Vで出力でき、スピーカー仕様だと思っていたのですが、これに起因していた?
様々なシチュエーションのサンプルスケッチがあるESP8266Audioライブラリを使わせて頂きました。
wavファイルをxxd -iでヘッダファイルに変換、PROGMEMに置くことにして再生したスケッチはこれ。
ヘッダファイルとしてPROGMEMキーワード付きで配置することにしたwavファイルについては、後述のように数年前にESP8266Audioライブラリを使った際、Audacityで自身の声を入れたものを作成、使用していたものを流用しました。
ヘッダファイルに変換後の配列にPROGMEMキーワードを足し、元ファイル名が配列名となっているはずなので配列名をスケッチ側と合わせます。
これについては、数年前、同じESP8266AudioライブラリでしゃべるArduino音声合成・再生デモやしゃべるESP-01/12/ESP32音声合成・再生デモでサンプルスケッチのデモを、また、ArduinoでWAV/MP3オリジナル音声の発話で自身の声をwavファイルに保存、配列に変換してスケッチ内にPROGMEMキーワードを足したものを書いてやってみたことがあります。
ESP8266Audioライブラリのサンプルスケッチは、命名規則が徹底されており、メモリ領域名やコーデック名などを変えることで様々なパターンが使えるような規則正しい構成になっています。
よってSPIFFS上のmp3再生については、先のスケッチを、この命名規則に沿って書き換えたものとしました(結果、該当するサンプルスケッチとほぼほぼ同じになっているはずです)。
SPIFFS/mp3用のmp3ファイルについては、何らかの音楽でも良かったのですが、手っ取り早く、新たにAudacityで自身の声を録音、作成したものを使用しました。
ちなみに番外編として、先日、MAX98357AやINMP441を買って届くまでの間にDACを使わないパターンでSPIFFS上のmp3ファイル再生を試したサンプルスケッチPlayMP3FromSPIFFS.inoも試しました。
番外編NoDAC用のmp3ファイルは、とある楽曲のほんの一部をAudacityで録音、作成したものを使用しました。