« 2008年12月21日 - 2008年12月27日 | トップページ | 2009年1月4日 - 2009年1月10日 »

2008年12月28日 - 2009年1月3日の1件の記事

2008年12月28日 (日)

SDカードPCMプレーヤーの開発

非圧縮オーディオの再生はやはり難しい(12/23/08)
 色々迷ったが、直近の次のプロジェクトは16ビットDACを使ったデジタルオーディオに決めた。折角DACチップを買ったのだ。動かしてやりたい。他は別の用途にも使える。ターゲットマシンを何にするかも迷ったが、結局やはり使い慣れたAVRにすることにする。Pict0854

 というのは、H8/3069Fの現在のMMCインタフェースのSPIは高速と言ってもデータシートを見ると最大速度が250khzしかない。GPIOで手作りすればもっと早く出来るのだろうが、このままではAVRのCPUクロックの1/2のSPI(最大10Mhz)に比べれば見劣りがする。ARMプロセッサーのSTARMはSDカードを、買ってすぐにつけたが、こいつは当初より映像処理を目的にしているうえ、開発環境がまだ整っていないのですぐには立ち上がれない。で、必然的にAVRに落ち着いた。

 ファイルからWAVデータを読んでDACチップに投げるだけのプログラムである。始めは軽く考えていたが、サンプリング周波数44.1khz、データサイズ16ビットステレオという非圧縮のオーディオストリームは、シリアルで流れるとすると1.4Mbpsの速さである。MP3のビットレート192kbpsとか256kbpsという速さに比べると桁違いに大きい。下手をするとファイルを読む早さが間に合わないかもしれない。あわててSDカードのアクセス速度を確かめる。

 がた老AVR研のこれまでの実測データは、クロック8MhzのMega168で、読み込みが200KB/秒だ(バッファーサイズ128バイト)。オリジナルのchaNさんのレポートでは、9MhzのMega64でバッファーサイズが2048バイトだと300KB/秒近辺である。PCMオーディオの1.4Mbpsをバイトに直すと176KB/秒。うーむ、微妙なところである。余裕がありそうに見えるが、今度はファイルを読むだけでなくDACチップにデータを送るオーバーヘッドがある。SRAMの小さいMega168ではバッファーを大きく取れず難しいかもしれない。

 しかも、サンプリング間隔は、44.1khzだから22(正確には22.67)μsしかない。こんな短い時間で一回のファイルアクセスを完了することはSDカードでは不可能だ。処理は必然的にこの間隔を越えて動かなければならないが、もし、ファイルシステムがタイムディペンダントな部分を含んでいれば、CPUチップだけで再生しようというこの計画は即、破綻である。

 ソースコードを念入りに調べる。いやいやソースコードがあると言うのは有難いことである。調べた結果、データの送受はすべて1バイトづつSPIのデータレジスタを経由しており、データの読みこみ、書き込みのチェックはループで待っていることがわかった。AVRのSPIは独立したハードウエアであり、途中で割り込みがかかって処理が中断しても、アクセスが遅れるだけでおかしくなることはない。良かった。良かった。これで基本的な問題はクリアした。CPLDやFPGAを持ち出さなくて済む(ということで中々使う機会がない)。

 次の問題は、先ほどのDACへの書き出し処理のオーバーヘッドを含んだSDカードアクセスがはたしてPCMビットレートを上回るかと言う問題である。平均で遅いのは話にならないが、平均より早くてもバッファーサイズによっては途中で音が途切れる危険がある。こればかりはやってみるしかないが、せめて全体の目安くらいはつけておきたい。DACチップ(BU9480F)のデータシートをさらに読み込む。Bu9480f

 すると、このチップは、サンプリング間隔の中間でLとRを切り替え、それぞれ16ビットづつ送れば、中間を前後の平均をとった値で出力することがわかった。いわゆるオーバーサンプリングである。音質が良くなるのは良いが、送出するほうはさらに大変になる。間隔は22μsの半分の11μs(正確には、11.3μs)になる。そのたびに16ビットづつ送ってやらなければいけない。

 残る課題は、DACへのデータ送出を何でやるかという話である。AVRのSPIはひとつしかないので、ここに使うわけには行かない。それにAVRのSPIは8ビットで、16ビットを一気に送るようなしゃれたしかけはないので、オーバーヘッドを縮める時間稼ぎもできない。GPIO(普通のIOピン)で、クロックを自分で作りデータを送る方法に自然に決まった。

 BU9480Fが動く最も早いクロック(BCLK)は、60ns、16.6Mhzであり、この速さでデータを送れば、オーバーヘッドが減らせてSDカードアクセスに余裕ができるが、AVRがGPIOで出せる最高周波数はCPUクロックの1/2なので、最大クロックは10Mhzとなる。この速さでDACの16ビット送出にかかる時間は1.6μsで、サンプリング間隔との差、11.3 ‐1.6 = 9.7μsが、SDカードアクセスにかけられる時間となる。このあいだに2バイト(16ビット)が読めればバッファーアンダーランになることはないという理屈だ。

 データアクセス速度に換算すると、206KB/sec以上であれば、継続的な再生が可能なことになる。しかし、1.6μsはAVRのクロックから換算した上限値で、前後のLRCKなどのスイッチを考慮すると、2~3μsはかかるだろう。そうだとすると必要なアクセス速度は、215~240KB/sec以上ということになる。

 感触としては何とか出来そうな感じである。詳細設計に入ることにした。AVRの種類は迷ったがまずMega128で全体の動作を確認し、うまくいけばMega168にデグレードして、最終的には電池駆動のSDカードPCMプレーヤーにすることにする。

