ロジックアナライザーでタイミング合わせ

ロジックアナライザーで、タイミング合わせをしてみました。アナログ信号の場合、オシロスコープを使って波形を観察します。しかし、デジタル信号の場合、オシロスコープではやりづらい部分があります。デジタル信号の場合、波形そのものの重要性は高くありません。それよりも、他の信号との関連が重要となるため、より多くの信号を同時に扱う必要があります。また、信号をデコードして、信号の内容を表示する機能もあると重宝します。つまり、オシロスコープとは、少し違った見方で、信号を観察する道具が、ロジックアナライザーです。
激安ロジックアナライザーを買いました
Arduinoをいじり始めてから、ロジックアナライザーが欲しくなりました。しかし、まともなロジックアナライザーは高価で、私には手が出せません。そこで、困ったときのアリエクです。
早速目に飛び込んできたのは、500円以下のロジックアナライザーです。



この商品は、ロジックアナライザーというよりも、デジタル入力インターフェイスといった方がよいでしょう。これをPCに繋いて使用するようです。この手の中華製品ですから、説明書も保証書もなく送られてくるはずです。したがって、肝心のソフトウエアについては、自前で調達するしかありません。
もちろん、万一動かなかったとしても自己責任です。しかし、中華製品に共通する、「as isだけど無茶安だよ」という精神は結構好きです。
到着した商品を見てみる
中国から届いたロジックアナライザーは、見慣れた銀色の袋に入っていました。



中身は非常にシンプルで、本体とUSBケーブル、プローブ代わりのケーブル10本です。



いつものとおり、説明書も品質保証書もありません。そして、肝心のソフトウェアも同梱されていません。使用方法はネット検索をして、見つけなければいけません。ネット検索のキーワードになるのが、製品のモデル名です。



本体には「Analyzer 24MHz8CH」としか書かれていません。かなりざっくりしています。しかし、検索してみると、結構出てきます。片っ端から見ていったところ、どうやらPulseViewというアプリが使えるようです。
ロジックアナライザーのアプリを入手する
PulseViewの開発を行っている、sigrokのページに飛んでみました。すると、サポートしているデバイスの一覧に、購入したロジックアナライザーらしきものがありました。



早速、ソフトウェアをダウンロードしました。



ダウンロードして、インストールしたのですが、MSVCP100.DLLが見つからない旨のエラーが出ます。これは、Visual C++の再配布可能パッケージが、インストールされていないために生じるエラーです。これは、マイクロソフトのサイトからダウンロードできます。
ロジックアナライザーを早速使ってみた:解決すべき問題
試しに、Arduinoにある三つのタイマーの同期をとってみようと思います。Arduinoでは、タイマーを使って、PWM信号を発生させることが出来ます。しかし、三つのタイマーの同期をとることが、これまで上手くいきませんでした。同期がとれていない状態を、ロジックアナライザーで取得してみました。



タイマーAとBのスタート位置は合っていますが、タイマー0,1,2のスタート位置が一致していません。つまり、三つあるタイマーカウンターTCNT0、TCNT1L、TCNT2の値がバラバラだということになります。
そこで、以下のコードをスケッチに追加してみました。
// タイマ同期
TCNT0 = uint8_t(0);
TCNT1L = uint8_t(0);
TCNT2 = uint8_t(0);
三つのカウンターをゼロリセットしてみました。その結果がこれです。



いい感じになりました。
ロジックアナライザーを早速使ってみた:ズレ時間の計測
三つのタイマーを、ゼロリセットすることで、大まかに同期は取れました。しかし、よく見ると少しずれています。拡大して、どのくらいずれているのかを計ってみましょう。



拡大した信号のスタート部分にマーカーをつけて、ズレ時間を測定してみました。なお、マーカーを使う方法以外に、カーソルをあてて計測する方法があります。しかし、カーソルの場合二点間の計測しかできません。今回は三点の計測をしたかったので、マーカーを使いました。
マーカーAの右側のマーカーに+125nsと表示されています。そして、三番目のマーカーには、250nsと表示されています。
つまり、Timer1のリセットは、125nsオフセットした設定をしなければなりません。また、Timer2については250nsオフセットさせなければなりません。
Arduinoのクロック周波数は16MHzですので、1クロックサイクルは62.5nsです。すると、Timer1は125ns/62.5nsですので、ぴったり2クロック遅延していることになります。そして、Timer2は250nsですので、4クロックの遅延です。これをスケッチに反映してみました。
// タイマ同期
TCNT0 = uint8_t(0);
TCNT1L = uint8_t(2);
TCNT2 = uint8_t(4);
計算どおり、Timer1を2クロックオフセットしました。また、Timer2については4クロックオフセットしました。その結果はこんな感じです。



