« 2008年12月 | トップページ | 2009年2月 »

2009年1月の4件の記事

2009年1月22日 (木)

Mega328の44.1khz非圧縮オーディオ再生

ロジアナの威力を改めて実感(1/18/09)
 やっとのことで綺麗な音の再生ができて、色々調べる余裕が生まれた。ロジックアナライザーのタイミングチャートは、スタート直後はとれているが、再生中の状況は観測できていない。バッファーがどれくらい余っているのか、44khzのCDレベルのオーディオ再生にはあとどれくらいのバッファーサイズが必要なのか知りたいところである。ロジアナを接続しなおし、再生中にトリガーをかけて観測することにした。22khz8stereo_2

 プローブ点をバッファーの切り替え時点に置き(これに早く気がつくべきだった)、SDカードを読む前後にもプローブ点をつけて、トリガーをファイル読み込みのスタートにしてデータを採集する。出た。おお、しっかりファイルを読み込み、余裕でバッファーがスイッチされているのがわかる。おや、ファイル読み込みが瞬間で終わっているところがある。これは何だ。SDカードを読むSPIは何も動いていない。プローブピンに変なパルスが入ったのだろうか。

 あ、あ、あ、分かったぞ。今まで何を考えていたのだろう。SDカードのデータアクセスがセクター単位(このときは512バイト)であることを、すっかり忘れていた。今までのロジックアナライザーのデータは、DACのサンプリング間の極く短期間のファイルアクセスにばかり気を取られて、やれ、区間内に3バイト読んだ、2バイトだと危ないとか一喜一憂していたけれど、これはセクターを一気読みしている間の部分で、全体からみれば、データアクセスはバッファーサイズがセクターより小さければ、間歇的なのだ。まさしく、木を見て森を見ずという諺どおりである。

 セクターを読んだ後の、ファイル読み込みを示す短いパルスは、SRAM内のデータ移動だけの区間だったのである。ノイズでも何でもない。FatFSのソース(ttf.c)の中に、512バイトの構造体があって、これは何だろうと気になっていたが、実際に512バイトのSRAMエリアがあることを恥ずかしながら、ここで始めて理解した。

 お馬鹿な話である。コンパイルの後のSRAMサイズがバッファーを200バイトくらいしかとっていないのに、常に800バイト近くあるのを不思議に思っていた疑問は氷解した。構造体は必ずしも実メモリが存在しなくても定義できるので、てっきり仮想的なメモリ空間だとばかり思っていたのである。

 今になって考えれば、そんな仮想的な空間がこの狭いマイコンのメモリの中であるわけがない。知らないということは恐ろしいことである。それはともかく、このチャートで、今さらながら全体の動きを完全に理解できた。こうなると44.1khzのCDレベルのデコードに必要な要件はこのタイミングチャート上からすぐ計算ができることになる。

 チャートを見ると、ファイルのアクセスにかかっている時間は一目瞭然である。SDカードの1セクター、512バイトを読む区間は、readリクエストを出して、SDカードがACKを返し、実際に読み込みを終了して、読み込み関数f_readがアプリに帰ってくる時間である。これはクロック20Mhzで1300μsくらいだ。バッファーをセクターより大きくしない限り、ファイルアクセス時間がこれ以上長くなることはないだろう。

 一方、DACが送り出すバイト数は、完全にサンプリング周波数とデータ長で決まる。チャートを調べるまでもない。44.1khz16ビットステレオを、BU9480Fは、11.3μsごとに16ビット取っていくので、1300/11.2×2=229.4バイト以上のバッファーサイズがあれば、バッファーのアンダーランはおこらない。

 惜しい、Mega168でも、あと少しだった。思ったより少ない。Mega128の4KBのSRAMまで必要がなさそうだ。このところウェブで話題になっているのMega168の拡張版、Mega328がある。これならSRAMが2KBある。これで十分である。

 早速、ショップ(マイクロファン)にMega328を注文した(¥525)、ここは何度かMega168を買っているところで、事務所に近いので電話で注文し、直接取りに行っていたが、今回は気がせいているので通販にする。

 このあいだはオシロに助けられ、今度はロジアナで全貌が見えた。いやいや道具には金をかけるものである。ただ、実装のイメージがまだ固まらない。SDカードに入れた音楽CDを聴く機会がどれだけあるのかわからない。今の携帯電話で十分なのではないか。これまで作った温度ロガーや、LANによるAC電源制御、メトロノームの間隔を調べるリズムキャプチャー、自分から言うのもなんだが、結構みんな役に立っている。今度の機械はちょっと自信がない。