Mega168でも動きそうだ(12/27/08)
 実装手順としては、次の順番で実験を進めていくことにした。

(1)まず、DACの処理オーバーヘッドを入れたSDカードアクセスプログラムを組み、速度が所定の条件を満たしているか確認する。

(2)そのあとDACの部分をコーディングして動作を確かめる。最初のステップでは、UARTでファイル選択、再生開始、終了の処理を制御する。

(3)その後、LCDでのロジックを考える。

(4)アナログ出力は最初、オシロで観測するだけとし、そのあとオペアンプ、LPF等を追加して最終的にはヘッドフォンをドライブする。

 問題のWAVフォーマットはウェブで簡単に手に入れることが出来た。ハードウエアは、既にブレッドボードにMega128のSDカードシステムが動いているので、当面これを活用してテストを進めていくことにする。851brews128

 (1)のステップである。これまでの実測がMega168だけだったので、Mega128でもベンチマークをとった。chaNさんのFatFSにはサンプルプログラムがついており、その中には、ファイルのアクセス時間を表示してくれるfr,fwというコマンドが用意されている。ただ、このコマンドの時間単位が10msなので、短いレコードの計測では誤差がでるため、これを1msに縮めてより正確にデータが測れるようにした。

 ブレッドボードのMega128のバッファーサイズは2Kバイト(2048)ある。chaNさんのクロックが9.2Mhzだが、こちらは8Mhzである。結果はクロックの違いを正直に反映して、わずかに遅くなったが、それでも300KB/秒近辺に納まった。次に、クロックを16Mhzに上げる。SDカードとのアクセスも倍になる。アクセス速度は期待通り、倍にはならないが倍近い550KB/秒にはねあがった。しかし、残念なことに読めないメディアがでてきた(パナソニック128MBのミニSDカード)。

 まあ、2GBのマイクロSDが読めるのでこの問題は先送りして次に進む。バッファーサイズを256バイトに縮める。これはCPUをMega168に落としたときに使えるかどうかのテストである。アクセス速度は当然下がったが、330~360KB/秒と十分な速さである。素晴らしい。面白いことに16MBのメディアの方が、2GBのメディアよりわずかだが早い(chaNさんのレポートと同じ)。

 次はいよいよDACの割込みを考慮したときのアクセス速度の測定である。タイマーのひとつTIMER0を使って何もしない割込みルーチンをつくる。11μs単位に割込みがかかり、その度に2μsループしてから帰るルーチンである。動作確認のためにモニターコマンドを追加して、割込みマスクをON/OFFできるようにする。

 動かしてみる。おや、アクセス速度は殆ど変わらない。勿論、割込みが入るほうが遅くなるが思ったほど遅くならないのだ。メディアを替えたり、データ量を変えるとわずかに変化するが、それでも1~2%しか低下しない。何故だろう。チャートを描いてみてその理由がわかった。300KB/秒というのは、等間隔で1バイトづつ読むとしてその間隔は3.3μsである。 SPIはデータレジスタをCPUが読むとフラグが立ち、次のデータが来るまでフラグは変わらない。CPUはこのフラグが変わるのをひたすらループして待っている。遅くならないのは、待ち時間に比べてCPUの処理時間が少なく、2μsのDACのオーバーヘッドの殆どがこの中に吸収されてしまうからだと考えられる。Dac

 これで、SDカードによるPCMオーディオプレーヤーの基本的な問題はすべて片付いた。Mega168を16Mhzで動かせば、バッファーサイズが256バイトでも、かなり余裕を持ってPCM44.1khz ステレオ16ビットのオーディオデータをデコードすることができそうである。FatFSもR/Oにすればフラッシュサイズは8KB以下に納まる(LEDマトリックスのときに確認)。コーディングが楽しみになってきた。

 ソフトの構造はそんなに難しくない。ファイルのアクセス単位が大きいので、リングバッファーではなく、ダブルバッファーにして、DACの読み出しが別のブロックにあるときのみ、そこへデータを読み込むようにする。最初は、DACを止めておき、データが半分貯まった(2番目のブロックを読み始めた)とき、割込みマスクをはずしてデコードを開始する。このあとはDACのデコードとファイル読み込みとの競争になる。

 そろそろ、演奏の中断(途中から再開)、中止、曲の選定などの操作仕様を考える段階に来た。このあたりは最初のうちから考えておかないとソフトの構造が汚くなる。携帯機器にしたときのLCDの画面仕様も課題だ。手持ちの2行LCDで曲リストなどを出せるだろうか。Mega168なのでフラッシュメモリは限られている。なかなか難しそうだ。でも、それだから楽しいとも言える。

| | コメント (6) | トラックバック (0)

« 2008年12月21日 - 2008年12月27日 | トップページ | 2009年1月4日 - 2009年1月10日 »