USB I2Sブリッジを実現するには三つの方法があります。
- PCM2706などの既成のチップを使う
- FPGAで論理実装する(トラ技のLV1-USBIMなど)
- マイコンを使いソフトウエアで実装する
最後の方法で、PIC32MX2XXにはUSBとI2Sのサポートがあるので、USBのAudioをI2Sにするモジュールをつくってみました。
左がSilicon LabsのCP2114で中央がPIC32MX220F032Bで右がTI(BB)のPCM2706のモジュールです。コネクタは統一して、SDATA,LRCLK,BCLK,MCLK,GND,5Vにしています。
回路は8MHzの水晶を付けた一般的なやつです。最初は@h_nariさんの基板でテストしていました。
当初Microchipのサンプルコードを探したのですが、
PIC32 USB Digital Audio Accessory Board(DM320014)のサンプルコードの"USB Device - Headset"を自分の開発環境でビルドしてFlashに焼いてもUSBの認識できませんでした。このコードは結構汚かったので、デバッグは諦めました。(DM320014はメモリの大きなチップを使っているので、バッファを大きく取っていて8KのPIC32MX220F032ではそのままでは動かないのかもしれません)
次にMicrochip Libraries for Applications(MLA)のサンプルコードのUSBの"Device - Audio - Speaker"のコードを確認してみたところ、このコードはUSBをポーリングで処理していて、そのまま使う事ができません。
USBのサンプルコードで"Device - Audio - MIDI"のコードは比較的新しく、XC32でもビルドされていて、割り込みで処理しているので、このコードをベースにすることにしました。
USBの基本的な処理はMLAのusb_device.cに処理があり、このコードがレポジトリにあるusb_config.hをincludeしています。
このコードに最初のDM320014のサンプルコードをかけ合わせてみたのですがうまく動きません。
DM320014のサンプルコードは同時に録音と再生を行っているためかAK4645AをI2Sのマスターにして、PIC32MXをスレーブにしているようです。再生だけであればPIC32MXをマスターにするのが普通です。
なかなか動かないので一旦I2Sだけの確認に前の記事を試しました。これが動いたのでI2Sのコードを混ぜ合わせてみました。
これで、どうにかUSBからの信号がI2SのSDATA,LRCLK,(MCLK)に出力されるようになったのですがBCLKが出ません。デバッグしてみたところUSBの初期化とコンフリクトしているようでした。
検索してみたらSPIとUSBで同じ問題がありました。USBがBCLKのPINを使ってしまうようです。
config.hのCONFIG_FVBUSONIOを0にする必要がありました。
これでI2Sでデータが送り出されるようになって48K 16bitの再生ができるようになりました。
DM320014のサンプルコードは録音と再生を同時におこなうコードになっていたのですが、録音の部分のコードはばっさり消しました。またDACのAK4645Aをi2cで制御していたのですが、この部分も消しました。またmain.cのPIC32MX以外のPICのコードも消しました。
USBのディスクリプタは所々にサイズが入っていて、手で修正するのは難義でした。
サンプルコードは理解しやすいコードであるのが望ましく、録音と再生のコードは別にするのが良いような気がします。あとPIC32MXのレジスタアクセスはレジスタ丸ごと、ビットフィールドと、マクロでの設定ができて、サンプルコードでは結構バラバラになっていて理解の妨げになります。I2S共通の処理とAK4645A固有の処理が一緒くたんに実装されているのもいただけないです。
いろいろ調べてみるとサンプリング周波数の設定機能が実装されていて32KHzと48kHzが設定できるようにコードやディスクリプタがなっているのですが、ところどころに48kHz固定のコードがあります。
あと(株)インターフェースさんのページにUSBオーディオの良い説明のページがあったのですが、48kHzの場合、USB Full Speed(12MHz)の1msのIsochronous転送では通常は48フレームの転送ですが、47フレームから49フレームの転送も許容されるという事です。これも実装されていません。
もう一つUSBディスクリプタには44.1kHzサンプリング周波数設定がコメントアウトされていて、main.cには残骸が残っていますがak4645a.cには全くありません。自分も44.1kHzを試してみたのですが、うまくいかないので、サンプルを作った人も同じだったのかもしれません。
DM320014は24BitなDAC付きなんですが、24Bitのサンプルコードはどこにもありません。
MLAのディレクトリ名にスペースが入っている物があって困りものです。ほんと素人仕事です。
DM320014のサンプルコードにはMLAのファイル(usb_function_audio.c)が含まれているのですが、サンプリング周波数の設定ができるように修正が入っています。なぜかMLAのファイルには定義があるのに実態が無い状態でした。
ビルドはMac OS X雪豹でPinguinoのgccとMLAとxc32のファイルを使っています。
xc32の最適化できるバージョンが有料になっているのでPinguinoのgccを使っているのですが、かなり変則的なビルド環境なのでPlatformioに移したいのですが、ldのエラーがでたりplib.hがなかったりして、今のところ断念しています。
USBで受信したデータをI2Sで送り出す簡単なお仕事なので、MIPS16を使わなくてもバイナリは20KくらいでPIC32MX220F032Bに十分に入ります。
DACをつないでテストしているのですが、特に問題なく動いています。チップがちょっと大きいですがDIPだし秋月で安く買えるし、結構良いような気がしています。このコードや回路をチューニングすればTENOR TE7022LやXMOS ES9028Q2MやSaviAudio SA9027に匹敵するものが作れるかな?
ほとんどのUSB I2SブリッジチップにはボリュームボタンなどのためにHIDが実装されています。ディスクリプタ作るの面倒だし、特に必要もないので実装しないつもりです。
秋月のPIC32MX220F032Bは以前は220円でしたが現在(2018/6)は270円になっていて、なぜかPIC32MX230F064Bと同じ値段になってしまっています。最近秋月はよく値段が変わってちょっと残念です。
DM320014のサンプルコードの担当者にも問題がありますが、MLAにも問題があります。またxc32の有料化されている事や、plib.hのライセンスの事などもあり、会社全体に問題があるようなきがしてなりません。
コードを整理して24Bitサポート入れてみましたが、32Kしか使えなかったです。ベタな実装では限界かもしれません。16Bitの44.1Kもなぜかおかしいです。
内部での処理はこんな感じになります。
USBのVID/PIDはサンプルコードのままになっているので、注意してください。
DM320014は12MHzの水晶発振器を使っているようなので、水晶発振子よりも良いのかもしれません。
コードをクリーンアップしたら数十分でハングするようになってしましました。。。とりあえず戻しましたが、どうも何か秘伝のたれが潜んでいるようです。
結構いい加減な方ですが現在のコードは24時間の連続再生テストをしてあります。
LPCやSTM32やPSoCにもI2Sをサポートしたチップがありますが、PIC32MXはDIP品が秋月で入手できるので良いかもしれません。マイコンによってはMCLKの無いI2Sサポートだったりすることもあるようです。またMCLKについてはPIC32MXの資料が一番しっかりしています。
TDA1543,AK4382A,FN1242,PCM5102でチェックしてすべて問題なく動いています。
TDA1543はI2Sの規格を作ったPhilips社による90年代初頭につくられNon Over Sampling(NOS)なチップです。AK4382A,FN1242は2000年台、PCM5102は2010年台に作られたものです。I2Sの仕様が使い続けられていて古いものも同じように使えることは良いことです。
思い出してみると90年代初頭にはすでにOver SamplingなCDプレーヤなどが製品化されていたので、TDA1543はNOSとしては最後のチップなのかもしれません。それゆえ、息が長いのかもしれません。製品発売時はPhilipsでしたがNXPなマークのチップもあるようです。
FPGA + USB Phyで同じような事もできるようです。信号をいじりたい場合などは、こちらが良いのかもしれません。
2018/6/30 githubでリリースタグ打って、コンパイル済みバイナリ用意してみました。PIC32MX220F032Bに焼くだけで試せます。
Mac OS Xの10.4などで試していますが、WindowsではUSBディスクリプタの問題で正しくオーディオデバイスとして認識できないようです。
認識されても、鳴らない事もあるので、実験程度のものと考えてください。