割込み駆動でアドレスの比較をしては駄目(1/19/09)Pcm_cons
 公開に向けてソースコードの整理を始めた。今はUARTがモニターで、PCの端末から再生するWAVファイルの指定をするようになっている。実用的とはいえないが、DACチップの動作例として少しは参考になるだろう。Mega328が来れば、CD音質の44.1khz16ビットステレオの再生が出来そうだ。これならネットに公開しても恥ずかしくない。22khzでも結構音は良いが、このあいだPCで音楽CDを22khz(正確には22.05khz)8ビットステレオにダウンコンバートしSDカードで再生してみたら、やっぱり見劣りがする。それはそうだデータ量は1/4になるのだから。思い込みかもしれないが、音の輪郭がぼける感じがするのだ。

 それはともかく、いたるところにデバッグコードが入り、いろいろ試行錯誤をしたソースコードである。整理をしなければ自分でも読みづらい。一番無駄なところは、ダブルバッファーの処理である。余計なフラグを使ってややこしくなっている。リングバッファーと違ってデータが入るファイルの読み込みポイントは2箇所しかないし、データを取り出すDACポインターのアドレスの比較をすれば、フラグを設けたりフラグのスイッチする必要がないはずだ。

 フラグをやめて、ポインターのアドレスの比較だけにする。プログラムがすっきりし、フラッシュサイズも数十バイト減った。意気揚々とファームを書き込み、動かしてみる。これが、うまく動かない。ハングアップか「ブー」というノイズだけになってしまう。他の部分は何も変えていない。ロジックは間違っていないはずだ。何度も紙にチャートを描いて確かめる。間違いない。

 コードを一旦、正常に動いていたときに戻し、少しづつ変更しておかしくなるところをつきとめていく。その結果、犯人は次のバッファー読み込みのため、DACポインターがそのブロックを去るのを待っているコードであることがわかった。ステートメントは
   while(ptr > &Buff[ダブルバッファーの起点]);
だけである。調べようもない簡単なステートメントである。頭を抱えた。

 次の朝、AVRのデータシートを眺めていてひらめいた。I/Oレジスターの16ビットデータの取り出しのところである。LowバイトとHighバイトは、必ず割込みを禁止にしてから取り出せとある。いわゆるアトミックオペレーション(非分割操作)というやつだ。そうだ、これに違いない。ポインターはアドレスなのでAVRでは2バイトだ。ここは頻々と割り込みが入り、DACのポインターであるptrが動いて、それを比較する部分である。確かめるまでもない。比較を1バイトのフラグに戻しテストしてみる。

 直った!ちゃんと元通り音を再生するようになった。やれやれこんなところに落とし穴があったとは。C言語なので割込み禁止命令を挿入するわけにもいかないし、ステートメント全体でかければ、このステップの意味がない(割り込んでくれてはじめてwaitが解ける)。ここでも真犯人は別のところにいた。

