ディジタルオーディオ用 DAC をマイコンにつなぐ(3)
ここからは、各マイコンごとに、FM音源プログラムでの実例を示します。
まず最初は CQ 出版「インターフェース」2007年5月号付録基板 (CQ_V850) の V850 の例です。
BU9480F (ROHM)
BU9480 は2倍オーバーサンプリングということになっていますが、使われているフィルタは、単純な一次ホールド (相加平均) 特性です。
現在 番目のフレームで、 のデータが入力されていると仮定すると、両方のデータがそろった、サイクル最後の LRCK の立上がりエッジで、 に対応するアナログ値が出力され、LRCK の半サイクル後の立下りエッジで に対応するアナログ値が出力されるようになっています。
L ch だけデータを入力して、R ch については全くデータを入力しない (もちろんクロックも) 場合、L/R ともに同じデータが入力されたかのように振る舞います。
他の DAC の場合、L/R どちらかのデータ入力時のクロックが途切れると、出力を強制的にミュートするものもあります。
BU9480 の場合、1チャンネルの出力だけ使う場合には L ch だけデータを入力すればよく、手間が省けます。
V850 の場合
V850 では3線式可変長シリアルI/O(CSIB)モジュールの CSIB1 を使っています。
下の回路図のように、シリアル・クロック出力 SCKB1 を DAC の BCLK につなぎ、シリアル・データ出力 SOB1 を DAC の SDAT につなぎます。
LRCK は 16 ビット・タイマ/イベント・カウンタP(TMP)モジュールの TMP2 を使って生成しています。 TOP21 出力を DAC の LRCK につなぎます。
TMP2 タイマおよび CSIB1 モジュールの初期化のコード部分を抜き出したリストを示します。
void v850_port_setup(void) { ... // Timer2 setup TP2CCR0 = 1250 - 1; // 20 MHz / 1250 = 16 kHz TP2CCR1 = TP2CCR0 / 2; TP2OPT0 = 0x00; // CCR1 = compare, CCR0 = compare TP2IOC0 = 0x05; // TOP21 = square wave, TOP20 = square wave TP2CTL1 = 0x04; // interval timer mode TP2CTL0 = 0x80; // timer enable, clock = fxx TP2CCIC0 = 0x07; // enable Timer2 Compare 0 interrupt, level = 7 PFCE9L.6 = 0x01; // P96 = TOP21 PFC9L.6 = 0x01; // P96 = TOP21 PMC9L.6 = 0x01; // P96 = TOP21 // CSIB setup for digital audio DAC PFC9H.0 = 0x01; // P98 = SOB1 PMC9H.0 = 0x01; // P98 = SOB1 PFC9H.1 = 0x01; // P99 = SCKB1 PMC9H.1 = 0x01; // P99 = SCKB1 CB1CTL1 = 0x19; // CKP=1, DAP=1, clk=fxx/4 master CB1CTL2 = 0x08; // 16 bit transfer CB1CTL0 = 0xC0; // enable, TX enable, single, MSB first ... } // void v850_port_setup()
実際には、同時発音数を切り替える時に、タイマの分周数を変えて、サンプリング周波数を変化させています。
CSIB1 の動作モードは、
- MSB ファースト
- シングル転送モード
- 通信タイプ4
- クロック = fxx/4
- マスタ・モード
- 16 ビット転送
に設定しています。
ハードウェアで 16 ビット転送がサポートされているので、タイマ割り込みで SPI 出力する部分は、下のリストのように、きわめて簡単です。
// Timer2 IRQ handler #pragma interrupt INTTP2CC0 user_TP2CC0 // Timer2 Compare 0 interrupt __interrupt void user_TP2CC0(void) { int w; ... CB1TX = w; // spi output ... } // __interrupt void user_TP2CC0()
リストでは省略してありますが、w に出力すべきデータが用意されているとして、その値を送信データ・レジスタ CB1TX に書き込むだけです。
前回の出力が終了して、アイドル状態にあることは保証されているので、送信レジスタの空きステータスをチェックする必要もなく、また、L ch のデータだけを書いていますから、非常に簡単です。