PSoC5LP Prototyping Kit (5) --- SPDIF_Tx と DMA (4)

「ダブル・バッファ」は、その特性上、常にどちらかのバッファが「使用中」で、「空き」があるのはもう片側のバッファのみです。 オーディオ・サンプルを生産する側のソフトウェアから見れば、常にバッファ全体の半分の容量しか利用できません。
「ダブル」ではなく、全体を 3 個以上の整数個 (N) の領域に分割して、「マルチプル・バッファ」とすれば、「使用中」である 1 個のバッファの全体に占める割合は (1/N) に低下し、使用可能な「空き領域」の割合は (N-1)/N に増加することになります。
PSoC5LP では TD (Transaction Descriptor) が 128 個利用でき、ケチる必要もないので、今回のプロジェクトでは具体的には N = 16 として 16 個の TD を使うことにしました。
TD と DMA バッファの関係を下の図に示します。

DAC / SPDIF 出力 FIFO バッファを、それぞれバイト数が DMA_buf_bytes の N 個の DMA バッファに分割し、TD と対応させます。
先頭の DMA バッファに対応するのが TD[0] で、同様に最後の TD[N-1] まで DMA バッファに対応させます。
Next TD フィールドで次の TD とリンクし、TD[N-1] の Next TD フィールドは TD[0] を指すようにしてループ状の TD チェインとします。
DMA ハードウェアとしては、このような初期設定を行なってから起動すれば、あとはデータ転送に関してはソフトウェアの介入なく動作し続けることができます。
ただし、オーディオ・サンプルを生成するソフトウェア側と同期を取らなければなりませんから、各 TD の DMA 転送完了時に割り込みを発生させて、出力 FIFO バッファの読み出しインデクスの管理を行います。
その点に注目して書いたのが次の図です。

図の上側がアドレスの若い側、配列のインデクスの小さい側とします。
まず、オーディオ・サンプル生産側が FIFO に書き込む位置を示すインデクスを「wr_ix」とします。 DMA 側が FIFO からデータを読み出す位置を示すインデクスを「rd_ix」とします。
実際は DMA がハードウェアで自動的にデータを読み出しているので、「rd_ix」は DMA のためのパラメタとしては使われません。 あくまでも、ソフトウェア側が FIFO バッファの空きを知るための情報です。
一般的に、FIFO では、データ書き込み側は FIFO に空きがあるかどうか、データ読み込み側は FIFO 中にデータがあるか (FIFO が空でないか) どうかを知る必要があります。
しかし、DAC や SPDIF に連続的にデータを流している状態では、読み込み側での「データがない」という状態を検出できても役に立たないので、データ書き込み側での FIFO に空きがあるかどうかの判定が簡単になるような構成にします。
(FIFO バッファ長の modulo を考慮した上で) 常に (rd_ix >= wr_ix)、つまり読み出しインデクスの方が先行しているものとし、(rd_ix == wr_ix) は FIFO が一杯 (FIFO に空きがない) というお約束とします。
(rd_ix - wr_ix) が FIFO の空きエントリ数となります。
上の図で、現在 TD[k-1] の転送を実行中であるとすると、読み出しインデクスは「rd_ix (k-1)」と示してある位置にあり、空き領域は図の「empty」と示した範囲になります。
ここで、 TD[k-1] の転送が完了すると、転送完了割り込みが発生し、DMA 割り込みサービス・ルーチンが呼ばれます。 このとき、すでに DMA ハードウェアは TD[k] の転送 (の準備) にかかっています。
DMA 割り込みサービス・ルーチンでは、インデクス rd_ix を rd_ix (k) の位置に変更し、ソフトウェア側に TD[k-1] で使っていた DMA_buf_bytes 分の DMA バッファが解放されて書き込み可能になったことを知らせます。
次回は、PSoC Creator の DMA Wizard の話と、実際のプログラムについて触れます。