Mega328届く。苦もなく44.1khzを再生(1/20/09)
 SDカードのWAVデータを再生するプロジェクトもブレッドボード上のUARTインタフェース試作版では完成に近づきつつある。プログラムの改修で、こんなのは自分には関係がないと思っていた、アトミックオペレーションのトラブルを解決し何か急に自信がついた感じがする(乗りやすいタイプである)。勢いに乗って、周辺の機能を書き込んだ。

 まず、曲の再生中の中止である。ファイルを読むメインループにUARTのread監視関数を入れ、キーが押されたらループを抜けるようにする。簡単に出来た。調子に乗って中断機能を追加する。これも同じ関数をforループでまわし特定のキー(スペース)でこのループを抜ける。おお、これは便利だ。段々プレーヤーらしくなっていく。

 次はいよいよアナログ部だ。トランジスタのエミッタフォロワーをオペアンプのボルテージフォロワーにとりかえる。LPFはどうも今のPCスピーカー程度では、余り効果がわからない(耳が悪くなって高周波ノイズが気にならなくなったか)ので今のところ省略し、オペアンプに前に買ってあったオーディオ用のNJM4580を使う。

 最初は音が濁り、オシロで見ると明らかに発振を起こしている。ボルテージフォロワーは発振しやすいと言うし、具体的な対策は最近の位相補償がされているオペアンプでは難しい。アナログは一筋縄では行かない。色々試しているうち、DACの出力とオペアンプの間に直列に抵抗を入れると発振が弱くなることに気づいた。ここはハイインピーダンスなので相当高い抵抗を入れても問題ない。ためしに10kΩにしてみると見事に発振がとまったのである。理由はわからない。もしかしたら発振ではなく、DACからの干渉かもしれない。

 発振が止まったとなると音は、確かにトランジスタに比べてはっきりした音になったように思う。しかし何事も確認しないと気がすまない性格である。ウェブあたりでは酷評されている汎用のオペアンプLM358に替えてみる。なんだ、なんだ。ノイズもなくオーディオ用のNJM4580と変わらないじゃないか。増幅すれば変わってくるのだろうが、ボルテージフォロワーで使う限りは何の問題もない。オペアンプは2回路あるのでステレオにするのが楽だ。ヘッドフォンで聞くには少しゲインがありすぎるので、PCスピーカーに入れて色々な音を聞き比べる。Mega328

 夕方、郵便受けを覗くと、Mega328Pを入れたメール便が届いていた。予想より早い。夕食後、早速、換装にとりかかる。AVRSPは感心なことにちゃんとMega328Pを認識し、フューズビットの書き換えも全く問題ない。勢いにまかせてAVRstudioに持ち込む。328は168とピン互換なので何も替えないで良い筈だ。バッファーサイズを512バイトに上げ、サンプリングルーチンの22khz用をコメントアウトし、元の44.1khz用にもどし、コンパイルしてみる。

 あれえ、エラーが出る。何がエラーだ。何と、PD4とかPB0という汎用のピン名がエラーになっている。これはどうしたことだ。328用のヘッダーファイルを確認する。ない!全部、PORTD4、PORTB0という定義しかない。何でこんな変える必要もない(単に数字におきかわるだけ)基本的なところを換えるんだ、と悪態をつきつつ、定義し直し、コンパイル出来たので動かしてみる。ところが出来たバイナリはスタートメッセージをだすだけで先に進まない。リセットされてしまう。

 やれやれ、ピン互換じゃないのか。もういちどコンパイルメッセージを詳しく見ると警告の形で、割込みラベルが未定義というのを見つけた。ありゃりゃあ、ソフトUARTに使っているピンチェンジ割込みのエントリの名前が換わっている。何でこんなのを換えるんだ。それに警告はないだろう。これでバイナリを作られても困る。

 ぶつぶつ言いながらもう一度コンパイル。今度は警告メッセージは出ない。はやる心を抑えてPCから44.1khzのWAVデータをもう一枚のSDカードに移し、テストする。出た!これまで何度も挑戦して果たせなかった、44.1khz16ビットステレオの音である。やはりこれまでの22khz8ビットとは違うきめ細かな音で、シーッという量子化ノイズも全く聞こえない。やはり音の格が違う。素晴らしい。ロジアナでタイミングチャートを見てみた。バッファーをセクターと同じ512バイトにとったので、バッファーの切り替えの度にファイルを読んでいるのがわかる。うむ、想定どおりだ。満足、満足である。Pcm44_ok

 遂に、このプロジェクトも大詰めを迎えた。次のテーマをどうするか。こいつの実装版か。それも良いが、STARMを少しやりだしたし、H8のTOPPERSもある。AVGAもある。いやいや、やりたいことが多すぎる。

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

2009年1月16日 (金)

22khzステレオ8ビットのPCMオーディオ再生成功

