Determination of the quantization bit depth of an I2S signal by using SPLD.

動機

現在私はAK4493SEQを用いたUSB-DACの製作を行っています。そこで市販品のようにLCDにサンプリング周波数や量子化ビット数を表示させたいのですが、多くの自作派が用いるUSB-DDC(Combo384)ではサンプリング周波数の判定はできますが、量子化ビット数は判定できません。

そこでDDCから出力されるI2S信号を基に量子化ビット数を判定する手法を検討します。

こんな感じをイメージしてます

機能の実現手法

量子化ビット数を判定する機能を搭載した自作DACの前例は殆ど無いですが、以下の2つが考えられます。

  • マイコンで判定する方法

こちらは私が唯一インターネット上で前例を見つけたものです。

I2Sインターフェースを備えたマイコンで判定するみたいですが、私が真似をするにはハードルが高すぎます。(というか電子うさぎさんは完成度が毎度高すぎる…)

そして今回私が使用するマイコンはSTM32F446REで、前作のコードを流用するためArduino語で書く予定です。そのため、単純にピン割り込みなどを駆使して行うのもマイコンの速度的に厳しいと思います。

  • ロジック回路判定する方法

幸いにもI2S信号は単純な構造をしており、ロジック回路の組み合わせで量子化ビット数の判定は簡単に行えそうです。ロジック回路なら高いサンプリング周波数でも追いつけますし、2進数で出力すればマイコンで簡単に読み取れます。

とはいえ、今回のDAC製作の目標は小型化であるため、ロジックICの組み合わせでは巨大化は避けられません。

そこで人生初のSPLDに手を出すことにしました。いろいろ探してみると、GreenPAKという回路ブロックを繋げていくだけで、コードを書かずに動作するSPLDを発見しました。今回はこれを使って判定回路を作っていきます。

GreenPAK入門編

今回GreenPAK対応のSLG46826V-DIPを用いて動作検証を行い、実機の組み込みにはSLG46826Gを使用する予定です。この2つはパッケージが違うだけかと思っていたら、ピン配置が違っていたので注意が必要です。以降に示すものは「SLG46826V-DIP」のものですのでご注意ください。

製作に当たっては「Lang-ship」さんのブログを参考にさせて頂きました。ありがとうございます。

GreenPAK対応のSPLDへの書き込みは通常「SLG4DVKDIP」などの専用書き込み器を用いますが、どこの通販でも在庫がありませんでした。

そこでRenesas公式のドキュメントを参照しながら、Arduinoを用いて書き込みを行います。

このドキュメント内で使用しているArduinoスケッチのリンクが切れているため、以下に貼っておきます。(AN-CM-255.GPをクリックするとDLできます)

基本的には

  1. GreenPAKで設計
  2. NVMをHex形式でエクスポート
  3. VScode等で行頭9文字と末尾2文字を置換
  4. Arduinoスケッチにコピペして書き込み
  5. シリアル通信で操作してSPLDに書き込み

の流れで書き込みできます。置換しなくてもできる方法があるみたいですが、そんなに書き換えないので、そのままにしておきました。

I2S信号の構造 & 本記事での用語定義

I2SはInter-IC Soundの略でIC間で音声データを伝送するための通信規格です。大抵のデジタルオーディオ機器で採用されているメジャーな規格です。「LRCLK」「DATA」「BCLK」「MCLK」の4本線で通信します。

ここではステレオ、サンプリング周波数96kHz、量子化ビット数24bitの場合の実際のI2S波形を例にして解説します。

図の01011…みたいのはテキトーに書きました。本来は24桁(=24bit)です。
(画像をクリックで拡大)

まず右チャンネル(Rch), 左チャンネル(Lch)のそれぞれの波形を一秒間に96,000回の速度で区切り、その瞬間の音の大きさを2の24乗段階(=約1700万段階)で数値化し24桁の2進数の信号列としてDATA線で伝送します。

