2011年11月30日

Arduino用機器間通信プロトコルライブラリMemoryMapLib公開しました

Andyの制御に使用している機器間プロトコルはいろいろな種類というか都度適当に思いつきでいろいろ実装したりしていて、ホスト側とデバイス側が、似たような制御であってもプロトコルが合致しないというケースが多々あったりしてます。

神戸支部の夜子まま氏がAndyLibというADKBluetooth等の通信経路をひとくくりにできるAndroid側アプリに組み込んで使用する為の通信ライブラリを開発されています。その際に、通信プロトコルもそれぞれで統一されたものが良いということで、「メモリーマッププロトコル」というものを採用されることになりました。

メモリーマッププロトコルは、シンプルなプロトコルで、Andyで使用していた可変長のバイナリ通信をしてたプロトコルに似ています。このプロトコルはこのプロトコルで特徴があります。その辺はこれからご紹介してまいります。

なお、メモリーマッププロトコルはJS Robotics社さんが公開されているプロトコルとの事です。

さて、今回はこの通信プロトコルの紹介と、それをArduinoで簡単に使用するArduino用ライブラリを作成致しましたので、紹介させていただきたいと思います。
(詳細ドキュメントpdfを作成し、本記事の下にそのpdfへのリンクを置いています)


メモリーマッププロトコルの通信内容は大まかにはWrite Memory MapとRead Memory Mapというメッセージで主にやりとりしています。

例えば、Androidデバイスから、Andyのようなラジコンカーを動かす場合、例えばAndroidデバイス側をホスト、Andy側とデバイスにしたとすると、通信はホスト側から必ず発行されます。

スクリーンショット 2011-11-30 7.55.40.png 簡単な内部メッセージやりとりシーケンスはこちらです。
スクリーンショット 2011-11-30 7.56.46.png 使い方 やりたい通信内容を決めて、適当に、内容ごとにアドレス空間にマッピングします。以下は例です。
スクリーンショット 2011-11-30 19.58.41.png 次に、ホスト側から、任意のアドレスへ書き込みや読み出しをする形でアクセスする事で、機器間の通信を実現するという仕組みです。
スクリーンショット 2011-11-30 20.02.31.png 例えば、機器にLEDとスイッチが繋がっていて、ホスト側からLEDの点灯・消灯制御をしたり、スイッチの状態を取得したりしたいとします。
この場合、仮にLEDの点滅指示をアドレス 0x30 に、そしてスイッチの開閉状態をアドレス 0x31 にマッピングしておいたとすると、ホスト側からLEDの点滅制御をする際には、アドレス 0x30 に Write Memory Map を行い、一方ホスト側がスイッチの開閉状態を知りたいときには、アドレス 0x31 に対して Read Memory Map を行うことになります。

この通信プロトコルのデバイス側を簡単に実現するのが Arduinoライブラリ MemoryMapLib です。Arduino IDEから簡単に利用できます。

スクリーンショット 2011-11-30 7.56.15.png MemoryMapLibでは、それぞれのアドレスに対して、変数、または関数を紐付けることで、ホスト側からのWrite/Read Memory Map のメッセージに基づき、然るべき処理をする作りです。

では、MemoryMapLibが提供するインターフェースの紹介です。
int MemoryMap::registerMapAddressJob(unsigned char address,unsigned char RWOP,Job ptr);
int MemoryMap::registerMapAddressVar(unsigned char address,unsigned char RWOP,unsigned char* ptr);
int MemoryMap::registerMapAddressBlock(Command* );
int MemoryMap::removeMapAddress(unsigned char address);
int MemoryMap::setStreamInterface(HardwareSerial* );
void MemoryMap::poll(void);
インスタンス生成
    MemoryMap mMemoryMap;
シリアルインターフェースの接続 Arduinoと外部機器が通信をする際の、インターフェースをMemoryMapLibに設定します。現在はUARTに対応させていますが、他のI/Fへの対応拡張は容易と思います。今回は主に、Bluetoothでの制御を実現する為、Bluetoothアダプタと直結できるUARTを使用しています。

void setup()
{
    Serial.begin(9600);
    mMemoryMap.setStreamInterface(&Serial);
}