まともな音にならない(1/13/09)
 SDカードからWAVファイルを読み込み、DACチップにCD音質の44.1khz16ビットステレオ音声を再生するプロジェクトは、Mega168の2つのSPI(ひとつはUSARTの同期シリアル)で、何とか音が出る段階まで進んだ。DACチップが始めて動いたのである。しかし、出てきた音は、かろうじて元の音とわかる程度の歪みだらけの音で、成功とは程遠いレベルであった。

 始めはアナログの部分のLPF(ローパスフィルター)がなかったり、ハイインピーダンス(10KΩ)出力にヘッドフォン(数Ω)をつけたからだと思っていたが、どうもそんなレベルの歪ではない。エミッタフォロワーのトランジスタをつけ、LPFらしきものをつけてみたが当然全く改善されない。どうもアナログ以前のデジタルに問題があるようだ。しかしデコードのタイミングチャートはロジアナで見た限りでは、全く問題がなく、ファイルもエラーなしで最後まで読みきっている。

 正弦波のデータを作って、再生してみれば何が原因で音が割れているのかわかると思うが、WAVファイルを、ライン入力から作るには、PCの裏側まで廻ってコードを接続したり、歪まないようレベルの心配をしたりするのが面倒で、何とかそこまでせずに解決できないかと、SPIのモードを変えてみたり、LRCKのタイミングを変えて見たり(データ送出終了割り込みでトグル)するが解決の気配はない。

 デジタルは大丈夫、タイミングチャートは完全とは言っても、ロジアナのデータは、トリガーとデータ蓄積量の制約で開始直後のところしかとれておらず、DAC書き出しとファイル読み込みが錯綜する部分のタイミングチャートは採集できていない。途中のデータをとるには、プログラムを組む必要があり、そう簡単には出来ない。

 そこで、オシロを持ち出して、サンプリングのタイミングを決めるLRCKだけでも表示させてみた。これが何と、不揃いなところが見つかったのである。11.3μsでなく、明らかに9μs近辺まで短くなっているところがある。こんなに大きくサンプリングが揺れれば当然、音は歪みまくる。これが原因か。しかしこれは有り得ない話だ。サンプリングの割込みを遅らせる要因になるタイマー割り込みはこのあいだマスクした。だとすると、割込み禁止の区間がSDカード読み込み処理の中にあることになる。これは調べるしかない。

 FatFSのソースを仔細に読んでいく。データを読む関数f_readは、PCM再生中動く唯一の関数で、これを掘り下げると、個々のクラスターを読むget_clusterになり、これは、mmc.cにあるディバイス依存の関数、disk_readに行く。そして、SDカードからデータを受け取るreadコマンドは、最終的にはすべてrcv_spiという1バイト読み込みの関数に行きつく。ここではSPIの割り込みは使わず、loop_until_bit_is_setというステートメントでループして待っている。CPUループで待っている。どこも割り込み禁止をしているところはない。とすると、どこが遅らせているのだろう。SPIを動かすと、CPUクロックまでが遅れる?まさか。

