« 秋月FG用の周波数カウンターをつくる | トップページ | 周波数カウンターと秋月FGキットの合体 »

2008年11月 3日 (月)

2方式の周波数カウンターを2313で動かす

基本的な誤り(10/29/08)
 どうもおかしい。クロック20Mhzのマイコンの周波数計測が最大1Mhz以下というのはどうみてもおかしい。Webでもういちど調べてみた。こんなにみんな苦労していない。CPUクロックの半分の周波数は測れると書いてある。どうしてだろう。あああ、なんだ、わかった。カウントを数える直接計測はもっと簡単な方法があるのだ。タイマー/カウンターの機能に、外部クロックによるカウンターの駆動というのがあるではないか(だからカウンターなのだ)。今まで何と言う無駄なことをやっていたのだ

 やれやれ、おかしいと思った。これを使えば、少なくともクロックの半分くらいまでは測れるはずだ。プログラムを大幅に変更することにする。ただし、カウントするだけなので、計測時間が0.1秒なら分解能は10hzになるし、低周波では最低でも1秒は測らないと使い物にならない。これまでのレシプロカル方式で、時間を内部クロックで測りなおすという2本立ての測定ルーチンが必要になる。メモリが足りるかどうか。

 メモリのことはあとで考えるとして、カウンター入力によるプログラムをコーディングする。こちらのロジックは滅法簡単で、一定時間のゲートを開けてカウントするだけである。あっけなく出来た。動かしてみる。おお、10Mhzまでなら楽々測定できる。10Mhzがほぼ測定限界で、11Mhzではかえって周波数が落ちる。ハングはしない。

 計算を楽にするため切りの良い時間を作るのに良いタイマーの設定が見つかった。CPUクロック20Mhzで、8bitタイマーのプリスケールを64にしてTickを3.2μsにすると、122回(256×122×3.2=99.9424ms)まわした端数が18(0.0032×18=0.0576ms)できっちり、0.100秒になる。クロックが正確ならどこまでも0.1秒である。

 オシロとの周波数の誤差は全くなかった。温度特性はわからないが使っているクリスタルは一ヶ¥50 の普及品なのに立派なものである。少なくともオシロの表示する数字とは完全に一致している。1桁ほどこちらのほうが細かい。満足満足である。ただ前にも書いたように、あくまでも周波数測定ではなく、シグナルジェネレーターの周波数表示用のために作っている。なるべく早いタイミングで計測をしたい。とすると分解能を上げるためには、前に作ったレシプロカル方式のロジックを併用する必要がある。どのあたりでこの直接計測に切り替えるか、レシプロカル方式の測定期間をどの程度にするか、調べなければならないことが沢山でてきた。

 まず、レシプロカル方式は、どれだけ細かい時間まで計測できるかが、有効桁数を上げる決め手になるので、CPUのタイマーをプリスケールなしの最高速で動かすことにする。しかし有効桁数を上げるため大きな数字を取り扱おうとすると、計測時の変数は簡単に2バイトの上限(65535)を超えてしまう。4バイトデータのやりとりは2バイトのときよりはるかにステップを喰うので使うわけにはいかない。おのずと測定期間や最大測定カウント数が決まってきた。

 プログラムロジックは最初のプログラムとほぼ同じで、パラメーターを変えるだけだったので、プログラムはすぐ動き始めた。フラッシュサイズは2方式の測定、UARTを入れても1800 バイトどまりでLCDに切り替えても何とか入りそうである。

 UARTに直接計測で出した周波数と、新しいレシプロカル方式で出した周波数を並べて表示し、テストに入った。測定範囲が5Hz(レシプロカル方式の測定期間による下限)から、500Khz(I/Oポート入力を繰り返すループロジックの上限)ととんでもなく広いので、チェックしていくのに時間がかかる。

 最初にでてきたデータは、あっているところが少しある程度で、どこも全部違っていた。直接計測の方は、10Hzの分解能ながら見事に10Mから低周波まで、オシロが出す周波数と一致している。これはすごい。それに対して、レシプロカルは不安定極まりない。同じ周波数でも測るたびに違うし、第一合っていない。まあ、これからが勝負だ。少しづつバグをつぶしていこう。

 まず、すぐ分かったのは、タイマーオーバーフローのキャリーフラグ上げと測定時とのタイミングの違いによるミスである。何しろタイマーをCPUのクロックと同じ最速(0.05μs)で動かしている。測ったときとタイムアウトしたときのキャリーを一致させるため、やりたくなかったが、ループの中に時間記録と同時にキャリーも保存するステップを加える。

 次に頭を悩ませたのが、周波数帯の一部で、突然、測定周波数が不正確になる現象である。これは、UARTに途中経過の変数を逐一表示させ、数字をチェックして、4バイトのデータの桁あふれを見つけた。4バイトは10進数で9桁あるのだが、計算の段階の、ある変数の範囲で10桁になることが分かった。

 マイクロセカンドの世界なので通常の数が6桁、除算は乗算より桁を取らないとはいえ、うまく分割して計算しないと、32ビット(4バイト)でも難しい。周波数を出すのに一回の計算ではできないので、始め3回分けて計算していたのを工夫して2回に減らしていたがその配分がまずかった。WINAVRで64ビット変数が使えることを発見し、喜び勇んで入れてみたら、フラッシュサイズがいきなり5Kを超えて唖然とする。そう世の中は甘くない。775

