

I2S信号の量子化ビット数をSPLDで判定する
GreenPAK を使って I2S 信号の量子化ビット数を判定する回路の検討
現在私は AK4493SEQ を用いた USB-DAC の製作を進めています。そこで市販品のように LCD にサンプリング周波数や量子化ビット数を表示させたかったのですが、多くの自作派が使う USB-DDC の Combo384 では、サンプリング周波数は判定できても量子化ビット数までは判定できません。
そこで今回は、DDC から出力される I2S 信号をもとに量子化ビット数を判定する方法を検討しました。
動機#
量子化ビット数の判定方法としては、ざっくり次の 2 つが考えられます。
- マイコンで判定する方法 ↗
- ロジック回路で判定する方法
マイコンで判定している前例は見つかったのですが、私が今回使うのは STM32F446RE で、既存コードの流用都合もあって Arduino ベースで書く予定でした。ピン割り込みなどを駆使して I2S を追いかけるのは、速度的にも実装難易度的にもかなり厳しそうです。
その一方で、I2S の構造自体は比較的単純です。ロジック回路の組み合わせなら高いサンプリング周波数にも追従しやすく、結果を 2 進数で出してやればマイコン側はかなり楽になります。ただし、ロジック IC を何個も並べると大型化しやすいのが悩みどころでした。
そこで人生初の SPLD として、GreenPAK を使ってみることにしました。
GreenPAK入門編#
今回の検証には SLG46826V-DIP を使い、実機組み込みには SLG46826G を使う予定です。名前が似ていますが、この 2 つは単にパッケージ違いではなく、ピン配置も異なるので注意が必要です。以下の内容は SLG46826V-DIP 前提です。
製作にあたっては Lang-ship の GreenPAK 記事一覧 ↗ をかなり参考にしました。ありがとうございました。
GreenPAK への書き込みには本来 SLG4DVKDIP のような専用書き込み器を使いますが、当時はどこも在庫がありませんでした。そこで Renesas の Arduino 書き込み例 ↗ を参照しつつ、Arduino から書き込むことにしました。
記事執筆時点ではドキュメント中の Arduino スケッチへのリンクが切れていたため、代わりに Renesas の検索ページ ↗ から AN-CM-255.GP を辿る構成になっていました。
基本的な流れは次の通りです。
- GreenPAK Designer で設計する
- NVM を Hex 形式でエクスポートする
- VS Code などで行頭 9 文字と末尾 2 文字を置換する
- Arduino スケッチに貼り付けて書き込み用データにする
- シリアル通信で操作して SPLD に書き込む
I2S信号の構造と、本記事での用語定義#
I2S は Inter-IC Sound の略で、IC 間で音声データを伝送するための通信規格です。デジタルオーディオ機器ではかなり一般的で、ここでは LRCLK DATA BCLK MCLK の 4 本線で扱う前提で話を進めます。
まずは、ステレオ・96kHz・24bit の I2S 波形を例に見てみます。
正式な規格書で使う用語とは少し違いますが、以降は次の図の呼び方で説明します。
DATA の 0 と 1 は観測タイミングによって変わるため、数フレーム分を重ねてデータ区間の長さを見やすくしています。
ここで注目したいのは、L/R の各フレームに対して BCLK が常に 32 クロック分用意されていることです。つまり、伝送する量子化ビット数に関わらず、1 フレーム長は 32bit 固定です。
そのため、量子化ビット数が 32bit 未満のときは後ろにパディングが発生します。
- 16bit ならデータ区間 16bit、パディング区間 16bit
- 24bit ならデータ区間 24bit、パディング区間 8bit
- 32bit ならパディングなし
実際の波形を見ると、その違いがよく分かります。
データ区間の長さそのものを求めるのは大変ですが、パディング区間は常に DATA=0 です。そこで、パディング区間の長さを判定できれば量子化ビット数を逆算できます。
SPLDでパディング区間長を判定する#
方法1#
最初に試したのは、LRCLK=1 かつ DATA=0 の間だけ BCLK を数える方法でした。要するに、Rch 側のパディング区間だけを抜き出して、その長さで 16bit / 24bit / 32bit を見分けようという考え方です。
データ区間中にも一時的に DATA=0 になる瞬間はあるため、DATA=1 が現れたらカウンタをリセットするようにして、純粋にパディング区間だけを数える構成にしました。
GreenPAK 上のシミュレーションではうまく見えたのですが、実機では動作が不安定でした。原因は、たとえば 24bit 入力でもデータ区間の終端が 00000000 になった場合、その 0 とパディングが連結して見えてしまうことです。結果として 16bit 判定になるケースが出てしまいました。
つまりこの方法を現実で成立させるには、数百フレームぶんの DATA を保持して論理和を取り、「データ区間は 1、パディング区間は 0」という理想化された状態に近づける必要があります。今回の SPLD ではそこまでの記憶資源を持てないので、別案を考えることにしました。
方法2#
方法1の失敗から逆に見えてきたのは、全データ区間を覚える必要はなく、16bit と 24bit の境界付近だけ監視すれば十分だということです。
ここでいう「監視」は、対象 bit が 0 なら無視し、1 なら自己保持回路で一定時間結果を保持する、という意味です。入力が 16bit なら両方の自己保持回路は動かず、24bit なら 1 つだけ動作し、32bit なら 2 つとも動作します。
各部の役割は次の通りです。
-
監視タイミング信号生成 18bit 目と 26bit 目でパルスを発生させます。
LRCLKとBCLKの論理積を使って Rch 区間だけのクロックを抜き出し、これをカウンタで数えます。カウントが流れ続けてズレないよう、LRCLKをリセット信号として使っています。 -
監視結果 監視タイミングと
DATAの論理積を取るだけです。監視タイミングにDATA=1なら 1 を出力します。 -
自己保持回路 監視結果が 1 だった場合、その結果を一定時間保持します。
-
リセット信号生成 自己保持回路をいつクリアするかを決める部分です。
LRCLKを1/255分周器 2 段に通しているので、およそ 65,000 フレームの間、判定結果を保持できます。44.1kHz 時でおよそ 1.5 秒ほどです。 -
再生/停止判定 16bit 入力時は監視結果が両方とも Low になりますが、これは「何も再生していない」場合とも区別がつきません。そのため、再生停止を見分けるための 3 つ目の自己保持回路を追加しています。停止直後に 32bit 表示が 16bit 表示へ誤って落ちるのを避けるため、こちらの信号が先にマイコンへ届くように遅延も入れています。
この方式で実機検証したところ、狙い通り正常に動作しました。そこで本番機でもこの方法を採用する予定です。
余談ですが、SPLD をマイコンへ直結すると SPLD 側もマイコン側も壊れる現象が出ました。信号レベルは揃っているはずなのに、SPLD は NVM を焼き直すまで復帰せず、マイコン側は入力ピンの一部が 3.3V を出し続けるようになってしまいました。間に適当な抵抗を入れたら再発しなくなったのですが、原因はまだ不明です。
設計データ頒布#
今回紹介した方法1・方法2 の両方について、GreenPAK の設計データを公開しています。
- 方法1:
Bitrate_detect_DIP.gp6 - 方法2:
Bitrate_detect_DIP2.gp6
方法1はシミュレーション上でしか正常動作しません。どちらも、見たい場所にプローブを置いて DATA 入力のデューティー比を変えながらシミュレーションできます。
- 50% で 16bit 相当
- 75% で 24bit 相当
- 100% で 32bit 相当
まとめ#
今回は SPLD を使って、I2S 信号の量子化ビット数を判定する方法を検討しました。
自作 DAC で量子化ビット数を LCD などへ表示するのはハードルが高めですが、この方法なら 300 円以下の SPLD を DDC とマイコンの間に挟むだけで、市販 DAC のようなインターフェースにかなり近づけます。
DAC を製作する機会があれば、参考になればうれしいです。