« 2009年1月4日 - 2009年1月10日 | トップページ | 2009年1月18日 - 2009年1月24日 »

2009年1月11日 - 2009年1月17日の2件の記事

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月4日 - 2009年1月10日 | トップページ | 2009年1月18日 - 2009年1月24日 »