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

PIC32MX に AC97 コーデックを接続する実験をしています。
と言っても、現在使用している基板上に実装スペースがないので、実際にはまだ接続しておらず、信号をオシロで観察しながらプログラムを書いている状況です。 
当初 DMA や割り込みがうまく起動せず悩みましたが、それも解決し、うまく行きそうな感触が得られたので、今後新しい基板を作成して AC97 コーデックとつなげる予定です。
AC97 の「プライマリ・コーデック」との接続では、ビット・クロックは AC97 コーデック側からコントローラ側に供給し、SYNC パルスはコントローラ側から AC97 側に供給します。
マイコン側の SPI の動作でいえば、SPI の動作自体は「スレーブ・モード」で、SYNC パルス (フレーム・パルス) についてはマイコン側が「マスター・モード」として働くことになります。
以前 SH2A に AC97 コーデックを接続しましたが (→こちら)、SYNC パルスは外部回路で作成するか、SSIF をもうひとつ使って SYNC 信号を発生させる必要がありました。
PIC32MX では、SPI ひとつで AC97 コーデックとのインターフェースに必要な SYNC パルスを発生させることができます。

一般的な AC97 コントローラと AC97 コーデックとの接続は上の図のようになりますが、PIC32MX では次のように SPI の信号と対応させます。

PIC32MX
SPI
信号
方向
AC97プライマリ
コーデック
SSx SYNC
SCKx BIT_CLK
SDOx SDATA_OUT
Pyz RESET#
SDIx SDATA_IN

ここで、「x」は使用する SPI の番号「1」あるいは「2」であり、「Pyz」はコーデックのリセット信号を出力する汎用ポート (「PB3」 とか 「PA4」 など) を表現しています。
PIC32MX の SPI モジュールは、通常の動作モードのほかに「フレーム・モード」として動作させることができます。
これは複数個のデータからなる「フレーム」を単位として動作し、フレームの先頭位置を示す「フレーム同期パルス」を SSx 端子から入出力することができます。
「フレーム・マスター・モード」ではフレーム・パルスは出力となり、「フレーム・スレーブ・モード」ではフレーム・パルスは入力になります。
このモードは SPI 本体のマスター/スレーブ・モードとは独立に選べますから、

  • SPI 本体はスレーブ・モード (SCKx は入力)
  • フレーム・マスター・モード (SSx は出力)

とすれば AC97 プライマリ・コーデックとのインターフェース信号の方向が揃います。
このフレーム・パルスの幅は、1 ビット・クロック幅か、1 ワード幅かを選択できます。
AC97 規格では SYNC パルスの幅は 16 ビット・クロックと決められているので、SPI の転送モードを 16 ビットとし、フレーム・パルス幅を 1 ワードに選べばスペックに合致させることができます。
また、AC97 では 1 オーディオ・フレームは 256 ビットで構成されているので、SPI のフレーム長を 16 に選べば
16 [ビット/ワード] × 16 [ワード/フレーム] = 256 [ビット/フレーム]
となります。
そのほかに、SYNC/BIT_CLK/SDATA_OUT の各信号の間には下の図のような関係があります。

フレームの開始を示す SYNC パルスの立ち上がりから 1 ビット・クロック遅れて、新しいオーディオ・フレームの MSB が送信されます。 これは I2S での関係と同様ですが、SPI モジュールでは、モード設定により、このようなタイミングで動作させることができます。
具体的に、SpiChnConfigure() 関数で指定するパラメタの値を示すと下のようになります。

const uint32_t SPI_CONFIG_params =
  ( SPI_CONFIG_FSP_HIGH  // AC97 SYNC pulse = High
  | SPI_CONFIG_ENHBUF    // ENHanced BUFfer (FIFO)
  | SPI_CONFIG_MODE16    // 16 bit / word
  | SPI_CONFIG_FRMEN     // frame mode enable
  | SPI_CONFIG_FSP_WIDE  // frame pulse is 1 word wide
  | SPI_CONFIG_FRM_CNT16 // 16 word per frame
  | SPI_CONFIG_TBE_EMPTY // interrupt on Tx buf empty
  | SPI_CONFIG_RBF_FULL  // interrupt on Rx buf full
  );

これには割り込みイベントの指定も含まれています。
オーディオ・モードで使用するわけではないので、CONFIG2 パラメタを含む SpiChnConfigureEx() 関数を使う必要はありません。
CONFIG2 パラメタの中では、「SPI_CONFIG2_IGNTUR」を指定すると送信アンダーランを無視するようになりますが、送信アンダーランが発生する状況ではフレームが正しく同期できず、意味がありません。
サンプリング周波数 48 kHz のオーディオ・フレーム中で 16 ビット転送を 16 回行う必要があるので、そのレートは 48 [kHz] × 16 = 768 [kHz] となり、40 MHz CPU クロックでは約 52 クロックごとに 16 ビット転送 1 回を行う計算になり、プログラム転送では負担が大きくなり過ぎます。
さらには「コーデック」として入出力を同時に行う場合にはレートは 2 倍になります。
そういうわけで、実用的には SPI に対するデータ転送は DMA で行う必要があります。
SPI の FIFO バッファ・サイズは 16 ビット転送の場合に 8 ワードとなるので、それをフルに活かすために「バースト転送」のサイズ (PIC32MX の DMA モジュールの用語では「セル・サイズ」) を 16 バイトに選べば、1 オーディオ・フレーム中に 2 回の DMA 転送が行われることになります。