ロジックアナライザーを早速使ってみた:最後はエイヤで治す
2クロックずつオフセットした結果、ズレは減少しました。しかし、完全にズレを無くすことはできていません。そこで、オフセット量をもう少し大きくしてみました。
スケッチは、こんな風に修正しました。
// タイマ同期
TCNT0 = uint8_t(0);
TCNT1L = uint8_t(3);
TCNT2 = uint8_t(6);



ビンゴです。信号のスタートが、ぴったり一致しました。
これで、デューティー比が異なる6つの同期した信号を、同時に出すことが出来ました。信号全体はこんな感じです。



今回使用したスケッチはこんな感じです。
void setup() {
// put your setup code here, to run once:
// timer0のセッティング
TCCR0A = 0; // タイマー0コントロールレジスタAをクリア
TCCR0B = 0; // タイマー0コントロールレジスタBをクリア
TCCR0A |= (1 << WGM01) | (1 << WGM00); // タイマー0をmode3 fast PWMモードに設定
TCCR0B |= (0 << WGM02); //
TCCR0A |= (1 << COM0A1) | (0 << COM0A0); // D6 SET on BOTTOM,reset on MATCH
TCCR0A |= (1 << COM0B1) | (0 << COM0B0); // D5 SET on BOTTOM,reset on MATCH
TCCR0B |= (0 << CS02) | (0 << CS01) | (1 << CS00); // プリスケーラー 1/1
TIMSK0 |= (0 << OCIE0B) | (0 << OCIE0A) | (0 << TOIE0); // 割り込みは使用しない
OCR0A = 37; // duty factor 1/7
OCR0B = 73; // duty factor 2/7
// timer1のセッティング
TCCR1A = 0; // タイマー1コントロールレジスタAをクリア
TCCR1B = 0; // タイマー1コントロールレジスタBをクリア
TCCR1A |= (0 << WGM11) | (1 << WGM10); // タイマー1をmode5 8bit fast PWMモードに設定
TCCR1B |= (0 << WGM13) | (1 << WGM12); //
TCCR1A |= (1 << COM1A1) | (0 << COM1A0); // D9 SET on BOTTOM,reset on MATCH
TCCR1A |= (1 << COM1B1) | (0 << COM1B0); // D10 SET on BOTTOM,reset on MATCH
TCCR1B |= (0 << CS12) | (0 << CS11) | (1 << CS10); // プリスケーラー 1/1
TIMSK1 |= (0 << OCIE1B) | (0 << OCIE1A) | (0 << TOIE1); // 割り込みは使用しない
OCR1A = 110; // duty factor 3/7
OCR1B = 146; // duty factor 4/7
// timer2のセッティング
TCCR2A = 0; // タイマー2コントロールレジスタAをクリア
TCCR2B = 0; // タイマー2コントロールレジスタBをクリア
TCCR2A |= (1 << WGM21) | (1 << WGM20); // タイマー2をmode3 fast PWMモードに設定
TCCR2B |= (0 << WGM22); //
TCCR2A |= (1 << COM2A1) | (0 << COM2A0); // D11 SET on BOTTOM,reset on MATCH
TCCR2A |= (1 << COM2B1) | (0 << COM2B0); // D3 SET on BOTTOM,reset on MATCH
TCCR2B |= (0 << CS22) | (0 << CS21) | (1 << CS20); // プリスケーラー 1/1
TIMSK2 = (0 << OCIE2B) | (0 << OCIE2A) | (0 << TOIE2); // 割り込みは使用しない
OCR2A = 183; // duty factor 5/7
OCR2B = 219; // duty factor 6/7
// DDR(Data Direction Resystor)の設定
DDRD |= 0b01101000; // D3,D5,D6を出力モードに設定
DDRB |= 0b00001110; // D9,D10,D11を出力モードに設定
// タイマ同期
TCNT0 = uint8_t(0); // Timer0をリセット
TCNT1L = uint8_t(3); // Timer1は8ビットモードなのでTNCT1Lのみ3クロックオフセット
TCNT2 = uint8_t(6); // 3クロック2回分、計6クロックオフセット
}
void loop() {
}
デコード機能を試す
今回購入したロジックアナライザーは、ワンコインで買える安物です。しかし、有志の手によるソフトウェアが優れています。例えば、信号のデコード機能も用意されています。
試しにUARTの信号のデコードをしてみました。



試しにUART信号をASCIIにデコードしてみました。UART以外にも、I2CやSPIなど、数えきれないくらい沢山のデコーダーが搭載されています。
今回購入した、ロジックアナライザーですが、サンプリング周波数は、最大24MHzまでです。また、チャンネル数も8チャンネルしかありません。しかし、アマチュアならばこの程度の性能であっても、そこそこ使えるのではないでしょうか。今回やった、6チャンネル62.5kHz PWM信号の同期をとるのには十分な性能でした。また、強力なデコード機能は、重宝しそうです。
これでワンコインなら、いい買い物だと思います。