オシロの波形を一目見て原因が判明
(1/14/09)
 やっぱりまともに正弦波データを作って、ひとつづつ問題点を洗い出していくしか解決の道はなさそうだ。このあいだ作ったFG(ファンクションジェネレーター)の出番である。このFGの出力はいわゆる0デシベルのライン出力(1V  P-P)で、PCのサウンドボードのライン入力に直接つなげるはずだ。用心のため簡易アッテネーターを経由し、Windowsのサウンドレコーダーを始動させる。念のためオシロでも波形が見られるようにする。

 おお、出た出た。割れてもいないようだ。サウンドボードのライン入力は直接、出力にも出るので調整も楽だ。思ったより簡単に正弦波、方形波など各種の音声波形を入れたWAVファイルを作ることが出来た。ファイルをSDカードに移し、それをMega168に持ち込み、オシロをDAC出力につないで再生してみる。あっあっあー、なーんだ。わかった。出てきた波形を見て一発で原因がわかった。波形が途中から折れた正弦波が観測されたのである。方形波もいたるところで寸断されている。あれこれ悩む必要は何もなかった。最初から、波形データを調べれば良かったのである。音が途切れる原因はバッファーのアンダーランに違いない。ファイルの読み込みが間に合わず、DACのポインターが一周してしまっている。Dacovrflow

 サンプリング周期は変更できない(ジッターで音が歪む)ので、DACのデコードを待たせるわけには行かない。ファイルが読まれる前にDACへの送り出しのポインターが、読み込むべきバッファーの領域にまで入ってしまうと、新しいデータでなく前の古いデータをデコードすることになる。11.2μsごとに2バイトづつ送り出すDACのポインターが1周して、ダブルバッファーの2つを使い切る時間、11.33/2×160=906μs前の元の波形に戻っている波形がオシロに見事に表示されている。いやあ、素晴らしい。こんなにはっきり見えるとは。事態の深刻さも忘れて、暫し、オシロの威力に感動する。思い切って買っておいて良かった。

 SDカード読み込みの一回のサイズは、ダブルバッファーなので、全体の半分わずか80バイトしかない。これでもMega168のSRAMは80%以上の800バイトを越え、これ以上大きくすると、スタック領域に被ってプログラムがまともに動かなくなる。 バッファーのアンダーランは、始めは心配していたが、20Mhzのクロックだと、平均ではファイルアクセスの方が2倍以上早く、DACのオーバーヘッドもSPIにして20%以下になったのでつい油断していた。

 念のため、割込みルーチンにカウンターを設け、アンダーランしたとき(ファイルの読むバッファーと、取り出すバッファーが一致したとき)、カウントアップするステートメントを入れて調べてみた。結果は、べらぼうな数字で、1秒程度のWAVデータ(180KB)で、2万回は起きている。一旦、アンダーランが起きればファイルアクセスが止められるので、1ブロックをデコードする間すべてカウントされるから、バッファーサイズ80バイトとして40回、ダブルバッファーの切り替えは、180KBで、2250回、2万回/40=500回、2250/500=4~5回に1回は、ファイルアクセスが間に合わず追い越されている計算になる。

 少しでもアンダーランが減るかと、バッファーサイズを少しづつ増やしてテストしてみた。80バイトから128バイトまで増やすことができた(それ以上は暴走)。しかし、アンダーランの数は全く変わらない。厳密に言えば、新しいデータがバッファーに溜められたあとのアンダーランは必ずしもデータが間違っているわけではないので、回数のすべてが不正データと言うことではないが、いずれにしてもこの程度のバッファーサイズの増加は効果がないようだ。

 音の割れる原因は明らかになった。しかし、これは深刻な問題である。平均ではファイル読み込み速度の方が明らかにデコードより早いのでバッファーサイズを大きくすれば解決できるだろうが、Mega168というプラットホームに限定する限り、これ以上は無理である。オーバークロックという手もあるが、効果は余り期待できない。バッファーを5割増やしても変わらなかったのだから、2割程度のスピードアップで回避できるとは思えない。このあいだファイルアクセスルーチンを解析したときに、クラスターチェーンを延々と調べているロジックを見ている。読み始めると早いのだろうがアクセスは連続的ではない。

 最近、Mega328という168のフラッシュを32Kにした石が出てきて、これはSRAMが2Kある。これを使う手もあるが、ただ、2KのSRAMで間違いなくこの問題が解決されるかどうかはわからない。いずれにしても、SRAMが4KあるMega128ならともかく、残念ながらMega168では、CD音質の44.1khz16ビットステレオの再生は無理なようである。