上記例では、Serialを9600bpsに設定した後、mMemoryMapに渡してます。

アドレスへの動作のマッピング
このライブラリでは、任意のアドレスにアクセスがあった場合に、「変数の操作」または、「関数の実行」のどちらかを定義します。ここでアドレス値と対応する仕事を紐付ける為に使用するのが、registerMapAddressVarまたはregisterMapAddressJobです。

unsigned char var = 0;
void setup()
{
    mMemoryMap.registerMapAddressJob(0x30,OPERATION_WRITE|OPERATION_READ,&jobLED);
    mMemoryMap.registerMapAddressJob(0x31,OPERATION_READ,&jobSW);
    mMemoryMap.registerMapAddressJob(0x32,OPERATION_READ|OPERATION_WRITE,&var);
}

ジョブ関数内の実装
MemoryMap::registerMapAddressJob()に渡す関数は、以下の形式です。
void (*jobFunction) (unsigend char RWOP,unsigned char address,unsigned char * value)
RWOP[in] : Read(OPERATION_READ) or Write(OPERATION_WRITE)どちらのアクセスにより呼び出されたかが設定される。
address[in] : Read or Write対象のアドレス値が入る。例えば、registerMapAddressJobにより、複数のアドレスに同一の関数を定義した場合でも、ここに設定されるアドレス値を確認することで動作を切り替えることが出来る。
value[in/out] : Writeで呼び出された際には、設定内容のメモリーへのポインタがセットされるで、参照する。Readで呼び出された際には、ホストに送り返すバッファへのホインタがセットされるので、値をセットする。

このライブラリを使用して、Android制御ラジコンを作ったコード例です。以下のように、やりたい制御だけ記述すれば実現できますよ。
#include "MemoryMapLib.h"

#define PIN_MOTOR_L_VREF      6
#define PIN_MOTOR_R_VREF      5
#define PIN_MOTOR_L_CONTROL1  A0
#define PIN_MOTOR_L_CONTROL2  A1
#define PIN_MOTOR_R_CONTROL1  A3
#define PIN_MOTOR_R_CONTROL2  A2
#define MOTORTYPE_MOTOR_R    0
#define MOTORTYPE_MOTOR_L    1

MemoryMap mMemoryMap;

void setup()
{
    pinMode(PIN_MOTOR_R_VREF,OUTPUT);
    pinMode(PIN_MOTOR_L_VREF,OUTPUT);
    pinMode(PIN_MOTOR_R_CONTROL1,OUTPUT);
    pinMode(PIN_MOTOR_R_CONTROL2,OUTPUT);
    pinMode(PIN_MOTOR_L_CONTROL1,OUTPUT);
    pinMode(PIN_MOTOR_L_CONTROL2,OUTPUT);
    digitalWrite(PIN_MOTOR_R_CONTROL1,LOW);
    digitalWrite(PIN_MOTOR_R_CONTROL2,LOW);
    digitalWrite(PIN_MOTOR_L_CONTROL1,LOW);
    digitalWrite(PIN_MOTOR_L_CONTROL2,LOW);
    analogWrite(PIN_MOTOR_R_VREF,0);
    analogWrite(PIN_MOTOR_L_VREF,0);
    
    Serial.begin(9600);
    mMemoryMap.setStreamInterface(&Serial);
    
    mMemoryMap.registerMapAddressJob(0x1b,OPERATION_WRITE,&jobMotor);
    mMemoryMap.registerMapAddressJob(0x1c,OPERATION_WRITE,&jobMotor);
}

void loop()
{
    mMemoryMap.poll();
}

void jobMotor(unsigned char RWOP,unsigned char addr,unsigned char* value)
{
    struct S_MOTOR_BIT_FIELD {
	unsigned char power :6;
	unsigned char cont :2;
    };
    if(RWOP & OPERATION_WRITE){
	unsigned char cont,power;
	cont  = ((struct S_MOTOR_BIT_FIELD*)value)->cont;
	power = ((struct S_MOTOR_BIT_FIELD*)value)->power;
	controlMotorPower(addr == 0x1b ? MOTORTYPE_MOTOR_R : MOTORTYPE_MOTOR_L,cont,power << 2);
    }
}