この信号列のRch, Lchを受け取り側が判別するためにLRCLKがHighの区間はRch、Lowの区間はLchといった具合で判別します。つまり1/96,000秒間隔でRch,Lchの瞬間的な音の大きさを伝送しているため、LRCLKはサンプリング周波数の96kHzに一致します。

またDATAが連続して0や1だった場合に、受け取り側が何個0や1が来たか分からなくなってしまうので、BCLKが立ち上がったタイミングのDATAを読んで判定しています。例えばDATAがずっと0でその間にBCLKが4パルス来たら、送りたかったデータは「0000」と分かるわけです。

もう一つの信号線「MCLK」ですが、これは他の3信号よりかなり周波数が高く、各種動作の基準に使われているらしいですが、今回は使いません。

ここで、今後の説明をスムーズにするために、勝手に用語定義をします。正式な用語はI2Sの規格書をご覧ください。

以降はこの図の用語を用いて説明していきます。

DATAの0と1は観測する瞬間によって違いますので、数フレーム分を重ねることによって、データ区間の長さを分かりやすくしています。

今回、I2S信号から量子化ビット数を判別する方法は、以下に示す各量子化ビット数毎の波形を見ればお分かりいただけると思います。

44.1kHz / 16bit
96kHz / 24bit
192kHz / 32bit

先ほども書いた通り、LRCLKはサンプリング周波数に一致するのですが、上の3つの例ではLRCLKが一周期分になるように時間軸を伸縮させています。

注目すべき点は3つの例全てにおいて、L・R各フレームでBCLKが32クロック分だという点です。つまり伝送する量子化ビット数に関わらず、DATAのフレーム長が32bit分用意されているということです。

そのため伝送する量子化ビット数が32bit未満の場合はパディングが発生します。

  • 量子化ビット数が16bitならデータ区間が16bit、パディング区間が16bit(32-16=16)
  • 量子化ビット数が24bitならデータ区間が24bit、パディング区間が8bit(32-24=8)

といった具合になります。(もちろん量子化ビット数32bitではパディングは発生しません。)

DATAは時々刻々と変化するので、データ区間の長さを求めるのは難しいです。よって、常にDATA=0であるパディング区間の長さを基に量子化ビット数を判別します。以降はこのパディング区間の長さをSPLDで判別する方法を模索していきます。

SPLDでパディング区間長を判別する

方法①

まず最初に試したのはLRCLK=1かつDATA=0におけるBCLKのクロック数をカウントするという方法でした。LRCLK=1というのは単に判定にRchのDATAを使っているというだけです。

つまりパディング区間のBCLKを数えてパディング区間長を判別するという方法です。また、データ区間でもDATAが0になる瞬間は普通にあるので、DATA=1になったらカウントを一度リセットする機能も付けました。これによって純粋にパディング区間のみ数えられます。

実際には結果をフレーム間で保持する機能なども付いています
設計データは記事の最後の方でDLできます。

GreenPAK上でのシミュレーションではデータ区間のDATAがすべて1だと仮定して、デューティー比を変えることで量子化ビット数を変えてるように見せかけて行いました。

シミュレーションではうまく動作したので、実機で検証したところ動作が不安定でした。

よくよく考えてみると、仮に入力が24bitでパディング区間が8bitなのに、データ区間の終わりが「00000000」だった場合、パディング区間とこの0が連結して、16bit判定になってしまいます。

シミュレーションではDATAがすべて1だと仮定して行っていたので、現実でこの方式を実現するには数百フレームのDATAを保存して、それらの論理和(OR)をとる必要があります。つまりデータ区間は全て1、パディング区間は全て0になるような入力を用いる必要があったのです。

もちろん今回のSPLDにはそれほどのデータは記憶できないので、別の方法を考えます。

方法②

実は先ほどの失敗にもヒントはありました。DATAはその瞬間によって内容が変わってしまうので、数百フレームにわたって監視しなければいけません。そして、先ほどの方式では全データ区間を記憶しなければなりませんでしたが、実際に量子化ビット数を判別するには、先頭から16bit、24bit目の境界付近のみ監視していれば十分です。

