mbed + 猫カメラで苦戦中

昨日、少人数ながら定例の組み込み系飲み会を開きました。
いろいろと盛り上がった会合でしたが、席上、fenrirさんから猫カメラのブレークアウト・モジュールを評価用に譲ってもらえましたので、mbedとの接続を試みているところです。

ブレークアウト・モジュールのピン配置がEagleをもってPCBのレイアウトを開かないとわからないので手間取りましたが、まずは写真のようにブレッドボード上においています。同じ席にいたいしかわさんや、はじめさんは、コネクタできれいにまとめようとして手間取っているようですが、私は根っからいい加減な男なので、とりあえずこんな形です。ちなみに写真中青いワイヤがSCL、黄色いワイヤがSDAです。
さて、苦戦中な訳ですが、例によって例のごとく、I2Cをあつかったことのある人なら皆悩むアドレスで引っかかっています。

mbedのI2Cのアドレスの扱いはどうなっている?

I2Cのスリーブ・アドレスはプロトコル上の1バイト目のbit7:1を占めます。今考えると、このフィールド構成が後々まで災厄を引きずることになりました。つまり、I2Cのアドレス表現には二つあっります。

  • プロトコル上の1バイト目の表現をそのまま使う
  • bitフィールド7:1の値を取り出して使う

NXPのI2Cの仕様によると後者が正しいのですが、mbedのI2C::write()やI2C::read()のアドレス引数がどちらなのかは明確には説明されていません。ただ、「read()のアドレスのbit0を1にする」という説明から類推するに、前者のプロトコル上の1バイト目の表現を使っているようです。

猫カメラのI2Cアドレスは?

fenrirさんの説明によるとconfigurationの書き込みアドレスは0x3E、読み出しアドレスは0x3Dです。これはセンサーデバイスTCM8240のデータシートの6ページ目からすると、プロトコル上のbit7:1を持ってアドレスとしているようです。I2C標準通りです。
ただ、writeで0x3E、readで0x3Dというのは、やや困惑する値です。というのは、コンフィギュレーションレジスタへの書き込みはデータシートを見る限り、この値は0x3Dであるべきだからです。

猫カメラからのデータのダウンロードは?

これが難しいところです。
先のデータシートには、センサーからのコンフィギュレーションレジスタのI2Cによる読み方が示されているだけです。その方法はrepeated startによるwrite-readシーケンスを使います。
ところが、fenrirさんの解説ページによると、レジスタ・アドレスを指定しない単純リードを繰り返すことで映像データを読み出せるとなっています。この方法はデータシートに記載されていないのですが、どうやら成功例もあるようです。

読み書き自体はできているらしい

いまのところ、mbedの関数のリターン値を見る限りI2Cのプロトコル自体は正しく機能しているようです。まだデータサイズの読み込み値に不審点があるものの、リターン値そのものはエラーなしを指示しています。
今週はここまでかな。

#include "mbed.h"

#define CAM_I2C_ADDRESS 0x7A

char cam_config[][2] = {
    {0x02, 0x00},    // Set Camera Active
    {0x02, 0x40},    // Set Camera Reset
    {0x03, 0x00},    // PLL
    {0x02, 0x00},    // Set Camera Active
    {0x0B, 0x00},    // White Line OFF
    {0x58, 0x20},    // Exposure Time
    {0x05, 0x80},    // Frame Rate Quarter(00)/Half(40)/Full(80)
    {0x1A, 0xFF},    // HCOUNT = 0x3FF = 1023
    {0x1B, 0xB3},    // VCOUNT = 0x21B = 539
    {0x1C, 0xA1},    //
    {0x11, 0x4A},    // Changed b/c of PICSIZE
    {0x14, 0x23},    // Changed b/c of PICSIZE
    {0x04, 0x0B},    // RGB    160x120    OUT ON
    {0x1F, 0x0C},    // SPCOUNT = 0xBC3 = 3011 // Doesn't match formula?
    {0x1E, 0x23},    // SPCOUNT[7:0]
    {0x0E, 0x00},    // According to the AppNote it should be 0xAC for this PICSIZE?
};

int data_size = 0;

LocalFileSystem local("local");
I2C i2c(p9,p10);

int main() {
    FILE *fp = fopen("/local/out.txt", "w" );
    int i;
    int result;


        // initialize cammera module by sending initialization parameter
    for (i = 0; i < sizeof(cam_config) / sizeof(cam_config[0]); i++) {
            // for each time 1 register write, send stop bit and then, start next sesstion
        result= i2c.write(CAM_I2C_ADDRESS, cam_config[i], 2 );
    }
    fprintf( fp, "result is %d \n", result );
    
        // read 4 bytes as length
    result = i2c.read( CAM_I2C_ADDRESS | 1, (char *) & data_size, 4 ); 
    fprintf( fp, "result is %d \n", result );

        // write down length
    fprintf( fp, "data size is %08x \n", data_size );
    fclose(fp);
}