« 2017年6月25日 - 2017年7月1日 | トップページ | 2017年8月27日 - 2017年9月2日 »

2017年7月23日 - 2017年7月29日の1件の記事

2017年7月26日 (水)

オシロのテストどころかソフト開発で大はまり

 新しいオシロで色々テストするつもりが、久しぶりにソフトのデバッグにはまってそれどころではなかった。超音波距離センサーSR04のI2C化の最中に、avr-libcのバグらしいもの(と最初は確信)に遭遇して意気込んでいたのだが、何のことはない、わかってみたら全てこちらのミスと判明した。いやあ情けない。まあ、それまでのいきさつを最後まで聞いてください。

新しいオシロは機能がありすぎて持て余し気味(6/30/2017)

 ほぼ10年ぶりにオシロ(帯域200MhzのSiglent SDS1202X-E)を新調して、埃をかぶっていた自作のファンクションジェネレーター(以降FG)を棚から持ち出し、FFTとか、シーケンスモードとかの新機能を試そうと、張り切ってオシロに向かった。

Dsc01176 ただし、まだ操作に慣れていないので簡単な測定でも四苦八苦である。トリガーのかけ方がいまいち理解できない。スロープとエッジの違いも良くわからない。FGで矩形波を出し、FFT(高速フーリエ解析)の波形を見るが、思っているような形にはならない。だいたいアナログ機器の調整ならともかく、単にFFTでスペクトル波形を出しても、「で、それがどうした」と言われたら黙るしかない。

  というので仕事の帰り、秋葉原の書泉ブックセンターに寄ってオシロの参考書を探した。入門書はいくつかあるが、中上級のものはほとんどない。技術の進歩が激しいので単行本になりにくいのだろう。雑誌の特集を集めたムック本が2種見つかったが、ひとつはすでに初代のオシロの時に買ったものだった。しかたがないので残りの一冊も買う。Dsc01175

 参考書の中のオシロはメーカーが違うので、パネル面や用語が手持ちのものとかなり異なる。まあ基本のところは大体似たような機能なので迷わないが、ちょっと細かくなってくるとわからなくなる。本来はこの会社(Siglent)のマニュアルを探すべきなのだろうが、日本語のものはないし、とっつきにくい。

 ウェブには何故かこういう紹介サイトもある。しかし、情けないことに半分も理解できない。うーむ、難しいな。知らなければならないことが山ほどある。ここは基本的なやり方を参考書の最初から読みこんで少しづつ理解していくしか方法はないようだ。

 前記事にあるように測定の時間的な範囲が広がったのはとても収穫だが、アナログ波形を見なければ進まない工作は現在していない。そう、宝の持ち腐れと言っても良い。使い道が見いだせないというのはつらいものだ。

センサーのブレークアウト基板を作る。久しぶりハンダ付けが楽しい(7/4/2017)
 いうことで、これまでの工作の続きをすることにした。ブレッドボードに組んでいた超音波距離センサーHC-SR04のブレークアウト基板の制作である。入力を電源3.3VとI2Cだけの結線にしぼり、RaspiやESP8266などの最近のCPUと簡単に接続できるようにする。

 手持ちのケース(タカチのSW70 75X50X35)に全体が入ることを考慮して、秋月のC基板を少し小さくする(72X40)。ここにSR04とTiny85、それに例のストロベリーリナックスのDC-DCコンバーター、秋月で入手したI2C用のレベルシフター(FXMA2102 ¥200)をレイアウトする。Dsc01164

 過去のブログ記事を見てみたら、本格的なアートワークをやる汎用基板でのハンダ付けは数年ぶりのことだ。久しぶりのアートワークそのものが楽しい。ここでの醍醐味は、複雑だった引き回しが部品の位置を少し変えるだけで簡単になることだ。

 パズルを解くのと同じである。何度もアートワークをメモに描きなおし頭を捻る。配線を交叉させないというルールは守れないかなと諦めたころ、ピンヘッダーの方向を逆にするときれいに解決したりする。鬼の子をとったような気分である。実際の工作前にもこれだけ楽しめる。

 アートワークも完成したので、部品を揃えてハンダ付けの工程に入る。ハンダ付けは一気にやらない。楽しみながら少しづつやる。実体顕微鏡を買っておいてよかった。最近TVのCMでメガネにかける拡大鏡を見かけるが、これは精々1.6倍程度で、倍率20倍のこの顕微鏡にはかなわない。ただ、顕微鏡は慣れないと対象物に絞り込むのが一苦労だ。Dsc01171

 配線作業は進む。サインペンでアートワークにハンダ付けした部分を塗りながら、出来上がっていく基板を矯めつ眇めつ(ためつすがめつ)眺めて感慨にふける。考えてみたら、この方式を始めて、そろそろ10年。このパズルのような、UEW線を交差させないアートワークと、この細かいはんだ付けの絶妙な組み合わせが、心をひきつけてやまない。

 自分がこの小宇宙の創造神である。満足感、達成感は、悪いけれどArduinoやRaspiなどでの工作とは比較にならない、至福の時間である。この基板にI2Cスレーブライブラリーを使ったSR04のインターフェースソフトを合わせて記事にしたら喜んでもらえるかもしれない。期待が膨らむ。

