雑記帳

電子計算機の"明後日"から、他愛もない話まで。

USB-DAC for STM32F4 Discovery

ええと、前回分が長くなりすぎましたので、改めて本題です。

早速軽いのを作ってみました。USB-DAC for STM32F4 Discoveryです。

イメージ 1

というのも、メイン機のSE-90PCIが絶不調(ボード差しているとよく死ぬ)になってしまいまして、急遽代替品が必要になったからです。たまたま、以前勤めていた会社から「自己啓発用」として渡されたボードが余っていたので、こいつを使ってサクっと(はいきませんでしたが…後述)作ってみました。

一応、このボード上にはDAC(CS43L22)が乗っていまして、こいつを使って音声出力しています。データフォーマットはPCM 44.1KHz 32bit ステレオ固定です(但し、DAC側は24bitまでの対応なので、I2S送信時に最下位8bitは無視されます)。また、ストリームの転送にはアイソクロナス転送の非同期モードを使用します(DACをホストと独立したクロックで動かし、別途フィードバック通知用のエンドポイントを用いてホストからの送信データ長を調整します)。Windows Vista以降であれば標準ドライバで使用できるはずです。

今回から、ブツのアップ先をgithubにしてみました。また、ファーム書き込みに開発環境が必要なので、生成済のバイナリは用意していません。試してみたい方は"System Workbench for STM32"を導入の上、リポジトリのプロジェクトをインポートしてビルド→デバッグ(書き込み)を行って下さい。他、動作中のLEDに関する説明や、micro-B側からのバスパワー化改造等については、リポジトリの方のreadmeを参照下さい。そもそも英語でまとまった文章を書いたのがほぼ初みたいなものなので、あんまり酷いところや意味不明な文などがありましたらご指摘頂けると幸いです。

本当はサンプリングレート・ビットレート等を色々選べるようにしようと思ったのですが、チップのデータシートを見れば見るほど微妙な気がしてきたので、この石を使って全力で作るのは止めました。というのも、まずチップ内蔵のUSB Phyがフルスピードまでにしか対応していないため、データレートを上げるのは困難です(1023バイト/msまでしか転送できないため、176.4kHz 24bit ステレオがギリギリアウトとなる)。また、DACへのMCLK出力を有効化すると、一般的な帯域における実サンプリングレートでそこそこの誤差が出ます。CS43L22はMCLKを入力しないと使えないDACのため、止むなく44.1kHzのストリームを約44.108kHzで再生する実装としています。幸いフィードバック通知用のエンドポイントを使っていますので、こんな誤差持ちでもデータバッファが空になったりすることはありません(長時間演奏でもおかしくなることはないはずです)。

また、プロジェクトの雛型自体はCubeMXで吐かせたものを使っているのですが、USB Audioスタックがそのままだとまるで使い物にならなかったので、それなりに手を加えております。他、USBコアやI2Sドライバにも手を入れています。

特に、このチップのアイソクロナス転送機能は、送受信開始時に予め「奇数フレーム / 偶数フレームのどちらで転送すべきか」を適切に指定する必要があります。ドライバの素の実装では、送受信開始時点で最後に受信したSOFのフレームIDを見て、次のフレームで正しく転送が行われるようビットを設定しているのですが、そもそも次のフレームで転送が行われるかどうかはホスト次第ですし、再生停止中(ホストがSET_INTERFACEでalt = 0を選択している状態)はOUT転送が全く行われません。さらに、フィードバック用のエンドポイントはディスクリプタに記載された周期(今回は32ms毎)でしかIN転送リクエストが来ませんので、タイミングによってはフィードバック送信が全く行えなったり、初回のデータストリームを取りこぼす可能性があります。

元のプロトコルスタックではこの辺りに対するケアが全く無く、このままだと全く使い物にならないのですが、データシートをよく見ると「アイソクロナス転送のincomplete割り込み」というのがありまして、SOF~一定時刻までに予定したアイソクロナス転送が行われなかった場合に割り込みを起こすことができます(但し、素のプロトコルスタックでは、このコールバック関数の呼出パスが突然分断されてたりする謎仕様です)。この辺を補ったところ、EVEN/ODDの指定を間違えた場合にもこの割り込みが来ているようですので、今回はこれを使って転送をリトライするようにしました(この辺の挙動については、CubeMXの生成物に対するものではありませんが、海外フォーラムなどでは詳しい議論が行われていたりします。最初原因がわからずマジで頭抱えてました…先人達に多謝)。

以上のように、USB-DACという使い方に対しては大変筋が悪い石のような気がしますので、わざわざこのボードを買ってきてまで作るようなもんではないと思います。が、もし手元にSTM32F4 Discoveryが使い道も無く余っているようでしたら、こういった形で復活させてみるのも良いと思います。

あ、ちなみに音はそんなに悪いもんじゃないですよ。直接ミニフォーンジャックにヘッドホンを差して聞いても、特に目立ったノイズは感じません。自前のアンプ + SX-WD5KTに繋いでみても、今までのSE-90PCI(DACからの直出し)と比べて、一聴してわかるほどの悪化は感じられません(少なくとも、良くなった印象はありません)。まぁこんなもんか…という感じです。

でもまぁ、そのうちハイスピード対応の石と差動出力対応のDACを使ってちゃんと作りたいですねぇ(秋月のラインナップだとNXPのLPC4337位しか無いなぁ…)。

 

もしこのコードをベースに色々弄る場合は、以下にご留意下さい。

  • ディスクリプタを弄る場合、同一VID/PIDのデバイスであればWindowsが初回接続時にキャッシュした値を使ってしまうようです。一旦デバイスマネージャから削除した上で再接続して下さい。
  • ビルドオプションにて、最適化レベルを「デバッグ(-Og)」にしています。-O2(デフォルト)等では、ほぼCubeMX生成直後のレベルでも不審死が相次ぎました…。