念願の非圧縮PCMオーディオ(22khz)の再生に成功(1/16/09)
 プロジェクトの方向をどちらに進めるべきか迷った。SRAMの大きいMega128ないし、Mega328に換えて、あくまでもCD音質にこだわるか、44.1khzを諦め、22khzステレオ8ビットの非圧縮WAVデータの再生を考えるかである。というのは、昔、買った環境CDに入っていたクラシック音楽が22khzの8ビットデータにもかかわらず、なかなか良い音がしているのを見つけたからである。22khz8ビットステレオなら、データ量は1/4になり今のシステムでも十分再生可能の感じがする。

 実用的な用途を考えているわけではない。この程度のオーディオ機器なら今は市販の手のひらサイズのものがいくらでも手に入る(ICレコーダーがPCMで録音できる)。もとはといえば、はずみで買った16ビットDACチップを動かしてやろうと言う単純な動機である。とにかく音を出すほうが先だ。22khzステレオ8ビットデータの再生を試すことにする。

 プログラムの改修にとりかかる。サンプリングの周期を倍にする。デコードは16ビットDACなので、1バイトだけバッファーから読み、下位バイトは0にしてやれば8ビットデータが16ビットになる理屈である。あっというまに出来た。サウンドレコーダーで短い22khzステレオ8ビットWAVファイルを作り、はやる心を抑えながらブレッドボードの基板に持ち込む。

 再生してみる。あれえ、前よりひどい。ノイズでしかない。何を間違えたか。気を落ち着けてWAVフォーマットを確認する。ちゃんと書いてあった。16ビットデータと8ビットデータはフォーマットが違うのだ。16ビットは符号付き、8ビットは符号なしで、中間の128が0Vに相当する。やれやれ、あせってやるとろくなことはない。データから128を引いた変数を符号付き1バイトにキャストする。これで良いはずだ(自信がない)。

 今度こそと祈る気持ちで再生する。やったやった。とてもクリアな音がヘッドフォンから聞こえた。今までの音とは全く違う歪みのない音だ。テスト用の正弦波データを再生してみる。うむ、きれいな正弦波が出ている。間違いない。正しく再生できたようだ。

 勢いに乗って、20MBばかりの環境(ヒーリング)CDのクラシック曲をSDカードに移し、ヘッドフォン出力をPCスピーカーにつないで音をだしてみた。おお、全くノイズも歪みも感じられない美しい音だ。今までテストしてこなかった片チャンネルもついでに直結してみる。何だLPFをかけずに直結しても大して音は違わない。ステレオになったので余計音の厚みが増す。素晴らしい。PCの小さなスピーカーくらいでは、PCでの再生と違いは全くわからない。今まで歪みだらけの音を聞かされて暗い気持ちになっていた目の前の暗雲が吹き飛び、透き通った青空に雲雀の声を聞く気分である。今までの苦労がうそのようだ。A1151445

 嬉しくなって、7つばかりの曲データをすべてSDカードに入れて次々に再生する。いやあ22khz8ビットでもなかなかのものではないか。至福の時間である。これで去年の暮から始めた非圧縮オーディオの再生は、CDレベルには届かなかったが、とりあえず非圧縮PCMオーディオの再生まで辿りついた。曲を再生しながら、ブレッドボードに乗ったMega168、BU9480F、ファイルアクセスを示すLEDをいとおしく眺める。ジャングルのような配線を通して、この音が出ていると思うととても不思議な気分になる。

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

2009年1月13日 (火)

AVRのUSARTでPCMオーディオ音が出た!

STM32F103を調べ始める(1/6/09)
 SDカードPCMプレーヤーの開発はAVRでは挫折した。しかし、やりかけたら、とことんまでやらないと気がすまない性分である。このまま引き下がるわけには行かない。DACチップは結局動かさずにプロジェクトは中断している。チップにはまだデータが一度も流されていない。何とか音を出してやらないとこのままではDACチップが可哀そうだ。Stm32f103

 で、当然、AVRに替わるターゲットは、例の雑誌付録(デザインウエーブ2008年5月号)のSTマイクロのARMプロセッサー、STM32F103ということになる(H8はMMCインタフェースが遅すぎて無理)。この基板は、SDカードをつけ、USBのマスストレージが動くところまで確認したが、その後は手をつけていない。クロック72Mhzの32ビットプロセッサーである。オーディオではなくビデオ関連の開発機として考えていたのだが、オーディオの出番がまわってきた。

 こいつは、18MhzのSPIを2つ持っているし、DMAもある。スペック的には全く問題ない。しかし、何と言っても未経験であり、雑誌についていた開発環境すらまだインストールしていない状態だ。無償版の開発環境はフラッシュが32KBに制限されているが、当面は問題ないだろう。gccが、雑誌の後の号で紹介されているが、これは開発環境そのものをビルドするだけでも相当な手間がかかりそうなので先の話だ。

 具体的な目標が出来たので、改めて雑誌の記事をもう一度詳しく読み直した。このARMに関する記事は、4号にわたって、かなり詳しく出ている。このうち3冊までは買ってある。しかし、自分の知りたいことは何も書かれていないことがわかった。開発環境のインストールや、DFUというUSBからファームを書き込むライターのインストール手順は詳しく出ているがその先がない。

 少しまともなプログラムを開発をするために必要な具体的な情報が殆どないのだ。ソースが出ているのはLEDを点滅させる10行足らずのサンプルプログラムだけである。32ビットプロセッサーだけに豊富なペリフェラルがついている。これを使いこなすにはライブラリが必須だと思うが、記事には、その一覧表があるだけで、利用する手順は一切省略されている。せめて"Hello World"をどこかに出すくらいのソースコードでもあれば、ライブラリの使用例が見えるのだが、それもない。

 この基板を使おうかというレベルの読者には何のたしにもならないSDカードソケットのハンダ付けの方法が何故か詳しく写真付きで解説してあったり、別売りの拡張基板の紹介にはページが沢山割かれているが、どうも何かずれている。せめてUSBの仮想COMポートのAPIの紹介くらいないか隈なく記事を探したが、それもない。やれやれ、ソースを見ろと言うことか。

 記事はあてにならないことがわかったので、CD-ROMにあるサンプルプログラムのVirtualComPortのソースを調べ始めた。これは、ComPortになったUSBインタフェースからの送受データを、標準UARTのひとつとやりとりしているソフトである。例の長ったらしい変数と関数名をひとつひとつ調べて動きを追う。その結果、プログラムの構造がデバイス単位の割込み駆動になっており、これを母体に必要な処理を各割り込みルーチンに入れていけば、PCコンソールとのコマンドのやりとりで動くモニター程度は作れそうなことがわかった。

 さらに7月号のフォトフレーム製作記事を読むうち、FATライブラリーもあることがわかった。早速ソースコードを出版社のサイトからダウンロードする。記事には説明がないので、これも、ソースからの解析が必要だ。いやいやAVRと同じような状況にするまでにはまだ相当時間がかかりそうである。

