Arduinoのi2cライブラリ(Wire)の拡張(WireExt)

Arduinoがとても大好き(笑)な僕ですが、カメラからの画像を線を4本つなぐだけで取得できるモジュールをテストする都合もあり、Arduinoを積極的に使っています。今回はその過程でおきた問題で、Arduinoの標準付属ライブラリWireが役不足な故に、その拡張版を作ったというお話です。

TCM8240MD_breakout_and_Amini.jpg
とても小さなテスト環境。

上の写真はそのテスト風景ですが、Arduino Miniと接続している線は電源2本(VCCとGND、VCCは+5V/3.3V両対応)、そしてi2cのSDA/SCLの2本、計4本です。今回のお題であるWireというライブラリは、そのi2cでデータを送信したり受信したりするためのライブラリです。

i2cは2本の線にいろいろな機器を接続できるなどなかなか高機能な規格で、データの送受信についても複数バイトを一つの単位として扱うことができます。言い換えれば転送によって複数バイトで構成されている意味を失わずにすむわけです。例えば今回のカメラモジュールについては、1回のシャッターで撮った画像を1回の転送で処理する、というような対応関係にしました。

ArduinoのライブラリWireもそのような意味づけを扱いやすいように設計されています。例えば送信ならば以下のようなコードを使います。beginTransmission()からendTransmission()までの範囲が一つの単位として送信されます。

Wire.beginTransmission(address);
Wire.send(byte[0]);
Wire.send(byte[1]);
...
Wire.send(byte[n]);
Wire.endTransmission();

一方の受信はこのような使い方をします。ちょっと作りが送信とは違います。

requestFrom(address, n);
while(n > 0){
    if(available() > 0){
        byte b = receive();
        do_somthing_with(b);
        n--;
    }
}

ここで問題が発生しました。カメラモジュールの場合、nがとても大きくなります。例えばVGAで1ピクセルあたり2bytes表現のRGB565を使った画像でしたら640*480*2=614400(bytes)です。Wireではnが内蔵メモリに収まる程度、例えば32bytesまでの範囲でしか使うことが想定されていません。このままだと画像の少し先頭を受信できるだけで、意味がありません。

そこで送信に似た形で受信も無限に行えるよう、Wireの拡張ライブラリをこさえました。その名もWireExt。使い方はbeginReception()とendReception()で囲んでget_byte()でデータを1byteずつ受信できます。アドレスが間違っているなど受信開始に失敗した場合はbeginReception()で負の値が返るので、それを検出して例外処理を行うことができます。さらに、beginReception(address, twbr)とすると、twbrの値を小さくすることで受信スピードを一時的に早くすることもできます(0をいれると最速になり、Arduino Miniでは1Mbps)。

#include <WireExt.h>
void loop(){
    unsigned long count = 0x1000;
    if(WireExt.beginReception(cameraAddress) >= 0){
        while(count > 0){
            byte b = WireExt.get_byte();
            do_somthing_with(b);
            count--;
        }
        WireExt.endReception();
    }
}

ArduinoのlibrariesフォルダにWireExtというフォルダを作成して、中にWireExt.cppWireExt.hkeywords.txtを配置すれば使えるようになります。

June 22, 2010 01:31 fenrir が投稿 : 固定リンク | | このエントリーを含むはてなブックマーク

コメント

コメントする