新年明けましておめでとうございます。
2022年もド素人電子工作アカウントのAUDIYをよろしくお願いいたします。
今回から前回のシミュレーション結果をもとに、いよいよFPGAにリアルタイムPCM-DSDコンバータを実装していきたいと思います。
ΔΣ変調のブロック図
さて、前回シミュレーションしたPCM-DSD変換ですが、
これをリアルタイム実装するにはΔΣ変調をFPGA上に実装する必要があります。
ΔΣ変調のブロック図としては、個人的に下記ブログが最も理解しやすいと感じました。
積分器のブロック図含めて描かれています。
今回はこれをFPGAに実装するためにVerilogコードにしましたので解説していきます。
I2S-パラレルPCM変換
これは今回のリアルタイムDSDコンバータを作るモチベーションとなったものですが、Verilogコードそのものの公開は初めてと思います。
HDLを書いたことの無い方のために言葉で説明しますと
- BCLKの立ち上がりエッジに合わせてデータを64bit分(Lch: 32bit、Rch: 32bit)ストック&LRCKを1BCLK分遅延させる
- 遅延させたLRCKの立ち下がりエッジに合わせて64bitを上位32bit(Lch)、下位32bit(Rch)に分離して出力
- RST_I信号がLowとなった際には出力と内部の保存データを全て0にする
という機能を実現しています。
これによりLRCKをワードクロックとしています。
微分器
ΔΣ変調の「Δ」に相当する部分です。
デジタルにおける微分は「入力値から1サンプル前の微分値を引き算する」ことによって実現していますが、今回は上記のブロック図に則り引き算のみを担当します。
1サンプル前の数値は、後ほど紹介するDSM_MAXIMIZER.vが担当します。
積分器
ΔΣ変調の「Σ」に相当する部分です。
微分器の反対なので「入力値と1サンプル前の積分値を足し算する」ものです。
ただ足し算だけ繰り返すといずれオーバーフローしますので、足し合わせる計算結果は1ビット→シフトします。
量子化器
積分した結果を1ビット信号として出力します。
積分した結果が正であれば1、負であれば0を出力すれば良いのですが、
上記のコードの通り最上位ビットを反転すれば良いです。
なぜかというと、符号付き整数においては最上位ビットが符号ビットであり、
0: 正の整数
1: 負の整数
であるためです。
出力したい結果は
正の整数なら1
負の整数なら0
なので、0→1、1→0つまり最上位ビットのNOT演算で実現できます。
遅延+振幅の最大化
量子化された結果を微分器へフィードバックするためのモジュールです。
ここで微分のために1BCLK分の遅延を加えています。
量子化された結果は1bitだと1か0となり、そのままでは入力と計算しても正しく微分できないので、これをPCM信号の最大振幅とします。(ブロック図上でよく「DAC」と表記されている部分です)
配置配線
筆者はQuartusで開発していますので、ブロック図を描いて機能を実現します。
これを論理合成すると下のような回路図になりました。
ひと通り見たところ間違いはなさそうですが、どうでしょうか?
ブロック図は下記リンクのVerilogコードに変換済ですので、VivadoやDiamondをお使いの方でも合成・配置配線できるかと思います。(Intel固有IPも使っていません。)
使って遊んでくれると嬉しいです。