ブログのコメントでAVRに戻る(1/8/09)
 いよいよSTARMでの開発を始めようかと考えていたとき、ブログに「Mega168にはSPIにもなるUSARTがあるはず」というコメントが上がった。確かにその通りだが、このUSARTはデバッグ用に既に使っており、データシートのボーレートの表を見ても、みな2Mbpsどまりなので諦めていた(ボーレートはクロックの1/8)。しかし、このコメントを見て、もういちどデータシートを詳しく調べ直してみたら、これは非同期のときで、SPIにすると、何と速度は、クロックの1/2までの速さで動くと書いてあるではないか。

 これは、これは、気がつかなかった。ここに宝物が埋まっていた。SPIがあればDACのデコードは直打ちに比べ圧倒的に早くできる。光が差してきた。

 STARMの研究を中断し、AVRに戻る。プログラムのデバッグ用のUARTを別のGPIOで組み直す作業に着手した。 初期に作ったソフトUARTが役に立つときである。空いているPORTCの適当なピン2つを送受ピンにしてソフトUARTを移植する。単純に移植できると考えていたが、そう簡単ではない。このソフトUARTはISPピン用でデータが正論理になっている。これを本来の負論理に替える開発が残っている。

 これが結構、難物だった。年のせいでプログラムの中の細かいロジックをみんな忘れているのである。まず送信が出来ない。たいして複雑なコードではない。データの負論理化は上手く行っているのに、どうしても正しいデータがPCに来ない。悩んだ挙句、ロジアナのお世話になる。タイミングチャートを見ていてデータラインの初期値がLowであることに気がついた。UARTは非同期(スタートストップ式)の負論理なので、初期値はHighにしておかなければいけない。スタートビットがわからなくなる。

 受信側も手こずった。アセンブラールーチンにばかり気をとられて、Cで書いた割込みプログラムのチェックを忘れていた。ピンチェンジ割り込みは、あらゆるピンの変化で割り込みが起きるので、特定の割込みだけに反応するようにCのプログラムでフィルターをかけている。ここでもスタートビットの論理を逆にすることに気がつくのにえらい時間がかかった。結局、UARTの移設は半日仕事になった。Webbook

 遅くなった理由は他にもある。久しぶりに新しいサブノートPCを新調したのだ。ネットブック(EeePC S101)である。それとこれにつけるポータブルDVDドライブ(DVSM-P58U2)。10インチディスプレイのサブノートPCが6万円台で買えてしまう時代である。このあたりの技術は、少しフォローを怠っている間に、驚異的な進歩を続け、追いつくのに大変だ。DVDはいつのまにか2層の8GBになっているし、無線LANどころか、Bluetooth、ウェブカメラまでが、標準でついている。Let'sNoteの初期のサブノートを30万近く出して買ったのは、10年ちょっと前の話だ。久しぶりのPCまわりの買い物に電子工作のほうが少しご無沙汰になった。

