STM32F446RE 内蔵の SAI モジュールの AC97 モード (1)

 STM32F446RE などに内蔵されている SAI (Serial Audio Interface) モジュールの AC97 モードを使って、AC97 コーデックとの接続を試してみました。
 「AC97 リンク・コントローラ」に「AC97 プライマリ・コーデック」ひとつと「AC97 セカンダリ・コーデック」ひとつを接続する構成の図を、AC97 のスペックの資料に準じて示します。

 「AC97 リンク・コントローラ」と「AC97 コーデック」ひとつとは「AC リンク」と称する下に示す 5 本の信号線で接続されます。

  • SYNC
  • BIT_CLK
  • SDATA_OUT
  • RESET#
  • SDATA_IN

 コーデックの動作には 24.576 MHz のメイン・クロックが必要であり、通常、プライマリ・コーデックの水晶発振回路に 24.576 MHz の水晶振動子を接続して発振させます。
 AC リンク信号のタイミング基準となるのが「BIT_CLK」で、24.576 MHz メイン・クロックを 2 分周して得られた 12.288 MHz クロックをコーデック側から出力してコントローラ側に供給します。
 「SYNC」はフレーム・タイミングの基準となる信号で、コントローラ側から出力され、コーデック側に入力されます。
 「SDATA_OUT」はコントローラ側から出力され、コーデック側に入力される信号で、主にコーデックの DAC 入力へのディジタル・データとして使われます。
 「SDATA_IN」はコーデック側から出力され、コントローラ側に入力される信号で、主にコーデックの ADC 出力からのディジタル・データとして読み込まれます。
 「RESET#」はコーデックのハードウェア・リセットのための信号で、コントローラ側が出力、コーデック側が入力となります。
 AC リンク信号はリンク・コントローラ側から見れば、「BIT_CLK」と「SDATA_IN」のみが入力で、他の 3 つの信号は出力となっています。
 セカンダリ・コーデックの信号は「SDATA_IN」のみコーデックごとに独立してリンク・コントローラの SDATA_IN 信号に接続する必要があり、他の 4 本の信号はすべてのコーデックの同名の信号線に「パラって」接続します。
 ここで「BIT_CLK」信号はプライマリ・コーデックでは「出力」で、他のセカンダリ・コーデックでは「入力」となります。
 STM32F4 の SAI モジュールひとつを使って AC97 プライマリ・コーデックに接続する場合を、リファレンス・マニュアルに準じて図示すると次のようになります。

 SAI モジュールは、「ブロック A」、「ブロック B」と称するふたつの同等なブロックから構成されており、それぞれ送信専用あるいは受信専用のいずれかのモードで動作させることができます。
 また、「マスタ・モード」、「スレーブ・モード」のいずれかで動作させることができ、マスタ・モードでは

  • SAI1_FS_x
  • SAI1_SCK_x
  • SAI1_SD_x

の信号線がピンに割り当てられます。 ここで、信号名末尾の「x」は「A」ならブロック A、「B」ならブロック B を示します。
 スレーブ・モードでは「SAI1_SD_x」のみがピンに割り当てられ、他の信号はマスタ・モードに設定されている他のブロックの信号にパラレルに接続されます。
 ブロックの動作モードを

  • ブロック A = マスタ、送信
  • ブロック B = スレーブ、受信

という組み合わせにすると、「SAI1_FS_A」と「USART2_RX」とが同じ「PA3」ピンに割り付けられてしまうので、そのままでは USART2 が使用できなくなってしまいます。
そこで、ブロックの A/B をひっくり返して、

  • ブロック B = マスタ、送信
  • ブロック A = スレーブ、受信

としたのが上の図です。
 「RESET#」信号は SAI モジュールの信号としては用意されていませんが、コーデックの確実な動作のためには GPIO を利用するなどして別に用意する必要があります。
 上のふたつの図を比較すると分かりますが、SAI の AC97 モードでは「BIT_CLK」をリンク・コントローラである SAI 側から供給していることが分かります。
 AC97 r2.3 では、プライマリ・コーデックでも「BIT_CLK」が入力になるモードでの動作が規定されていますが、手持ちの AC97 コーデックは r2.2 以下のリビジョンで、 BIT_CLK 入力モードでは動作しないようです。
 外部クロック入力「I2S_CKIN」を分周なしで SAI モジュールのクロックとして使う場合、I2S_CKIN → SAI1_SCK_x の信号経路には論理ゲートやバッファのみが含まれると思われるので、伝達遅延が生じる以外には不都合は生じないと考えられます。
 50 MHz 帯域のオシロで実測してみたところ、遅延は約 8 ns ほどで安定していました。
 プライマリ・コーデックが発生する「BIT_CLK」を外部クロック入力「I2S_CKIN」に接続し、SAI が発生する「SAI1_SCK_B」は SAI 内部だけで使うようにしたのが次の図です。

 この構成では、コーデックが使う「BIT_CLK」と SAI が使う「SAI1_SCK_B」との間に約 8 ns の遅延があり、互いにその分だけセットアップ・タイム/ホールド・タイムのマージンを損なうことになりますが、実用上は誤動作などの問題ありませんでした。