« リニアPCMプレーヤー3号機の開発 | トップページ | SDカードプレーヤーの演奏中の時間表示に成功 »

2010年1月 4日 (月)

マルチタスクにしたプレーヤー3号機の開発状況

あけましておめでとうございます。
 がた老AVR研究所も発足以来2年が経過し、おかげさまでアクセスが月に1万アクセスを超える、そこそこのブログに育ちました。組み込みコンピューターを中心とした電子工作の気ままな制作の過程をなるべく詳しくご紹介することをモットーにしています。

 これは、所長が現役時代に大規模システムの開発を職業としていた経験から、自分のやっている試行錯誤は、たとえどんなくだらないことでも必ず誰かの何かの参考になるという自信にもとづくものです。

 このブログを知る知人からは、「レベルが高いのか低いのかわからない」「文章が長すぎる」などのご批評をいただいていますが、技術的な情報を提供するブログをもともと目指しているわけではありません。少し偉そうに言えば、所長のかっての専門分野である「問題解決」のさまざまなアプローチを、電子工作を通じて楽しみながら紹介できれば望外の幸せというものです。

 これからもよろしくお願い申し上げます。

さて、本記ですが、現在のプロジェクト、リニアPCMプレーヤー第三版の制作は、年末に身内に不幸があったりして目だった進展はありません。備忘録的にこれまでの出来事をご紹介しておきます。

2回目のOlimex基板発注(12/21/09)
 リニアPCMプレーヤーの2つ目の基板は、12/21にEAGLEのボードファイルを添付してOlimexに注文申請メールを発送した。すると親切にも例のTsvetan君から、

Did you read about our Holidays?
Tsvetan / Olimex

と返事が来た。
あわててOlimexのトップページを読み直す。

お休みは12/24から1/4までだよ、12/17以降の発注(PO)は、出荷が1月になるよ。というメッセージしかない。
(We are closed 24-th of December to 4th of January.  PO forms sent after December 17th will be shipped in January)

別に年内に基板が欲しいわけではない。
「お宅の休みが24日からなのは知っている。17日以降のPOが来月送りになるのもね。
何か言うことある?(Do you have any other suggestion?)」とちょっといやみな返事を出す。

それきり返事はなかった。もしかすると怒らせてPOformが送られてこないかもしれない。少し心配する。

 とにかく、これでLPCMプレーヤー3号機のハード工程は一段落した。電池基板ケースも2個分の切り出しが終わった。ミニサーキュラソーは快調だが、標準の丸鋸の刃でプラスティックを切ると荒らすぎて切り口がきたなくなり整形が面倒だ。あさりのない細い刃の方が綺麗に切れそうなので、入手するまでそれ以上の作業は中止することにした。しかし、お正月の準備が忙しく、なかなか買い物にいけない。