void controlMotorPower(int motortype,int motoraction,int power)
{
    int pinno_1;
    int pinno_2;
    int pinno_pwm;
    
    const unsigned char cont[4][2] = {
	{ LOW	,	LOW	},	// STOP
	{ LOW	,	HIGH	},	// REVERSE
	{ HIGH	,	LOW	},	// FORWARD
	{ HIGH	,	HIGH	}	// BRAKE
    };
    
    if(motortype == MOTORTYPE_MOTOR_R){
	pinno_1 = PIN_MOTOR_R_CONTROL1;
	pinno_2 = PIN_MOTOR_R_CONTROL2;
	pinno_pwm = PIN_MOTOR_R_VREF;
    } else {
	pinno_1 = PIN_MOTOR_L_CONTROL1;
	pinno_2 = PIN_MOTOR_L_CONTROL2;
	pinno_pwm = PIN_MOTOR_L_VREF;
    }
    digitalWrite(pinno_1,cont[motoraction][0]);
    digitalWrite(pinno_2,cont[motoraction][1]);
    analogWrite(pinno_pwm,power);
}

上記ソースを実行した動画です。

以下のgithubにてソース公開しています。 https://github.com/yishii/Arduino_MemoryMapLib
または、以下でアーカイブダウンロード出来ます。

MemoryMapLib002.zip

詳細な資料はこちらです。ホスト側のプロトコルについても、こちらの資料に記載しています。
ArduinoMemoryMapLib.pdf




Arduinoをはじめようキット
スイッチサイエンス
売り上げランキング: 2842

Arduino Uno
Arduino Uno
posted with amazlet at 11.11.30
スイッチサイエンス
売り上げランキング: 5198
posted by いしいっち at 23:39| Comment(0) | TrackBack(0) | 日記 | このブログの読者になる | 更新情報をチェックする

2011年11月20日

PIC24FJ64GB002の各パッケージを並べて比較してみた

今年PICデビューしてからというもの、専らPIC24FJ64GB002ばかり使っています。まぁ、ピン数の多いマイコンを使ったアプリケーションをやっていないので、特にその他のマイコンに移行する必要性も感じなくて。。。

とはいえPIC32などいろいろ買い込んでしまってはいますが…。


さて、このPIC24FJ64GB002はブレッドボードで使用するならピン間隔が2.54mmのDIPパッケージが適していると思います。基板に直接差し込んではんだ付けするのにも便利です。一方、IC本体のサイズ(パッケージのサイズ)が大きいので、製作したい機器を小さくまとめるには不向き。

そこで半導体ベンダーでは、同じ機能の半導体でもいろいろなパッケージを提供し、ユーザーが必要とする実装面積に合ったデバイスを選択できるようにしているものもあります。
PIC24FJ64GB002もその一つで、中身は一緒だけどガワは違うものがあります。

たまたま実験的にいくつか買ってみたら揃ってしまったので写真を撮ってみました。

R1206044.JPG

R1206042.JPG

左から、QFN、SSOP、SOIC、DIPです。PIC ADK Miniboard rev.1で使用しているのは右から二番目のSOICタイプです。これはピン間隔がDIPの半分の表面実装品です。PIC ADK Miniboardのrev.3あたりではSSOPにしたいかなと思っています。
あと、別途、もっと小さくしたいとも思うので、QFNのボードにチャレンジしてみたいと思います。

QFNは側面・裏側に端子が出ています。
QFNSIDE.jpg

また、QFNはピンの配置がQFPを裏返した感じ、と思ったんですがこのデバイスはTOP VIEWでも反時計回りのピン順で配置されてるのかな。

C言語ではじめる PIC24F活用ガイドブック
後閑 哲也
技術評論社
売り上げランキング: 54997






FPGA ボードで学ぶ組込みシステム開発入門 〜Altera編〜
小林 優
技術評論社
売り上げランキング: 4768


posted by いしいっち at 09:03| Comment(0) | TrackBack(0) | 電子工作 | このブログの読者になる | 更新情報をチェックする