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

いつものように、ROHM のディジタルオーディオ用 16 ビット・シリアル DAC BU9480F を CQ-FRK-MCF52233 基板につなぎました。
回路図を下に示します。

MCF52233 に内蔵されている SPI 機能は QSPI モジュール1個だけなので、DAC の「SDAT」と「BCLK」は、選択の余地なく、それぞれ「QSPI_Dout」と「QSPI_CLK」につなぎます。
DAC の「LRCK」は DMA Timer0 出力の「DTOUT0」につなぎます。
この「LRCK」発生については 2008 年 8 月 18 日の記事「のこぎり波ピーピー」 (→こちら) にプログラムが示してあります。
QSPI の端子に関しては、EzPort モードと共用されていますから、EzPort モードでフラッシュ書き込みを行う際には DAC にもシリアルクロックおよびデータが供給されてしまいます。
この時、「LRCK」入力がフローティング状態だと、DAC に不正な値が入力されて、不快な異音を生じることがあります。
これは、同様にフラッシュ書き込み用 SPI を共用する AVR マイコンの場合にすでに経験していて、「LRCK」をプルアップ / プルダウンして、フラッシュ書き込み中に変化しないようにすれば避けられることが分かっています。
そのため、SilentC / GDB スタブのどちらで起動するかを切り換える JP2 がつながっている「DTOUT0」を「LRCK」発生に使っています。
JP2 オープンでは 10 kΩ でプルアップ、JP2 ショートでは 2.2 kΩ でプルダウンされるので、マイコンがリセット状態でもフローティングになることはなく、外部にプルアップ / プルダウン抵抗を設ける必要はありません。
QSPI の初期化部は次のリストのようになります。

void mcf_spi_init( void )
{
// enable QSPI_CLK, QSPI_Dout
  MCF_GPIO_PQSPAR = (0xFFCC & MCF_GPIO_PQSPAR) | 0x0011;
// master, no Dout Hi-Z, 16 bit, pos clk, change on rize, 60 MHz / (2*10) = 3 MHz clk
  MCF_QSPI_QMR   = 0x800A; 
  MCF_QSPI_QDLYR = 0x0000;  // use standard delay
  MCF_QSPI_QWR   = 0x0000;  // queue size =1 (ENDQP = NEWQP = 0)
  MCF_QSPI_QIR   = 0x0000;  // disable interrupts
  MCF_QSPI_QAR   = 0x20;    // select command RAM (QCR0)
  MCF_QSPI_QDR   = 0x4000;  // BITSE = 1 (select QMR[BITS])
} // void mcf_spi_init()

「QSPI」は「Queued Serial Peripheral Interface」の略で、データシートを良く読む前には、普通の SPI に受信 / 送信 FIFO を付けたもの程度に考えていたのですが、実際には、もう少し複雑なものでした。
ソフトウェアで「キュー」を実現する場合と同様に、一定量のバッファ RAM およびキューの先頭の位置と末尾の位置を示すポインタで管理するようになっています。
キューの準備が完了した後、転送開始のフラグを上げると、あとはハードウェアが自動的に転送を行うようになっています。
ハードウェアの転送が終了しても、RAM の内容はそのまま残りますので、同じフォーマットで何回も転送する場合には、データなどの異なる部分だけを書き換えて再実行すれば良く、毎回すべての設定を繰り返す必要はありません。
ここでは、16 ビットの転送を1回だけ、つまり、キューの長さ = 1 という設定で使います。
サンプリング周期で、実際に DAC のデータを送り出す部分のコードは次のようになります。

void __attribute__((interrupt_handler)) 
dtim0_handler() {
  MCF_DTIM0_DTER &= 0x03; // clear REF, CAP flag
  if (lrck ) { // left channel timing
    short int w;
    ....
//    w に出力データが入っているものとします
    MCF_QSPI_QAR    = 0x00;  // select QTR0
    MCF_QSPI_QDR    = w;     // write 16 bit data
    MCF_QSPI_QDLYR |= 0x8000;// start QSPI
  }
  lrck ^= 0x01;
} // void dtim0_handler()

例によって、BU9480F 用の「手抜き」コードで、L ch データだけ設定してやれば、 L / R 両方とも同じデータ出力されるということを利用しています。
実際に QSPI を操作しているのは、次の3行です。

    MCF_QSPI_QAR    = 0x00;  // select QTR0
    MCF_QSPI_QDR    = w;     // write 16 bit data
    MCF_QSPI_QDLYR |= 0x8000;// start QSPI

1行目は送信データ RAM の「QTR0」をアクセスするために、アドレスレジスタに「0」を設定しています。
2行目はデータレジスタを介して QTR0 に送信データを書き込んでいます。
3行目は転送開始のフラグをセットしています。