非圧縮オーディオはやっぱりAVR単独では無理か
あけましておめでとうございます。
当研究所も発足して1年と2ヶ月がたちました。おかげさまで、昨年9月にブログを公開して以来、5000人以上の方がこのブログをご覧になり、リピート率も最近上がって、15%近くの方が2回以上訪れておられます。
余り参考になる技術情報はありませんが、電子工作で誰でもやりそうな失敗をあえて公開し、行き詰ったときや途方に暮れているときに少しでも役に立つヒントになればと思っています。問題解決の過程をなるべく細かく書いていますが、これは自分のためでもあります。今回も、非圧縮のオーディオデータの再生に向けての悪戦苦闘の状況を時系列でご紹介します。
久しぶりのソフト開発(12/30/08)
今年もあとわずかだが、今日も年末の買い物にあちこちつきあっただけで、ひたすらPCに向かってAVRのソフト開発三昧であった。SDカードに入ったWAVデータを再生するPCMプレーヤープログラムのコーディングは、昨夜から始めて、今日の午後には完成した。
ダブルバッファーや、DACへのデータ送出など初めてのロジックだったが、思ったより順調にコーディングできた。テストに入ったが、これが思わぬところでつまずいて、DACを動かすところまでいきつかない。SDカードがうまく初期化できず、出来てもそのあとエラーが続出して先へ進めないのである。
ハードは、ブレッドボードに組んだあった、Mega128で動いていたSDカードのテスト用のシステムをベースにした。MCUをMega168に替え、DACの部分を追加する。追加すると言っても、VccとGNDと3本のジャンパーをつなぐだけである。ただ、先にSDカードの方をテストするので、DACチップははずしてある。
ハードの動作確認のため、前に作ったファイルブラウザーのファームを168に入れる。クロックはとりあえず16Mhzとした。最初は、168のフューズビットを設定するのを忘れ(クロック1/8の出荷時のままだった)、UARTも動かずあせったが、これを直すと168では、128で読めなかった128MBのメディアまで読めた。
ここまでは、順調だった。ハードの確認ができたので、次はいよいよ新しいPCMプレーヤー用のファームを書き込む。新しい機能、DACの割込みはデータがバッファーに半分貯まってからであり、当面はマスクがかかっていて関係ない。ところが、これがこいつのせいかどうかファイルの初期化から、うまく動かないのである。
ファイルアクセスの部分は何も変えていない。割込みも始まっていないのに、おかしくなる理由がわからない。たまに成功するが、ディレクトリの表示が途中で切れたり、ファイルが読めなかったり、要するに不安定極まりない。ハードがおかしいのだろうか。動きは何故かハードが原因のような感じである。今日も深夜になったので作業をとりやめる。
12/31/08
大晦日である。残っていた買い物や、部屋の片付けをすませては、またデバッグに逆戻りする。Mega168はクロックを低電力で動かすモードにしてある。電池駆動を考慮してこのモードを選んでいた。データシートによればクロックを他に使うときは駄目だと書いてあるので、わずかの望みを抱いてフューズビットを直して動かしてみたが、やはり関係なかった。相変わらずのエラーである。しかし心持ちエラー回数が減ったような気がする。
それでも、初期化に成功するのは10回に一回といったところで、とても実用的なレベルでない。時々動くというのがデバッグでは一番始末が悪い状況である。これまでこんなに不安定なことはなかった。プログラムを変えていないと言っても、クロックを上げたり、細かいポートの設定で少しづつ変えている。SDカードの電源制御のバイパスなども加えた。どこかが、悪さをしているのだろうが、特定できない。仕方がないので、クロックをこれまでの半分の8Mhzにしてみた。このクロックではWAVデータの再生は微妙だが、クロックの影響を確かめるためである。
その結果は、ちょっとましになったとは言え不安定なことに変りはない。16MBのメディアは大体読めるようになったが、2GBでは5回に一回しか成功しない。128MBはもっと悪い。何十回もやって諦めようとしたときに読める程度だ。意外なところでプロジェクトが頓挫してしまった。ファイルが読めないことには次に進めない。Mega128では動くのかもしれないが、今さら替えるわけにも行かない。
1/1/2009
新年の東京は風が冷たいけれど、おだやかな正月日和だ。家族・親戚と久しぶりに元日の初詣を近くの神社ですませる。新年の気分は清々しいのだが、SDカードプレーヤーの開発は思わぬ障害に出くわして、どうも今ひとつ気分が、今日の青空のようには晴れない。
今まで何のトラブルもなく快調に読めていたSDカードがプラットホームを替えただけでおかしくなってしまったのだ。ディスクのイニシアライズは確かに最初つまずくこともあったが、リトライすれば、OKとなり、そのあとは全く快調だった。それがディレクトリを読むたびにエラーが頻発するし、ファイルのオープンもままならない。何かおかしい。
途方に暮れて、今まで動いていたMega168のSDカードアクセスプログラムを入れなおして動かしてみた。これが、何と、全く何事もなかったようにSDカードが読めるではないか。一回のミスもない。ひゃあー、これは一体全体どうなっているのだ。どこを変えてしまったのか。
原因究明はともかく、これまでのコードはとにかくご破算にし、今、動いているコードを母体に、PCMプレーヤーにすることにする。ファイルシステムをR/Oにし、不要なコードを削除しながら、少しづつ変えていく。全く問題ない。何をいじったのだろう。よく分からない。
遂に、最後のDACの割込みルーチンを入れるところまで来た。ここは動いていないので関係ないはずだが、とにかく割込みルーチンを入れ、割り込みがマスクされているのを確かめて動かす。うわあ、こいつが原因だ。これで動かなくなった。信じられない。ファイルの初期化ではまだ、この割り込みは動かない。プログラムを入れただけで何故動かなくなるのだ。わけがわからず呆然とする。
アセンブラーをもってしても無理そう(1/2/08)
すこし冷静になって考えてみた。16ビットのデコードにかかるクロック数である。このあいだは、単にDACクロックの上下だけしか考えておらず調子の良いことを書いていたが、ここにはデータラインをH/Lにするプロセスが必要で、これを加えて16回繰り返す必要がある。ここでの1クロックは16倍に効いてくるので大変だ。さらに割込み前後でのレジスター退避のオーバーヘッド(push/pop)、LRCKなどの切り替えなどを入れると、とてもこのあいだのような2~3μsではすみそうにない。ファイルも読めないのに基本的なところが駄目だとわかって愕然とする。
アセンブラーで書き直すにしても、20Mhzとして、ビットプロセスに6 クロック(データから1ビット取り出し、H/Lのチェック、ポートの出力、クロックポートのup、データのシフト、クロックのdown)かかるとして、6×16=96クロック、中心となる部分だけで4.8μs、前後の処理合わせて、6~7μsは最低かかる。この時間は、アセンブラーの最小の処理の時間だ。Cではこれ位ではすまない。
サンプリングの周期は11.3μs。半分以上がDACへの送り出しにかかる。やっぱり無理かもしれない。道理で、ウェブ上で、非圧縮のPCMプレーヤーの制作記事がないわけである。
WINAVRはCソースをアセンブラーにしたリストを表示してくれる。すこしゆとりが出来たので、このリストを調べてみた。やはり割込み部は、100バイト以上あり、これが16回ループするのだから、とてもじゃないが、11μsのサンプリング周期の殆どをDAC送り込みに使ってしまってファイルアクセスしている時間はとれない。アセンブラーにしても今のままでは、クロック20Mhzで5μs、16Mhzなら6μs、こりゃあ駄目だ。
ただ、それはともかく、まだファイル読み込みが成功していないのだ。何度もソースコードを見直すが、割込みはマスクされていることに間違いない。しかし、現象は割込みが初期化から始まって混乱させているように見える。SDカードの初期化は、何回か待ち時間を設けてタイムアウトでエラーにしているところがある。これが割込みで乱されると間違いなくおかしくなる。
仕方がないので、割込み部の処理を大幅にコメントアウトしてI/O命令だけを入れ、ロジックアナライザーで、本当に最初から割り込みがかかっているのか確認することにする。結果は割り込みはかかっていないことがわかった。しかし、今度は割込み部を入れてもファイルの初期化が問題なく終わる。おかしいな。前は入れただけで動かなくなったのに。
何故かいつのまにかファイルアクセスが正常に戻ってしまったのである(このあとSDカード基板のピンとブレッドボードの接触不良を発見した。これが主な原因くさい)。割込みルーチンを少しづつ増やしていく。ポインターを進めるステップを入れて、いよいよマスクを外し、データの読み込みまでやらせてみた。おお、やった。エラーも出ずファイルの最後まで読んだ。読んだ回数は正確にファイルサイズと一致する。うむ、最後まで読んだようだ。
ロジックアナライザーのプローブ点を増やし、割り込みと読み込みのタイミングを表示させる。出た、出た。サンプリングは正確に、11.33μs間隔で、LRのトグルも上手く行っている。ファイルの読み込みも、この間隔内で3バイト、4バイトと読んでいることが見える。素晴らしい。データをバッファーに2回(16ビット)入れる処理だけを入れて、2μsほどだ。
ここでひらめいたことがある。データを出すプロセスはGPIOを使ってクロック20Mhzで16ビット、最小でも4μsかかる。SPIならクロックの1/2まで出せるので、16ビットを10Mhzで送出するなら、1.6μs、2回目の送出はハードがやってくれるので、最小では0.8μsだけの時間で16ビット送れるかもしれない。 Mega168にはもうひとつのSPI、USIインタフェースがあるはずだと思ったが、残念、TWIはあるが、USIはなかった。Mega128もUARTは2つあるが速度が遅く(1M以下)使えない。うーむ、このクラスのMCUでは非圧縮のオーディオデータの再生は無理なのか。
オーバークロックとアセンブラー(1/5/09)
昔から、出来ないといわれると余計やりたくなる性格である。へそ曲がりであることには少々の自負がある(自慢にもならないが)。今回もこの程度で断念するわけには行かない。SDカードの読み込みが順調で、ロジックアナライザーにもそれらしいタイミングが表示されている。あともう少しで出来そうな気もする。ここで諦めてしまうのは情けない。いろいろな方法を試してみた。
まず、MCUのクロックを早くすることを考える。ウェブでAVRを24Mhzのオーバークロックで動かしている記事を見たことがある。クロックが早くなれば結果的にDACのオーバーヘッドが減ってSDカードのアクセスに時間が使えるようになる。規格外だけれど今のところ動くことが優先だ。幸いNICチップの時に予備に買ってあった25Mhzの石がある。動かしてみることにする。UARTとSPI(1/4の6.25Mhzに落とした)のボーレートを調整する。MCUそのものは特に問題なく動いた。SDカードのアクセスも順調だ。
それではというので、DACの割込み部に、16ビットに一回でるLRCKのトグルだけでなく、ベースクロック(BCLK)を出力するコードを追加する。うむ、ちゃんとBCLKも出た。しかし、ロジアナで時間を測ると、クロックを出すだけで7.2μsもかかっている。当然、SDカードの読み込みは途中でハングする。
このまま、データラインをドライブする処理を加えれば、DACの出力だけでCPUパワーを使い切ってしまうだろう。Cではもう限界のようである。割込み部をアセンブラーにする必要がある。AVRのアセンブラーは、最初の頃や、割り込みを使ったソフトUARTの時以来で余り慣れていない。それに割込みルーチンをアセンブラーにして外部変数の受け渡しに苦労した記憶があるので、気が進まなかったのだが、今はそんなことは言っていられない。資料を取り出して再勉強である。
外部変数の受け渡しに自信がないので、前と同様、Cの割込み部でアセンブラーの関数を呼ぶ形で久しぶりのアセンブラーのプログラムを作る。時間を稼ぐために、8ビットのデータをシリアル化するコードを8つ並べる。本当は16並べればもっと早くなるが少しさぼる。思ったより短い時間でコーディングができた。
動かしてみる。おお、やっとデータ部にそれらしいデータがロジアナのチャートにあらわれる。で、どれくらい時間がかかった? 16ビットのデコードだけで6.3μs、割込みルーチン処理時間は8.3μs、割込み前後のオーバーヘッドを加えれば、9μs以上。SDカードは勿論読めない。3ブロック目でストップしている。
44.1khz、16 bit ステレオの非圧縮オーディオの再生は、やっぱりクロックが20Mhz程度のAVR単独でやることは不可能のようだ。まあ、ステレオでなく片チャンネルだけの再生は出来るかもしれないが、このプロジェクトは残念ながらとりあえずここで中断することにする。
| 固定リンク
「AVR」カテゴリの記事
- ソフトI2Cはクロックストレッチまで手を出してあえなく沈没(2017.09.02)
- オシロのテストどころかソフト開発で大はまり(2017.07.26)
- 超音波方式の人感センサーI2C化と新しいオシロ(2017.06.29)
- motionの動体検知はRaspi3の電源が安定しない(2017.04.16)
- 赤外線学習リモコンはデータ再現で挫折したまま進まず(2016.07.21)
コメント
はい、現在はデバッグ用に使っていますが、今改めてデータシートを見ていて大きな勘違いに気づきました。ボーレートの表に惑わされて最大速度は1Mbpsどまりだと思っていたのですが、よく読むとクロックの1/2まで大丈夫なようですね。デバッグ用のUARTはGPIOで他に移せます。これはありがたい。可能性がでてきました。有力な情報ありがとうございました。
投稿: がた老 | 2009年1月 8日 (木) 13時14分
MEGA168では USARTがSPIとして使えるので total SPI 2CHと
することができるが、すでにUSARTは他の用途に使用済み?
投稿: kuga | 2009年1月 8日 (木) 03時40分