ディジタルオーディオ用 DAC をマイコンにつなぐ(2)

マイコンにディジタルオーディオ用 DAC をつなぐ場合、専用インターフェース・ハードウェアが存在するわけではなく、ソフトウェア的に実現しなければならない部分が出てきます。
割り込み応答時間は、一般には一定値ではなく、ある程度の時間幅で変動します。 それが、オーディオ出力のジッタにつながらないように注意しなければなりません。
まず、オーバーサンプリング・ディジタルフィルタを持つ DAC の場合、内部のディジタルフィルタを動作させるために、192 fs とか 256 fs などのマスタークロック (MCLK) を供給する必要があります。
サンプリング・レートの信号である、LRCK (Left Right ClocK) と MCLK の周波数比は DAC のスペック通りの整数値ぴったりである必要がありますが、位相関係は (安定であれば) 特に定められていないものが多いようです。
この MCLK と LRCK は、マイコンのカウンタ/タイマ・ハードウェアにより生成した、安定した信号として供給する必要があります。
ディジタル・データは LRCK をフレーミングおよび L/R を判別する信号として使用し、BCLK (Bit CLocK) で、シリアルデータ入力 SDAT (Serial DATa) をサンプリングして取り込みます。
DAC のデータシートには、これらの信号の関係として、下の図のようなタイミング・チャートが掲載されています。 (標準モード、16 ビットデータ、MSB first の場合)
この図は LRCK="H" つまり、L チャンネルのデータの場合について示してあります。 R チャンネルについても LRCK="L" となるだけで同様です。 また、MSB = b15、LSB = b0 として表示してあります。

BCLK の立ち上がりエッジが基準となって、データ入力 SDAT や LRCK の BCLK に対するセットアップ時間や、ホールド時間が規定されています。
例外はありますが、多くの場合、1 LRCK 周期中の BCLK 数は特定の値に強制されていません。
もちろん、16 ビット転送なら L/R それぞれ BCLK 16 クロック以上が必要なのは自明ですが、最大で 64 クロックといったような、ゆるい制限になっています。
LRCK のエッジの直前までに取り込まれた、直近の 16 ビット・シリアルデータが DAC 入力値として使われます。
マイコンの内蔵モジュールで、このような用途に使えるのは SPI モジュールです。(SPI モードが選択できるシリアル・モジュールを含む)
SPI をマスターモードで使い、LRCK のエッジで割り込みをかけて、SPI から 2 バイト出力すればクロックも 16 個出力されます。
ただし、割り込み応答時間は変動しますから、最も遅いタイミングになった場合でも、LRCK のエッジに引っかからないような余裕を持たせる必要があります。
したがって、LRCK = 32 BCLK は不可能で、たとえば LRCK = 40 BCLK のようにする必要があります。

上の図は、そのような使い方をした場合で、LRCK="H" の期間、BCLK 数はちょうど 16 個となります。
LRCK="H" の幅は 16 BCLK 以上あります。 割り込み応答時間のため、LRCK のエッジから遅れてシリアルデータが出力されています。 
また、割り込み応答時間の変動を吸収できるように、シリアルデータの最後のビットと LRCK のエッジの間には若干余裕があります。
DAC 出力レジスタが更新されるタイミングが LRCK から作り出されるタイプの DAC であれば、このような使い方でも、オーディオ出力にはジッタが出ません。
一方、出力タイミングが BCLK に左右されるタイプの DAC では、この方法ではオーディオ出力にジッタが乗る可能性があります。
たとえば、uPD6376 (NEC) では、データシートに

The analog outputs of the L.OUT and R.OUT pins are updated after the input of 4.5 clocks following data input

と明記してあり、LRCK のエッジの後、BCLK (uPD6376 では CLK という名称) が 4.5 サイクル到着した時点でアナログ出力がアップデートされます。
すなわち、BCLK がジッタを持つと、アナログ出力にジッタが乗ります。
そのような場合でもジッタが出ないようにするには、BCLK もハードウェアで発生し、SPI はスレーブモードで使う方法があります。
この場合、LRCK = 32 BCLK や LRCK = 48 BCLK のように、チャンネル当り SPI の 8 ビット転送2回分、あるいは3回分にきっちり合わせる必要があります。
また、タイマで作り出す LRCK と BCLK と SPI との同期を、初期化の時点できっちりと合わせる必要があります。
C プログラムだけでは無理で、アセンブラレベルで 1 サイクル単位でタイマと SPI をイネーブルするタイミングを調整する必要があります。