遂にPCMオーディオの再生に成功。しかしひどい音(1/9/09)
 去年の暮から取り組んでいたSDカードから読むPCMオーディオファイルの再生に遂に成功した。音はまだ歪みだらけのとても聞けたものではないが、とにもかくにもMega168とDACチップだけで、SDカードを読んで、16ビットステレオDACが動いた。いや嬉しい。

 きっかけは、前にもお世話になったブログのkugaさんのコメントである。デバッグ用のUARTがソフトUARTを使って他のピンで動いたので、空いたUSARTをデータシートどおりMSPI(マスターSPI)に変更した。Atmelのデータシートは、この部分がかなり詳しく書かれており、設定はとても楽だった。設定さえ出来れば、割込みルーチンのコードはもっと簡単である。SPIのデータレジスターに2バイト放り込んだ後、送信終了を確かめることなく直ちに本体に帰るだけである。LRCKのトグルは、割込み直後に行う。サンプリング周期を厳密に守るためと、一刻も早く割込みを抜けてオーバーヘッドを減らすためである。送ったデータのデコードは次のサンプリングで行われ、ファイルアクセスとDACデコードは同時に動くことが可能になる。

 出力ピンをロジックアナライザーに接続し、動かしてみる。おお、やった、やった。見事にデータが想定どおり出力され、WAVファイルも最後まで読んだ。割込みのオーバーヘッドはどうだ。うむ、バッファーにデータを放り込むだけなので、1.8μsしかかかっていない。これは優秀だ。LRCKのトグルとデータ送り込みの間に時間がかかっているのがちょっと気がかりだが、タイミングチャートとしては完全だ。Sdpcm_ok

 いよいよ、アナログ出力の検証である。ヘッドフォンをBU9480Fのoutputにつなぐ。出た。いやシャーッというノイズだけでまだ音になっていない。ただ、音をだしていると思われる期間だけのノイズなので何かしら出力が出ていることには間違いない。これはアナログではなくてデジタルの問題だ。

 タイミング的には、全く問題ない。16ビットが正確にLRごとに出ている。そうするとデータか。WAVフォーマットをもういちどチェックする。なになに、データは「インテルフォーマット」とある。む、もしかしてリトルエンディアン? DACのデータシートを見る。こちらはMSBファースト。えーっと、これ違うよね。あわててウェブで確かめる。

 そうだった。インテルフォーマットとは、リトルエンディアンでLSBファーストのことだ。これが原因か、音がノイズになるのは。2バイト送り出す順番が逆になっているからだ。あわてて順序を変えコンパイルし直す。

 ヘッドフォンをつないで音を出してみる。よーし、それらしい音がでた。音は歪みだらけで、まともな音になっていないが、確かにPCからSDカードに移したWAVファイルの楽器の音である。非圧縮PCMオーディオには程遠い音とはいえ、とにかく一旦は諦めたAVRでのデジタルオーディオ再生に成功した瞬間である。ささやかな成功の余韻に浸る。kugaさんありがとうございました。

 さて、これから本来のPCM音声にする作業が残っている。デジタルのところは少し調べようがないが、アナログはまだ何も手が付いていない。ヘッドフォンを直接DAC出力につないだだけである。適当なローパスフィルターとアンプでDACに負担をかけないように音をだせば、良い音に戻るのではないか。正弦波のWAVデータを作ってテストすれば解決が早いかもしれない。

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

2009年1月 5日 (月)

非圧縮オーディオはやっぱり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命令だけを入れ、ロジックアナライザーで、本当に最初から割り込みがかかっているのか確認することにする。結果は割り込みはかかっていないことがわかった。しかし、今度は割込み部を入れてもファイルの初期化が問題なく終わる。おかしいな。前は入れただけで動かなくなったのに。Dac104

 何故かいつのまにかファイルアクセスが正常に戻ってしまったのである(このあと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ブロック目でストップしている。Dac105

 44.1khz、16 bit ステレオの非圧縮オーディオの再生は、やっぱりクロックが20Mhz程度のAVR単独でやることは不可能のようだ。まあ、ステレオでなく片チャンネルだけの再生は出来るかもしれないが、このプロジェクトは残念ながらとりあえずここで中断することにする。

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

« 2008年12月 | トップページ | 2009年2月 »