使えないHC-SR04があった。ブレークアウト基板はミスなし(7/6/2017)
 サインペンで線を塗るところがなくなった。完成である。ニチアツのコネクターを奢って、圧接ペンチでソケットに入れるピンを用意する(久しぶりなので1ピン失敗した)。SR04は背の高さを低くするため、センサーのピンソケットを平型に換えてある(オリジナルはL型)。テストに入る。Dsc01172

 最初、動かなくてあせったが、沢山あるセンサーユニットSR04のうち、選りによってトラブルのある方を使っていたことがわかり、あわてて正常な方にピンを付け直す。さあこれでどうだ、電源ON。良かった。ブレッドボード上の親機(Tiny861)のUARTコンソールに、距離が表示された。

 やった、やった。基板のハンダ付けは完全試合だった。腕はまだ落ちていないぞ。SR04距離センサーは、このあいだ秋月で同種のセンサー(US-015)を買ってある。ついでにこれも平型ピンに取り替えてテストする。これも問題なく動いた。 

 これで当研究所には、なんと合わせて5つもの距離センサーが揃ったことになった。アマゾンでは2つも買ってあった。このうち正常に動くのは3つ。具合が悪いのは、アマゾンの一つと秋月で最初に買ったもの合わせて2つである。Dsc01166

 ハードは一応、これで一段落である。用途は現在、階段の照明切り替えに使っている赤外線人感センサーの代替を考えているが、人間の近接を距離によってどうやって検知するかロジックが決まっていない。これからテストをして決めていくことになる。

親機のコマンド新設。距離が安定しない。DC-DCコンバーターが怪しいか(7/8/2017)
 SR04ブレークアウト基板のソフトの整備に入る。これまでにI2Cスレーブそのもののソフトは、Tiny85に組み込み、かなり作りこんだライブラリーが完成してコードも公開済みである。

 マスター書き込みでデータを送った後、ストップコンディションを送らずに、続けてスタートコンディションが来ても、これに対応する機能(リピートスタート)や、書き込み/読み込み双方のストップコンディションの対応、タイムアウトなど、I2Cスレーブとしてはほぼ満足できる機能がライブラリーとして実現している。

 ここはもう余り手を加える必要はない。残るは、このブレークアウト基板が部品として使えるように、親機のTiny861に必要なUARTコマンドを追加して、汎用的なソフト環境を整備することである。Dsc01169

 まずは、連続して測定した距離を表示するコマンドを新設する。これは先のロジックを作るのにも必要な機能で、人が近づいたときどう距離が変化していくか連続的に調べるためである。作るのは簡単で、SR04の測定を開始するコマンドと、SR04のエコーを調べるコマンドを連続的に実行すれば良い。停止は、コンソールからのリターンキーである。

 簡単に出来たので、三脚にブレークアウト基板を固定して測定を開始する。順調にデータが出始めた。ところが、出力データが安定しないのである。階段の下から上部に向けて超音波を発射し、最上部に人が立てば、距離が変化して照明などの回路をONする理屈なのだが、無人なのに距離が安定しない。

 壁に囲まれた閉空間なので反射が多いからか、また、空気中の微粒子からの反射か、突然距離が短くなる。安定した距離が続かない。困った。このままでは、実用的な目的を果たせない。