ロジアナさまさま(11/01/08)
 細かいバグを追いこんで、段々レシプロカル方式も精度が上がってきた。しかし、キャリーの食い違いによる誤った周波数表示は稀にだが起きるし、周波数が低くなると全く不正確になる。どうも一回分パルスをミスしているようである。2回に分けた計算法も自信がない。Webに助けを求めるが、出てくる記事は、大掛かりな多倍長演算の手法ばかりで、こうしたちょっとした多数桁の計算のヒントになるようなものはない。

 特に低周波が不正確なのは痛い。直接計測では1秒測らないと最小桁が出ないので、このあたりはレシプロカルに頼るしかないのだが、これが安定しない。こんな低い周波数のところで、1周期見逃すはずがないのだが、結果は見逃した形になっている。キャリーの食い違いは、どうしても起きることがあるので、とうとう計測ループの中に割込み禁止命令を挿入して対処した。これで最大測定周波数は500Khz以下に下がってしまったが背に腹はかえられない。

 低周波の方は万策がつきた。とうとうロジックアナライザーの登板をあおいだ。ソースの上では数命令先だが、もしかしたら意外な時間をとっているのかもしれない。割り込みがかかって別のところにいくのかもしれない。実際に確かめてみようと言うのである。要所、要所に、ピンをドライブするsbi(PORT,PIN)などの命令を挿入し、そのピンにロジアナのプローブを接続して動かしてみた。

 机上には、オシロ、シグナルジェネレーター、ブレッドボード、アッテネータ、ロジアナなど所狭しと機材が並ぶ。いくつか挿入ポイントを変えてテストするうち驚くべき事実が明らかになった。

 測定期間にはいったあと、最初のパルスを確かに一回見逃しているタイミングチャートがでてきたのである。ほんとだ、タイムアウトのときに何かおかしくなると予想していたが、最初でまるまる1パルスをとっていない。一体これは何だ。何故最初の立ち上がりだけ見逃す? うわあー、わかった。立ち上がりパルスかどうか決めるスイッチ(前の状態を保存)を測定の前でクリアしていない。プログラムが動く最初は初期化しているが、このルーチンは無限ループの中にあるので、その都度、クリアしておかないといけない。

 わかってしまえば、馬鹿みたいな原因である。前回の測定終了後のスイッチの状態で、たまたま正しくなったり間違ったりする。不安定な状態に見えるが原因は単純なミスである。今回は、タイマーのお守りに注意が集中し、割込み要求のマスクや、レジスタ設定と初期化などには熱心にチェックしていたが、ここまでのチェックを怠っていた。Photo

 それにしても、ロジックアナライザーが大活躍である。その威力をあらためて実感する。そうか内部でわからないときはこうしたプローブ点を作ればいいのだ。ひとつ勉強した。嬉しくて、電源を切るときロジックアナライザーに深々と頭を下げてお礼をした。

 これで、周波数カウンターの開発は峠を越した。必要部品も確定したので、安心してケースの工作にも入れる。25Mhzまでの計測は最初、リレーかなにかで10Mhz以上を4分周に切り替えて測ろうと思ったが、少し大げさすぎるので、直接計測式はすべて4分周で400khz以上を測り、それ以下はレシプロカル方式で測定しなおすことにする。直接計測は測定期間をこれまでの4倍(400ms)にすれば、当初の10hzの分解能は確保できるはずだ。

