PIC32MX220F032B (7) -- AC97 コーデックを接続する (4)

AC97 コーデック (Realtek (旧Avance Logic) 製 ALC650) を実装し、AD 入力、DA 出力ともに正常に行えることを確認しました。
しかし、DAC 側には HPF (ローカット・フィルタ) が入っていて、DC が出力できないという残念な事実も判明しました。
ALC650 には 20 ビット分解能の DAC が 6 個内蔵されているので、多 ch 出力の CV 発生器などの応用も考えていたのですが、その場合は直流分を出せないと意味がありません。
ADC のディジタル出力は DC 出力可能で、CD 入力については CD-GND 入力との間で差動入力を形成しているので、アナログ入力側も確実に DC を入力できます。
ALC650 を実装した基板の写真を下に示します。

スペースがなくて、QPF 変換基板の一部が LPC1114 に覆いかぶさる位置にしか実装できませんでした。
ALC650 のリセット端子をドライブする出力ポートは特に割り当てず、リセット端子は PIC32MX の MCLR ピンに直結しました。
PIC32UBL.exe アプリケーションの「Run Application」ボタンを押して PIC32MX に書き込んだプログラムを実行させる場合、LPC1114 は PIC32MX に対してリセット・パルスを出力するので、ALC650 にも同時にリセットがかかります。
ALC650 の SDATA_IN 出力をオシロで観測した写真を下に示します。

上のトレース (Ch1) が SYNC パルスで、下のトレース (Ch2) が SDATA_IN 出力です。
SYNC パルスの前の方の位置に、少し見えにくいですが SDATA_IN 出力のパルスが 2 本見えています。
ここはスロット 0 の「タグ」の部分で、最初の「1」が CODEC READY を表すビットで、2 番目の「1」は 2 ビット幅でスロット 3 と 4 の PCM_in_L / PCM_in_R 出力が有効であることを示しています。
フレームの前 1/4 ぐらいの位置に見えるパルスがスロット 3/4 の PCM_in_L/R データです。
ALC650 は 5.1 ch 出力なので DAC は 6 本ありますが、AD 入力側に関しては AC97 標準の 2 ch 分しかなく、データがあるのはスロット 3/4 だけで、他のスロットの位置には「0」が詰まっています。
これは AC97 コーデック側からの出力なので、AC97 コーデックが正常に動作を始めれば、コントローラ (PIC32MX) 側が何もしなくても AD データ自体は出力されてきます。
ただし、「録音側」の入力セレクタや録音ゲイン、ミュート解除などを設定してやらなければ、目的の入力に対するデータは得られません。
ALC650 の SDATA_OUT 出力をオシロで観測した写真を下に示します。

これは 5.1 ch DAC 出力および S/PDIF の 2 ch 出力の計 8 ch にデータを出力しています。
DAC 出力はスロット 3/4/6/7/8/9、S/PDIF 出力はスロット 10/11 です。
スロット 5 と 12 にはデータを出力せず、空いています。
AC97 コーデックとコントローラとの間ではスロット 1 と 2 を使って AC97 コーデック内部レジスタへのアクセスを行います。
AC97 内部には最大 64 個の 16 ビット幅のレジスタを持つことができ、スロット 1 でレジスタ・アドレスと読み込みか書き込みかを指定し、スロット 2 で対象のデータを送ります。
以前、SH2A と AC97 コーデックを接続する記事で示したのと同様の、スロットの区切りとワードの区切りを示す図を下に示します。
今回は 16 ビット・ワードでの転送なので、16 ビットごとに青い線の区切りを入れてあります。

これを見ると、タグ/レジスタ・アドレス/レジスタ・データはフレームの最初の 4 つの 16 ビット・ワードの中におさまっていることが分かります。
DAC のデータは 48 kHz のレートで定常的に更新されますが、レジスタ・アクセスについては頻度が少なく、たまにしか更新されません。
そこで、レジスタ・アクセスの必要が生じたら、

  1. メイン・ルーチン側でレジスタ・アドレス/データ/タグを含む先頭 8 バイトのデータを 32 ビット・グローバル変数 2 個にセットする (アトミックな操作)
  2. DMA 完了割り込みハンドラで次のサンプルのデータを準備するときに合成する
  3. 割り込みハンドラ内でグローバル変数の内容をクリアする

ことにしました。
2. と 3. はグローバル変数の内容にかかわらず、毎回行われます。
32 ビット変数 2 個なので、手間は大したことはありません。
レジスタ・アクセスの頻度が少なく、更新と次の更新との間に何サンプル分もの時間が空く場合には、メイン側では 1. のグローバル変数へのセットをするだけですみます。
初期設定などでレジスタ・アクセスの量が多く、アクセス完了をチェックする必要がある場合には、1. で「1」に設定したビットが 3. で「0」にクリアされるまでループして待ちます。
具体的には、レジスタ・アクセスのためにタグ・ワードに 0x6000 を設定するので、これが 0x0000 になるのを監視します。