DC-DCコンバーターを調べているうちにレベルシフターを壊したか(7/12/2017)
 三脚に固定しているのに、距離センサーが不安定な原因は、どうもDC-DCコンバーターのせいではないかという疑いがでてきた。埃が原因というのも考えにくい。DC-DCコンバーターはSR04にごく近い所に固定されている。疑うところはこれくらいしかない。

 というので、5Vの昇圧コンバーターの動作を停止し、別のスイッチング電源からコードを引き込んでテストした。最初、これで安定したので、DC-DCコンバーターの影響に間違いないと思っていたのだが、少し長い間測っていると、やっぱり別電源でも測定値の揺らぎは発生した。がっかりである。

 障害物がまわりにあるときは、測定値が不安定になってしまうようである。気流の動きで反射した音波が遅れて到着し距離が不当に伸びるのかもしれない(ロジックは良くわからない)。そうこうするうちに、突然センサーが動かなくなった。I2Cの通信自体がNO Responseである。

 何度も確認したが、接触不良ではない。トラブルシューティングの原則通り、マルチメーターで各部の電圧をひとつひとつ調べていく。電圧も問題なかった。DC-DCコンバーターも5Vを作っている。

 次はI2Cだ。まだ使い慣れていないがオシロでI2Cの波形をチェックする。まず親機。大丈夫だ。次はスレーブI2CのTiny85、おやあ、クロックがおかしい。パルスは受けているようだが、0になっていない(負論理なのでactiveにならない)。

 I2Cのスレーブはクロックは受信するだけである。異電圧間をつなぐレベルシフター(FXMA2102)が正しく伝えていないのではないか。

新しいオシロがお手柄。すぐにレベルシフター不調を表示(7/13/2017)
 オシロの波形によれば、I2C信号がレベルシフターを介するところでクロックのパルスが痕跡だけになる。Tiny85のUARTは動くし、親機も正常にI2C信号を出している。配線でおかしなところもない。これはレベルシフターICが壊れたとみるのが順当なところだろう。

 この実験中、DC-DCコンバーターをはずして、5Vを別の電源アダプターなどで供給した。何度かやっているうちに逆差したのかもしれない。Tiny85などのDIP製品は逆差しに案外耐えるが、こういうSMD(表面実装)部品は一瞬でも壊れる可能性がある。

 幸い、レベルシフター(FXMA2102)は予備が買ってあった(こういうときのため)。後ろ向きの仕事で気が進まないけれど、交換してみるしかない。低温ハンダで基板とピンヘッダーをはずし(ピンヘッダーはハンダ付けしてしまった)、チップだけ載せ換えた。

 電源を入れ直す。SR04基板は問題なく動き始めた。I2Cの信号もちゃんと見える。やっぱりレベルシフターが死んでいたのだ。いや、レベルシフターを失ったのは残念だけれど、新しいオシロが手柄を立ててくれた。自らを慰める。

 距離が時々違う値を示す現象は、照射する方向を選ぶと殆どなくなることがわかった。反射面の形によって値が不安定になるようである。人感センサーとしては、垂直方向(音波の方向)で使うのは無理な気がする。水平方向(音波を横切る)なら100%検知できるのだが。