マルチタスク化はジッターが心配(12/24/09)
 演奏中に経過時間などを表示するマルチタスク化は、実現の見通しがたったが、いざ実際の開発に入ろうとして、マルチタスクのTick割り込みによって起きる、DACの割込みのゆらぎが気になってきた。いわゆるジッター(サンプリング周波数のゆらぎ)である。

 少なくとも、これまでのリニアPCMプレーヤーにはDACの割り込みを妨げる処理はない。理論上はCPUクロックのゆらぎ以外にジッターは起きない理屈である。音質が売り物の今度のプレーヤーだ。いくら発生頻度が低くても、マルチタスクにして経過時間を表示した結果、折角の音質が損なわれてしまうのでは改善の意味がない。

 CDプレーヤーから直接聞くより、一旦PCにリッピングしてディスクからWAVファイルを聞くほうが音が良いというのは、CDプレーヤーのドライブでエラーなどでジッターが起きるからだと言われている。高級な音楽CDドライブは必ずバッファーを設けてクロックを揃えたりする。

 しかし、今度のマルチタスク化によって、DACの割り込みは、SDカード読み込みの割込みで少ない確率ながら遅れる可能性が出てきた。これが音質を左右するほどの遅れになるのかが問題だ。

 ウェブの情報を漁る。まずジッターの単位が良く分からない。UIというのはUnit Intervalの略で、サンプリング時間を1としたときの、ゆらぎの時間だという。一方、psという単位もある。ピコセカンドという秒の単位だ。これは絶対値で、サンプリング周波数が変われば当然変化するので同じサンプリング周波数でないと意味がない。

 デジタルオーディオの世界で有名な、シーラスロジックのCS8416というトランシーバーICのジッターは、業界最高水準という200psを謳っている。この石のサンプリング周波数は192khzなので、UIに換算すれば、0.00004UIということになる。

 一方、現在のリニアPCMプレーヤーのクロックの水晶発振子の精度は数百ppm(百万分の1)で、DAC(BU9480F)のサンプリング周波数、88.2khz(2倍オーバーサンプリング)も、これに比例して変動し、UIでいうと0.0002(200ppmとする)、psで言えば、1/(88.2*1000)*200/100000=22000psである。かなり大きい。

 現在既にこの程度のジッターは出ている。従ってこれより少ないジッターに押さえることが出来れば、今回のマルチタスク化による割込み遅れは無視できると言えるだろう。業界最高水準と争うのは無意味だ。

 恐る恐る計算を始める。まず、割込みによって遅れる時間の見積もりである。WINAVRの説明によれば、割込みが起きて割込みプログラムにジャンプするとき、CPUはハードウエアでSREGレジスターをリセットし、ここで割込みが禁止になる。このあとレジスターなどをセーブし実際のユーザーの割込みプログラムに制御が渡るが、ISR_NOBLOCKオプションではジャンプの直後にSEI命令を置いて、すぐに割込みを許可にする。つまりジャンプ1命令とSEI命令の2命令分、クロック20Mhzで100ns遅れる計算である。

 DACのサンプリング間隔、11.33μsからみると、100nsは、UIで0.01となる。相当大きい。しかし、この遅れは常に起きるわけではない。ファイルアクセスが割込みによって2.9msごとに512バイトのセクターを読む時と、その前のバッファーが空くまで空振りする割込みの数回しかおきない。これが11.33μs間隔のDAC割込みとぶつかる確率は、相当低いはずだ。Dack_tick_2

 このぶつかる確率を正しく計算しようとして、このところずっと悩んでいた。まず、ファイルアクセスの開始を監視するTick割り込みは、これまでのチャートから見て、300から500μs間隔で十分余裕があると考えられる。クロック20Mhzの一命令の時間は50nsで、割込みの頻度は、Tickを300μsとして、300/0.05=6000命令に1回である。とても少ない頻度に見えるが、DACの割込みは11.33μsで226命令に一回、この割込みに先ほどのTick割込みが、どれくらいの頻度でぶつかるのかが計算できない。

 単純に考えれば、DAC割込みの26.54回に1回(6000/226=26.54)、Tick割込みがやってくるが、必ずしも常にDAC割込みと重複するわけではない。楽観的に考えれば、DAC割り込みは226命令に1回の頻度なので、1/(26.54×226)のような気もするが、この頻度は、Tick割込みの頻度と同じで、何か0=0を計算している感じだ。

 間違いないところでは、最悪で26.54回に1回(Tick割込みの度に必ずDACとぶつかる)、なので、この頻度をUIに適用するとそのUIは、0.01/26.54 = 0.0003で、水晶発振子のジッターとほぼ同じだ。Tick割込みの度に必ずDACの割込みと被るというのは、ちょっと考えられないので実際にはもっと低い。さっきの計算では、その1/226まで下がる。

 歯切れは悪いが、一応、割込みによるジッターは殆ど無視できるレベルにあると考えることにした。あとは実際に動かして聞いて見るしかない。ジッターの音に対する影響も明確な基準があるわけでもない。あまりこれにこだわることは止めることにする。

