netshとは?
netshのいいところ
設定画面は、利用者が設定を変更したい時に操作することを前提としています。一方、netshはあまりそういう使い方をしません。
設定画面は、利用者が設定を変更したい時に操作することを前提としています。一方、netshはあまりそういう使い方をしません。
前回からの続きです。
数日間ずっと暗い気持ちでモヤモヤしていたのですが、ふと、全く別のアプローチを思いつきました。Edisonが提供しているI2Cハードを使うのをやめて、汎用のデジタルIOピン上でI2C通信する処理を自前で実装するのです。(Bit Bangingと呼ばれる手法です)
基本的な実装は思ったほど難しくなかったのですが、いざ動かしてみると、ここにも一つ落とし穴がありました。
通常、汎用のI/Oピンは、データの方向(INPUT/OUTPUT)を設定してから、電圧レベル(HIGH/LOW)を読み書きします。今回はI2C通信をエミュレートするため、データ方向を頻繁に切り替える必要がありました。(I2Cは、データの送受信を1本の線でまかないます)
データ方向の切り替えはArduino互換ライブラリのpinMode関数を使って行ったのですが、この関数を呼び出すと、なんと、切り替えと関係ない「他のIOピン」の電圧が一瞬上下に振れます。I2Cプロトコルに準じた波形を作るために苦労している中で、こんな副作用があっては困ってしまいます。
試行錯誤した結果、今回は、pinMode関数を呼び出すタイミングを調整することで、なんとか副作用を抑えることができました。
Bit Bangingの実装が終わったところで、デモプログラムのI2C処理を置き換えて、動作確認してみました。どうせダメでしょ・・・くらいに思っていたのですが、なんとなんと、全てのパラメーター書き込みに成功しました!
結局、EdisonのI2CハードとArduCAMの相性が悪かったんですね・・・。
カメラモジュールを1台繋げた状態でうまくいったので、今度は、2台繋げて検証してみました。いろいろ試した結果、2kHz程度のクロック周波数なら、複数台繋いでもうまくいくことが分かりました。(10kHzだと、一方は正常に動作するものの、他方はパラメーター設定に失敗して変な画像が出力されたりしました)
2kHzと言うと、I2C仕様の中で最も低速なスタンダードモードの100kHzより50倍遅いことになります。とはいえ、今回の自作カメラにおいては、I2C通信はカメラモジュールの初期化時に1回走るだけです。初期化後のシャッター制御や画像読み取りは高速なSPI通信で制御されるので、実用上の問題はありません。
幾多の困難を乗り越えて、ようやくArduCAMがEdison上で動くようになりました。
動かし始めた頃は、EdisonからSDカードを抜き、自機のMAC OS Xに差し、画像を確認し、Edisonに再び差し直す・・・という作業を繰り返していました。ただ、これを数十回も繰り返しているうち、いい加減面倒になってきました。
そこで、Expressというnode.js用のWebサーバーAPIを使って、SDカードのJPEG画像を自機のWebブラウザから直接見られるようにしました。
$ vi app.js
var express = require(‘express’);
var app = express();// Edisonは、SD Card を /media/sdcardにマウントする
app.use(‘/sdcard’, express.static(‘/media/sdcard’));app.listen(3000, function () {
console.log(‘Example app listening on port 3000!’);
});$ node app.js #webサーバ起動
特にトラブることなく、あっさり成功。I2Cの苦労を思えば、まさに瞬殺です。こういうことがサクッとできるところに、Edisonの凄さを感じます。
冒頭でも述べた通り、本当にやりたい事はカメラから画像出力した先の処理なのですが、今回は、画像出力までで力尽きました。
でも、これでようやくスタートラインに立てました。これから色々試してみて、随時、本ブログに結果報告していきたいと思います。
前回からの続きです。
I2C通信に問題があることが判明しました。次は、それがデモプログラムの組み方の問題なのか、もっとハードウェア寄りの問題なのかを見極める必要があります。
そこで、Edison上のLinuxに同梱されている、i2c-toolsというI2C通信用コマンドセットを使って、現象の再現を試みました。再現しないならデモプログラムの問題で、再現するならハードの問題という事になります。
まず、i2cdetectコマンドを使って、接続されているI2C機器(今回の場合はカメラモジュール)のアドレスを取得できるか確認しました。1台のカメラを接続した状態であれば100%取得できます。(”30″というのが、ArduCAMのアドレスです)
2台繋ぐと少し取得の成功率が下がり、3台を超えると全く取得できなくなりました。
i2cdumpコマンドによるパラメーターの読み出しも試みましたが、同じ傾向が見られます。
EdisonのI2CバスにArduCAMを複数台繋げると、通信障害が起きるようです。結局、ハードの問題でした。(プログラムの問題なら対処も簡単だったのに・・・現実は厳しい)
とはいえ、手元のArduCAMカメラモジュールがJPEG画像を出力したところを一度も見たことがない自分としては、そもそも初期不良なのでは?という不安も払拭しきれません。
そこで、初期不良かどうかはっきりさせる為に、Arduino UNOも購入することにしました。
現品の到着後、早速、Edison for ArduinoをArduino UNOに差し替えてリトライしました。1台でも複数台でも、ちゃんと動きます。これで、初期不良ではないことがはっきりしました。
余談ですが、実はArduino UNO上で動かす時に、少々ハマりました。Arduino UNOは、Edisonと違ってメモリ領域の制限が厳しい為、デバッグ用にSerial.print(“xxx”)を挟みすぎると、文字列定数(“xxx”の部分)が貴重なメモリ領域を圧迫してしまいます。これが一定量を超えると、変数の読み書きが正しく行えず、プログラムの挙動が不安定になります。(本家サイトにも注意書きがありました)
この自作カメラは、1本のI2Cバス上に、同じI2Cアドレスを持つArduCAMカメラモジュールを複数台繋げる構成になっています。普通は、複数の機器を同一バスに繋ぐのであれば、それぞれが異なるアドレスを持つべきです。しかし、開発者本人は、「確かに良い設計とは言えない。でも、動くよ。」という見解のようです。実際、Arduino UNOで動くことは私も確認しました。でも、EdisonのI2Cバスにはその力技が通用しないという事なのかもしれません。
そこで、一旦複数台のカメラを繋ぐ事は先送りして、1台だけつないだ状態で動かしてみる事にしました。1台のみであれば、I2C通信に問題がないことは前述のi2c-toolsで確認済みです。
ところが・・・デモプログラムは動きません。
デモプログラムを動かす為には数十個のパラメーターを設定する必要があるのですが、ある特定のパラメーターに書き込みすると、それ以降、どのパラメーター書き込みもエラーになるのです。しかも、動作電圧(3.3V / 5V)によって、エラーの引き金となるパラメーターが異なります。加えて、3.3Vなら、同じパラメーター書き込みを何度も繰り返しているうちにいずれ成功するのですが、5Vだと、どれだけリトライしても失敗し続けます。
もはや説明がつきません。EdisonとArducamは相性が悪いのでしょうか?
それでも、ここまで来たら諦めきれません。I2C通信の波形を見れば、何かヒントが得られるかも知れないと思い、Analog Discovery 2 というデジタルアナライザを購入しました。(今回の自作は、結構な額を出費しています(泣))
早速、波形を観測してみました。
I2C通信のプロトコルシーケンス自体に問題はなく、Arducamがエラー応答(NAK)を返しているように見えます。
ちなみに、書き込みに成功した場合は以下のシーケンスになります。
残念ながら、カメラセンサーの内部構造を知らない私には、NAKを返す原因を調べる術がありません。
実は、デジアナであれこれ調べている時に、NAKとは別にもう1つ気になる点がありました。EdisonとArduino UNOの波形が少し違うのです。
Arduinoと比べると、Edisonの方はクロックのHI電圧が上がりきっていないように見えます。これが問題の原因とは考えにくいものの、他にやれることも見当たらないので、ここに対策を打ちます。
いろいろ調べた結果、Arduino UNOは100kHzのスタンダードモードがデフォルト設定で、一方のEdisonは400kHzのファーストモードがデフォルト設定だと知りました。
そこで、Edisonをスタンダードモードに落とした状態で、再度波形を観測してみます。
理想的な波形になりました。なったのですが・・・やはり、NAKを返す問題は解消されませんでした。
もう、打てる手がありません。