なんとかTiny2313に納まった(11/03/08)
 ロジアナのおかげでトラブルも収束し、直接計測式も、レシプロカル式もほぼ正確に周波数が出るようになった。次は、テスト用のUARTから、実装用のLCD表示に切り替える作業が待っている。しかし、フラッシュサイズはもう2Kバイト近くで余裕がない。祈るような気持ちで、UARTのライブラリをはずし、LCDを組み込む。

 コンパイルしてみる。やっぱり2Kバイトを超えてしまっていた。8桁の周波数を表示するためchaNさんのxatoiのライブラリを利用させてもらっている。書式付の出力関数(xprintf)は特に便利で楽なのだが、コードを喰うのが難点で、xprintfのステートメントひとつで100バイト近く増えるときがある。

 テスト用にいくつか書いていた出力関数をひとつに減らし、ライブラリにある使っていない関数をコメントアウトしたりして、何とか2K(2048バイト)以内におさめた。動かしてみる。と、また、全くLCDが反応しない。やれやれ、今度のLCDライブラリはピンの配置を自由に選べる最新版で問題ないはずだがと、ソースを見る。あーっ、単純にループする待ち時間が調整されていない。今度のプログラムは最速の20Mhzである。LCDはビジーフラグが動く前の段階の初期化に、一定の待ち時間を作らないとうまく動かない。そうか、これもコンパイラーオプションのF_CPUなどを使って自動的に変わるようにしないといけないな、と、このころは余裕を持ってデバッグしていた。

 しかし、その後もLCDは頑として動こうとしない。ビジーフラグを見るルーチンもはずしてみたが駄目、ウェイトの時間を増やしても駄目、コマンドenableの間隔を変えても駄目。配線の導通チェックも異常なし。UARTで状況を見たくても、もうメモリがない。だんだん顔が青ざめてくる。調べるところがなくなって、またロジアナに助けを求めることにした。

 そのときふと、データシートの表紙が目に留まった。Tiny2313には2つ種類があって、10Mhzまで動く低電圧版のTiny2313Vと、Vなしの20MhzまでのTiny2313がある。あーっ、私が秋月から¥100で買ってきた2313は低電圧版の2313Vだ。しかし、今までの何の問題もなく動いていた。UARTのときはピンが少ないので20Mhzでも動いたが、LCDのような多ピン駆動のときはロードがかかって駄目になるのだろうか。あわててオシロでクロックを確認する。少し電圧が低いけれど、クロックは20Mhzで動き、波形の乱れもない。

 ロジアナで見てみよう。動いていなければ買いなおしだ。確か、普通版の2313も秋月では¥100の値段に変りはなかった。どきどきしながらロジアナをつなぐ。これが、何と、ちゃんとというか、所定の初期化のコマンドシーケンスを送っている。しかし、初期化した後、全く反応がない。へえ、低電圧版でも20Mhzで動くんだと妙なところで感心するが、先が止まっていることに変りはない。

 これはもうLCDが原因ではない。何か別の原因でプログラムがスタックしている。試しにメインループに入る前にLCDにテストメッセージを出してみる。LCDが動いた!やっぱり、他の原因だ。どこを直した? UARTの部分をとりはずしただけである。それ以外に不要と思われるステートメントはフラッシュ節約のために色々変えた。そういえば初期化の割込み禁止のステートメントもはずした。ついでに解除(sei())のステートメントも。

 ええー、割り込みは禁止にしない限り、解除を入れる必要はないよね、と思いながらも半信半疑で元に戻して動かしてみる。驚くべきことに、これで動いたのである。タイマーの割込みが入らないのでスタックしていたのである。割込みを使うときにはsei()が必ず必要とは全く考えもしなかった。やっぱりバグは外に潜んでいたのだ。今日の朝からのトラブルがこれで解決した。Pict0778

 やっとのことでLCDに周波数が表示された。表示用だから更新間隔は短いほうが良いと最初考えていたが、余り早いと、下2桁くらいが見えなくなり、こういう表示は0.5秒くらいが一番見やすいことがLCD表示をさせてみて始めてわかった。

 しかし、フラッシュサイズはほぼ満杯の状態でこのままでは何も出来ない。メモリリダクションの作業に入る。まず、8桁の数字の一行表示だけに機能の豊富なxatoiライブラリを使うのは勿体無い。自前のルーチンを作る。これで200 バイト近くを減らした。次はLCDライブラリである。ピン配置が自由だけれどサイズは少し大きくなっている。これを今までのライブラリに切り替える。こちらは150バイト近くのメモリ節減になった。

 この余ったメモリを、やりたかった低周波数での小数点以下の表示に150バイトほど費やして、結局フラッシュサイズは、1926バイトに納まった。Tiny2313で、5hzから10Mhzまでの周波数カウンターのソフトの完成である。何とか、2313の2Kバイトのフラッシュに押し込むことができた。Pict0780

 直接計測からレシプロカルの切り替えは500Khzで自動に行い、11Mhzあたりまでこれだけで測れる。20MhzまではカウンターICで4分周して使う予定でこれは実装のときに細かいことを決めるつもりだ。分解能はレシプロカルはタイマーTickが0.05μsで、0.2秒ほど測っているので、上限の500khzあたりでも1hz近辺(理論上)。直接計測も0.2秒の測定ゲートで分解能は5hzとなっている。4分周するときは、測定ゲートを倍くらいにして分解能を10hz以下にしたいと思っている。