バックグラウンドタスクが動いた(12/30/09)
 ジッターの問題があって、実際のコーディングには、なかなか踏み切れなかった。折角苦労して作ってもジッターで音質が台無しになるかもしれない。うまく動いているのをいじりたくない気持ちも邪魔をしている。

 しかし、ハードの方は、Olimexに基板を発注してしまったので、やることがない。少しづつメモに書き出しながら、ロジックを練った。鉛筆で何度も書き直す。細かいフラグまで擬似コーディングし、満を持してAVRStudioに新プロジェクトを定義し、ソースコードを移す。

 バックグラウンドタスクの時間表示は手間がかかるので当面はアクセス回数を表示することにする。擬似コーディングを入念にやったお陰で、ソースの変更は簡単にすんだ。しかし、すぐ音を出す勇気がない。ぐずぐずしていたが意を決してファームを書き込み、祈る気持ちで電源を入れた。

 「LPCM PlayerV4」というWelcomeメッセージが出る。ソフトのバージョンはV4だ。ここまでは何も変えていないから動くのは当然だ。演奏開始ボタンを押す。鳴り出さない。心臓が鼓動を打ってきた。演奏中断を押し、再開ボタンを押す。おおお、SDカードのアクセスLEDが点き、演奏を開始した。

 しかし音は歪みだらけである。この前のアンダーランと同じ現象だ。全く動かないのならともかく、歪むと言うのはどういうことだ。Tickインターバルが想定どおりの時間ではないのか。考えたとおりに動いていないのか。

 時間的な要因なのでUARTで調べるわけにはいかない。ロジアナで実際のタイミングチャートを出した方が早い。I/Oポートに状態を出力するステートメントを要所に入れ、調べることにする。

 久しぶりにロジアナに火を入れる。プローブを割込みルーチンとファイルアクセス部分に入れてタイミングチャートを出す。出た出た。おやあ、ちゃんと想定どおりの動きをしているぞ。正確に300us単位に割り込みがあがり、バッファーが空くとファイルのアクセスを始めている。考えたとおりのタイミングチャートだ。何の問題もない。バッファーのアンダーランもない。何だ何だこれは。Lpcm4

 これで歪むというなら、この読んだデータが正しくないということだ。もう一度ソースを見直す。あっあっあ、割込みルーチンの書き出すバッファーがテレコになっている。これではDACが動いているときに、そこへ書き出してしまうことになる。こりゃ音が歪むのは当たり前だ。あわてて修正し、再度電源ON。おおお、綺麗な音に戻った。音質も全く前と変わらない。

 喜んでいたのも束の間、突然、演奏中の音楽が別の曲に変わる。何だ何だ、これは。こんな器用なことを誰がやる。SDカードを変えても同じように起きる。しかも同じところでは起きない。SDカードのアクセスがおかしい。  読み込むセクター位置が突然変わる感じである。これはどうもスタックのオーバーフローの疑いが強い。

 SRAMの使用バイト数は、1890バイトを越えて、90%を軽く越えている。うーむ、やっぱりこれだ。割込みプログラムは大量のスタックを消費する。こんどのSDカードアクセスの関数は、割込みプログラム上だ。ここのレジスターが破壊されれば、簡単に別のセクターを読む可能性はある。うむ、これに違いない。

 SRAMを減らす作業を開始する。これがなかなか減らない。1バイト変数を節約してもらちがあかない。結局、10ヶあるディレクトリリストを6ヶまで減らして、やっとこの現象は解消された。SRAMの使用率が90%を越えるとスタックオーバーフローが起きるようだ。

 曲リストをスクロールするときディレクトリの読み込みの頻度が多くなるが実用的には全く問題がない。定数ひとつの変更だけでリストの大きさを変えられるようにしておいて助かった。最初は面倒だがこういうときには威力を発揮する。

 演奏は正しくなった。しかし肝腎のバックグラウンドが動いていない。ファイルアクセス数は0のままである。試しに*を移動させるコードに変えてみる。少し待ち時間を入れてLCDが見えるようにする。

 おう、これは動いた。いや素晴らしい。バックグラウンドタスクをこなしながら演奏が続く。しかしコードをカウンター表示に戻すと0のままだ。xprintfがおかしいのか。そんなわけはない。気を落ち着けて調べ直す。変数をグローバル変数に替えている。

 あああ、なーんだ。わかった。ローカル変数にも同じ名前を定義している。これだこれだ。ファイルアクセス部分を割込みプログラムにして、変数をグローバル化したとき、ローカル変数の定義を移すのを忘れていた。良くあるバグのひとつである。A1042600

 ローカル変数の定義を削除してテスト。うむ、音楽を演奏しながら読み込んだセクター数が順調に増えていく。良いぞ。このLCDは表示時間が遅いので余り早くデータを送ると表示コマンドが立て続けに送られて結局何も映らない状態になる。ある程度、表示間隔を長めに(最低50ms)とる必要があるようだ。

 マルチタスク化は、これで峠を越した。あとは経過時間表示の計算と、プログレスバーなどの表示のロジックを考えるだけだ。このあたりはソフト開発でも最も楽で面白いところである。良い年を迎えられそうだ。

|

« リニアPCMプレーヤー3号機の開発 | トップページ | SDカードプレーヤーの演奏中の時間表示に成功 »

AVR」カテゴリの記事

電子工作」カテゴリの記事

コメント

コメントを書く



(ウェブ上には掲載しません)


コメントは記事投稿者が公開するまで表示されません。



トラックバック


この記事へのトラックバック一覧です: マルチタスクにしたプレーヤー3号機の開発状況:

« リニアPCMプレーヤー3号機の開発 | トップページ | SDカードプレーヤーの演奏中の時間表示に成功 »