VL53L0XはI2Cのアドレスは可変だが、揮発性なので、電源を入れるたびにアドレスを再設定してやる必要がある。メーカーのアプリケーションノートによると、デバイス1個あたり1本(or2本)のGPIOを割り当てて、1個ずつシャットダウンを解除しながらアドレスを割り当てるべし、とのことらしい。例えばセンサを4個使うなら、4本(or8本)のGPIOが必要になる。(2本使う場合は、デバイスの選択とデバイスからの割り込み)
ところで、VL53L0XにはGPIOが1本乗っている。割り込みの出力が本来の用途だが、GPIOというくらいだから汎用入出力も可能なのであろう。であるなら、これを使ってアドレスを一意に割り当てられるのでは。
昔読んだPDFで、ロジックICよろしくGPIOとXSHUT(shutdown)でデバイスをカスケードに接続してアドレスを割り当てていく、というような使い方があった気がする。
一番端のデバイスはXSHUTがオープン(プルアップ)で固定され、それ以外はXSHUTに一つ前のGPIOが接続されている。リセット後はすべてデバイスが起動状態になっていて、VL53L0Xに対してGPIO Lowを設定すると、すべてのデバイスがシャットダウンされる。ただし、一番端のデバイスはXSHUTが固定されているので、起動している。
この状態でアドレス変更コマンドを送ると、一番端の唯一起動しているデバイスのアドレスが変更される。続いて変更後のアドレスにGPIO Highコマンドを送ると、2つ目のデバイスが起動する。これにも一意のアドレスを割り振り、GPIO Highを送り、と、続けていく。
これによって、ホスト側のGPIOは1本も使わずに、すべてのVL53L0Xに一意のアドレスが設定される、という具合。
しかし、簡単に調べた感じだと、そういう使い方が書かれた資料を見つけられなかった。昔のデバイス(VL6180X)の資料にも、そういう使い方は出てこない。
***
試しに、VL53L0X_SetGpioConfigでいくつかコマンドを送ってみた。
デバイスモードがSINGLE_RANGING(後で使うモードによる)、FunctionalityがOFF、PolarityがLOWかHIGH、で、GPIOから任意の状態を出せるっぽい。ただし、PolarityはLOWでHighレベルが、HIGHでLowレベルが、出てくるらしい。XSHUTが負論理なので、それにあわせて論理が反転されている?
バーAからバーBまでが初期設定、バーBからバーCまでがトグル、バーC以降がレンジング、という感じ。
前回Lowレベルを出したのが残っているので、初期設定の途中まではLowが維持されている。が、初期設定の途中でGPIOモードが変わるらしく、ジタバタ暴れている。
デフォルトでは処理完了の割り込みに使われているようだ。
***
SetGpioConfigはリセット後(電源投入直後)にいきなり叩いても動くし、SetDeviceAddressも動く。ということで、とりあえず手持ちに有った2個のVL53L0Xを、ホストのGPIOを使わずにアドレスの割当を試してみた。
前述のシーケンスの通りに、0x52に対してGPIOをLowにするようにコマンド、アドレスを適当な値に変更、GPIOをHighにするようにコマンド、を、0x52からNACKが帰るまで行う。これにより、すべてのVL53L0Xに対して、一意のアドレスを割り振れることを確認した。
とはいえ、2個しか試していないので、もっと増えたときにも使える手段なのかはわからないが。
そして、ここからが問題なのだが、1個目のアドレスでGPIOをトグルすると、2個目のXSHUTがトグルされる。そして、その後でアドレスを確認すると、デフォルトのアドレスに戻ってしまっている。
つまり、XSHUTによるシャットダウンは、スリープとかサスペンドではなく、シャットダウンが行われており、揮発性の設定は消えてしまう、ということ。
通常の初期化シーケンスでは、GPIOを割り込みに使うように設定が行われるため、そのままではどこかのVL53L0Xを使うと、その次のデバイスはデフォルトのアドレスに戻されてしまう。
VL53L0X_StaticInitでSet interrupt config to new sample readyとコメントされている付近の処理を削除すれば、GPIOモードの変更は行われないため、GPIOが割り込みに使われることはなく、意図しないリセットも行われなくなる。
ただ、StaticInitはAPIとして用意されている関数なので、これを改変するのはちょっと気が引ける。
***
とりあえず、少ないリソースでVL53L0Xのアドレスの再配置ができそうだ、という感触はつかめてきた。使いづらいけど。
ただ、デバイスの初期設定をどうやるか、という問題がある。具体的には、マイコンがリセットされる以前に再配置されたデバイスをどうやって把握するか、という問題。0x52にデバイスが2個あるはずだ、と思っていたのに、実際は0x54と0x56に移動していた、とか。0x52に見たらない場合は0x54と0x56にあると仮定する、とか、アルゴリズム的に解決する方法もある。あるいは、VL53L0XのVDDにPch FETを入れておいて、電源でリセットするとか。VL53L0Xは1個あたりピーク40mAほど消費するらしいので、マイコンのGPIOで給電するのはちょっと厳しい。
あるいは、一番先頭のXSHUTは開放(プルアップ)ではなく、マイコンに接続しておき、初期化時に先頭を0x52にリセット、アドレスを再割り当てしていく、という方法も考えられる。ただ、再割り当てした先に別のデバイスが存在する可能性も考えると、一旦すべてを0x52に移動してから、再び再割当てを行う、みたいな工夫が必要になる。
VL53L0Xのコマンドは結構面倒で、GPIOのトグルとアドレスの再割り当てに、20弱のコマンドを送る必要がある。その間、3ms弱かかる。I2Cバス、遅い。
***
結局、VL53L0Xデバイス1個1個のXSHUTをマイコンのGPIOで制御したほうが楽じゃないか、という気がしてくる。デイジーチェーンだと途中の1個が壊れた場合、以降のデバイスがすべて使えなくなってしまうが、個別に制御するならその問題も無い。多少手荒に扱われることが想定されるような用途だと、堅牢性が低いのは結構デメリット。
個別にXSHUTを制御するなら、最初に全部をシャットダウンしておけば、すべてデフォルトのアドレスに戻るので、あとは1個ずつアドレスを割り振ればいい、という手軽さもある。
ホストのGPIOを使わずに制御できるデイジーチェーン型も、堅牢性の高い個別結線も、それぞれ利点欠点があるので、用途に応じて選べばいい、という感じかなぁ。
あと、普通にAPIを叩いて測距すると、API内でポーリングが走るので、複数デバイスを並列にアクセスするのが難しい、という問題もある。リソースでゴリ押しするならデバイス1個毎にタスク1個、少リソースでやるならこのあたりの処理全部自分で書き直し、という感じか。
このデバイス、使わずに済ませるのが一番賢い使い方な気がする。あるいは、せめて1個だけに限るとか。
0 件のコメント:
コメントを投稿