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

PSoC5LP の DMA コンポーネントでは、カスタマイザで設定可能なのは、DMA リクエスト・ハードウェア入力 (drq) を設けるかどうか、およびその信号の種類の選択、DMA 停止ハードウェア入力 (trq) を設けるかどうかの 2 つのオプションのハードウェア入力に関するものしかありません。
細かいソフトウェア的な設定については、PSoC Creator のメニュー・バーの「Tools」からアクセスできる「DMA Wizard」アプリケーションを使って DMA 初期設定プログラムの「断片」を作成することになります。
今回のプロジェクトのトップ・レベルの回路図を下に再掲します。

SPDIF_Tx コンポーネントインスタンス名は、「SPDIF_Tx0」、DMA コンポーネントインスタンス名は「DMA_spdif_tx0」としています。
DMA コンポーネントではオプションの「drq」入力を有効にして、信号タイプを「Level」にしています。
「固定ブロック」のコンポーネントの DMA 要求出力と接続する場合には信号タイプを「Derived」にしておけば、「レベル」または「エッジ」のいずれか適切な方を自動選択してくれます。
接続先が UDB コンポーネントで、DMA 要求信号が「FIFO not full」のようなステータス信号で与えられる場合には、「Level」を選択しておかないと正常に動作しません。
DMA コンポーネントを配置することにより、DMA 関係の API が作成されますが、実際のアプリケーションに合わせた TD の初期化などの細かい部分は含まれておらず、 DMA 初期設定プログラム部分は「DMA Wizard」を利用して (必要に応じて手を加えて) 作成します。
DMA Wizard を起動すると、まず、次のようなダイアログが現れます。

このダイアログで (もし複数あればそのうちのどれかの) プロジェクトを選び、 (もし複数あればそのうちのどれかの) DMA コンポーネントを選びます。
SPDIF_Tx コンポーネントで「マネージド DMA」モードを選んでいると、チャネル・ステータスのための DMA が自動で定義されるので、DMA の選択肢に定義した覚えのない「SPDIF_Tx0_Cst0_DMA」と「SPDIF_Tx0_Cst1_DMA」とが現れますが、そちらではなく、上の画面のように配置したコンポーネントである「DMA_spdif_tx0」の方を選びます。
Next >」ボタンを押して次のダイアログに進むと下のようになります。

この画面で、DMA チャネル・コンフィグに関する設定を行います。
メモリ (SRAM) からペリフェラルへの転送なので、「Source」は「SRAM」を、「Destination」は「SPDIF_Tx0」をドロップダウン・リストの中から選びます。
DMA のバースト長は、ソース/デスティネーションの選択により適切な値が自動的に選ばれます。
さらに、「Number of TDs」で使用する TD (Transction Descriptor) の数を指定し、「Loop」ラジオ・ボタンで TD チェインをループさせることを指定します。
ここでは、簡単のために TD は 2 個のみ指定しています。
Next >」ボタンを押して次のダイアログに進むと下のようにセル状の入力画面となります。

使用する TD ひとつにつき 1 行が対応しています。
前の画面で TD 数 2 を指定しているので 2 行ですが、16 を指定すれば 16 行並ぶことになります。
前の画面までの指定で自動的に値が埋められるカラムもありますが、情報がないメモリ関係のパラメタなどは空欄で現れますからそれを埋めます。
上の画面は「Enable nrq」にチェックを入れ、「Length」を 64 とし、「Source」を「dac_fifo」としたものです。 本当は TD0 と TD1 とで「Source」の値を変える必要があるのですが、それは C ソース・コードをジェネレートした後に手で変更を加えるものとします。
Next >」ボタンを押すと C ソースがジェネレートされ、下のように表示されます。

ソースは「セレクト」された状態になっていますので、「Copy to Clipboard」ボタンを押すとクリップボードにコピーされ、エディタでペーストすることができます。
ジェネレートされた C ソース・コードは次のようになります。

/* Variable declarations for DMA_spdif_tx0 */
/* Move these variable declarations to the top of the function */
uint8 DMA_spdif_tx0_Chan;
uint8 DMA_spdif_tx0_TD[2];

/* DMA Configuration for DMA_spdif_tx0 */
#define DMA_spdif_tx0_BYTES_PER_BURST 1
#define DMA_spdif_tx0_REQUEST_PER_BURST 1
#define DMA_spdif_tx0_SRC_BASE (CYDEV_SRAM_BASE)
#define DMA_spdif_tx0_DST_BASE (CYDEV_PERIPH_BASE)

DMA_spdif_tx0_Chan = DMA_spdif_tx0_DmaInitialize(DMA_spdif_tx0_BYTES_PER_BURST, DMA_spdif_tx0_REQUEST_PER_BURST, 
    HI16(DMA_spdif_tx0_SRC_BASE), HI16(DMA_spdif_tx0_DST_BASE));

DMA_spdif_tx0_TD[0] = CyDmaTdAllocate();
DMA_spdif_tx0_TD[1] = CyDmaTdAllocate();

CyDmaTdSetConfiguration(DMA_spdif_tx0_TD[0], 64, DMA_spdif_tx0_TD[1], DMA_spdif_tx0__TD_TERMOUT_EN | TD_INC_SRC_ADR);
CyDmaTdSetConfiguration(DMA_spdif_tx0_TD[1], 64, DMA_spdif_tx0_TD[0], DMA_spdif_tx0__TD_TERMOUT_EN | TD_INC_SRC_ADR);

CyDmaTdSetAddress(DMA_spdif_tx0_TD[0], LO16((uint32)dac_fifo), LO16((uint32)SPDIF_Tx0_TX_FIFO_0_PTR));
CyDmaTdSetAddress(DMA_spdif_tx0_TD[1], LO16((uint32)dac_fifo), LO16((uint32)SPDIF_Tx0_TX_FIFO_0_PTR));

CyDmaChSetInitialTd(DMA_spdif_tx0_Chan, DMA_spdif_tx0_TD[0]);

CyDmaChEnable(DMA_spdif_tx0_Chan, 1);

これは「断片」に過ぎないので、main() 関数の中に埋め込むか、あるいは形を整えて DMA 初期設定関数としてまとめるかします。
次回は、このコードに手を加えた実際のプログラムを示します。