「監視」というのは監視対象bitが0ならば無視、1ならば自己保持回路を用いて一定期間結果を保持し続けるというものです。入力が16bitならば自己保持回路は2つとも動作せず、24bitなら1つだけ動作、32bitならば2つとも動作するという結果になります。

以下に作成したブロック図を示します。

各部の説明です。

  • 監視タイミング信号生成

この部分では18bit目と、26bit目でパルスを発生させることができます。

まず、LRCLKとBCLKの論理積をとることによってRch区間のみのBCLKを取り出せます。このパルスをReset counterで数えることで監視タイミングでパルスを出せます。このままだと18パルスを数え続けてずれていってしまうので、LRCLKをリセット信号として入力しています。

  • 監視結果

この部分は先ほどの監視タイミングとDATAの論理積をとっているだけです。つまり監視タイミングでDATA=1ならば1を出力します。

  • 自己保持回路

この部分では先ほどの監視結果が1だった場合、一定期間値を保持し続けます。

  • リセット信号生成

これは自己保持回路のリセット信号を生成する部分です。LRCLKを1/255分周器2段に通してますので、およそ65,000フレームの間自己保持回路は結果を保持し続けます。

この長さはサンプリング周波数が最低の44.1kHzの時で1.5秒間程度です。

  • 再生/停止判定

今回の方式で入力が16bitの時は自己保持回路の出力が2つともLowになりますが、これは再生をしていない時(DATAを入力していない時)も同じ結果となってしまうので、これらを区別するために、3つ目の自己保持回路を設けました。

「32bit音源で再生を停止をしたらLCDの表示が16bitになった」といった現象を防ぐために、再生停止判定の信号の方が先にマイコンに到達しなければならないので、監視結果の自己保持回路の後ろにDelayを入れました。(まぁ別にマイコンのプログラムでも実現できますが。)

この方法②で実機検証をしたところ正常に動作したので、本番機でもこの方式を採用しようと思います。

実機検証の図(訳あってVOLのところにbit表示してます。)

それと、あまり関係ない話になりますが、SPLDをマイコンに直結して動作させるとSPLDとマイコンが故障しました。信号レベルは揃えているのですが、SPLDが完全に動かなくなり、NVMを焼き直すと復活しました。マイコン側については、SPLDからの入力ピンの一部がプルアップしてるわけでもないのに、3.3Vを出し続けるようになってしまいました。ピンの場所を変えても同じ症状です。

SPLDとマイコンの間に適当な抵抗を挟んだら壊れなくなりました。

SPLDはプッシュプル出力、マイコンはプルアップなしの高インピーダンス入力で、別に大電流が流れてなさそうですが、原因は謎です。わかる方いらっしゃいましたら是非コメントお願いします。

設計データ頒布

今回紹介した方法①、②の両方についてGreenPAK設計データを公開します。

方法①のファイル名は「Bitrate_detect_DIP.gp6」、方法②が「Bitrate_detect_DIP2.gp6」です。

方法①はシミュレーション上でしか正常動作しません。

①・②のシミュレーションの方法は同じで、見たいところにプローブを設定して、DATA入力のデューティー比を変化させながらシミュレーションを回します。

デューティー比50%で16bit相当、75%で24bit相当、100%で32bit相当です。

データの利用方法については、当サイトの利用規約に基づきます。個人での利用や引用はご自由にしてもらって構いません。

引用をする場合や改変したものを公開する場合は、必ず本ページを明記してください(連絡不要)。商用利用の場合はTwitter(X)のDMからご連絡ください。

まとめ

今回はSPLDを用いてI2S信号の量子化ビット数を判別する手法について取り上げました。

これまでは自作DACで量子化ビット数をLCDなどに表示するにはかなりハードルが高かったですが、今回の手法によって300円以下のSPLDをDDCとマイコンの間に挟むだけで、市販のDACのようなインターフェースが実現可能になりました。

DACを製作する機会がありましたら是非ともご参考にしてください。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です