ここにTiny2313の周波数カウンターのソースコードをAVRstudioのプロジェクトファイルの形で置いておきます。ピンアサインはソースのコメントをご覧下さい。PD5がカウンター入力であることが変わっているだけで、それ以外は変わったところはありません。回路図は全体が完成してから公開する予定です。なお、入っているLCDライブラリのLCD.cとLCD.hは、名前は同じですが、最新のものとは中身が変わっています。ご注意ください。

「FCTR2313.lzh」をダウンロード

|

« 秋月FG用の周波数カウンターをつくる | トップページ | 周波数カウンターと秋月FGキットの合体 »

AVR」カテゴリの記事

コメント

外部クロックだとそんなに規格外でも動きますか。恐らく低電圧版と通常版は発振機構のところだけが違うのでしょう。Mega128は16Mhzが上限ですが、20Mhzでも問題なく動くようですし、Mega168(Max20Mhz)はこのあいだ24Mhzで動かして平気でした。まあアマチュアが動かしてみるだけと言うのなら結構大丈夫なようですね。

投稿: がた老 | 2009年3月 6日 (金) 20時13分

記事を興味深く拝見いたしました。
実は無印2313と2313Vの違いについて検索していてココに辿り付いたのですが、
私は当初、無印とVは同じ物で検査時の仕様の違いだけで刻印を変えていると
考えていたのですが、ある日10MHzと20MHzのセラロックを交互に付け替えて
動作テストしていましたところ、同じヒューズビット設定で同じプログラムを
書き込んでいるにも関らずVと20MHzのセラロックの組み合わせでテストした
場合のみプログラムが正常に動いていない事が発覚いたしました。
耐クロック特性を見るために外部クロック供給にしていた場合は両方とも
40MHzくらいまでは動作していたので、どぉやら発振を構成している回路の
時定数設定に違いがあるような感じです。

投稿: | 2009年3月 5日 (木) 22時42分

コメントを書く



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


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



トラックバック


この記事へのトラックバック一覧です: 2方式の周波数カウンターを2313で動かす:

« 秋月FG用の周波数カウンターをつくる | トップページ | 周波数カウンターと秋月FGキットの合体 »