一進一退のデバッグ。同時処理でこける。avr-libcがおかしい?(7/16/2017)
  SR04を動かす分のソフト開発は大体終わった。SR04では使わない連続データの入出力機能などは開発済みだ。考えられる機能はほぼ実現したが、ただひとつ気になっているところがある。

 連続測定のとき、SR04のエコーが返ってくるまで余裕を見て50msの待ち時間を設けていることだ。用途から言って、そう短い測定間隔が必要なわけではない。実用上は全く問題ないのだが、距離が短くても、待ち時間は変わらない。そのあいだ何もしないというのも芸のない話だ。 Dsc01173_2

 この間隔を短くするのは、超音波のエコーが返ってくるまでに、親機の方から、エコーが返ってきたがどうかを調べるコマンドを送れば良い。親機はそのフラグを見て、バッファーに収容されたデータを読む。簡単なロジックだ。

 トリガーをSR04にかけるまえに、フラグを0にし、帰ってきたらこれを1にする。親機は適宜マスター読み込み宣言でこのフラグを読み取って1になるのを待つ。造作のない話なのだが、これがつまづきの始まりだった。どうにもうまく動かないのである。

 何故かフラグが1になったあとの計測データがでたらめになる。計測が割り込みを受けている間にデータが不正になるのである。慌ててAVRの参考文献を調べるが、AVRと、avr-libcは基本的にはリエントラント(複数のタスクを受け入れる)で、同じプログラムに複数のスレッドが通ることを許している。Ws000027

 これまでにこうしたプログラムはいくつか作り、何の問題なく動いている。リニアPCMプレーヤーなどは、DACの音声発生、SDカードの読み込み、LCDの進捗表示と3段のマルチタスクで動いている。

 勿論、リエントラントといっても共通のグローバル変数や、printfなどの標準関数はリエントラントには動かない。しかし、I2CとSR04の計測ルーチンは全く無関係だ(とこのときは確信していた)。だから問題なく動くはずなのだが、現実にはデータが汚されている。ハングするならともかくまともに戻って動くのが気に入らない。

 満を持してロジアナを出動させる(オシロでは無理)。I2Cとエコー、実際にデータをセットするプロセスにプローブを入れ、状況を見る。確かに、エコー期間の時にI2Cが動くとデータが不正になる。共通リソースもないのにどうしてこんなことが起きるのだろう。

情けない。とんでもない思い込みだった。立派に共通変数が被っていた(7/23/2017)
 このブログは原因がわかってから書いている。原因が解明される前のメモを今読み返しているが、いつものデバッグのときと同じで、なぜこれに気が付かなかったのだろうと感心するほど、思い込みというのは恐ろしい。 Ws000028

 I2Cの割り込みと、計測ルーチンとは全く独立していると完全に思い込んでいるから、最初は、もしかしたらavr-libcの不具合とか、もっと別なことが原因ではないかと思っていた。そのあいだに以下のような副次的なバグまで発見された。

(1)    親機から子機(スレーブ)のデータを読み込むのに、いちいちコマンドを送っていたが、そんなことをせずにマスター読み込み宣言で自由にデータが読めることがわかった。SR04のトリガーをかけてからの動作をひとつ省略した。出来る限り競合を避けるため。
 ->全く効果なし 

(2)    データをマスターに送る時、スレーブのバッファーに各ビットにひとつだけ1 の立ったマスクビットをANDしてバッファーを壊していた。データを送り終えると、元のバッファーデータはALLゼロになる。つまり、一旦送ったデータの再送が出来ていなかった。 
->これも特段の変化なし。データの再利用はしていなかった。

 完全な迷路にはまっていた。I2Cとエコーロジックは無関係だと思っているから、割り込みのときにレジスターなどが破壊されて値が不正になるのではとも考え、測定部分が関数になっていたので直接にコーディングしなおしたりした。もちろん変わりはなかった。ほぼこれで一週間悩んでいた。

 それが見るともなくソースコードを見ているとき、ふと気になるところが見つかった。スレーブのソフトI2Cは先方からの想定したビット列が来ない時は、ハングアップを避けるため1秒程度のタイムアウトを設けて、通信自体をリセットするようになっている。

 このタイムアウトのメッセージに、"No_Echo or Timeout..."というところがある。ちょっと待て、このNo Echoというのはどういうことだ。あっあっあー、何ということだ。このタイマーのキャリーを記録する変数をSR04のエコー期間を測定するときにも使っているではないか。

 たとえプログラムがリエントラントでも、変数を共通にしていては駄目になるのは当たり前だ。I2Cは通信開始時に必ずこの変数を0に戻す。これで、これまでに測っていたエコーのキャリー変数は0に戻り値はでたらめになる。あーあ、何というお馬鹿なプログラム。

 この修正は極めて簡単である。キャリー変数を、I2Cのタイムアウト用と、エコー測定用のものを分けて定義するだけだ。これで、どれだけエコー期間にI2Cが被っても正常な値を表示するようになったのは当然のことである。

 やれやれ、長い間かかった。思い込みというのは恐ろしい。「すべてのものを疑え」というデバッグの格言をかみしめる。 配線図や、コードの公開は、今ちょっとショックが大きすぎて作業する気力が生まれない。公開は次回以降としたい。

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

« 2017年6月25日 - 2017年7月1日 | トップページ | 2017年8月27日 - 2017年9月2日 »