FirmataでのI2C

117 views
Skip to first unread message

Shigeru Kobayashi

unread,
Oct 19, 2008, 9:06:46 AM10/19/08
to funnel-de...@googlegroups.com
主に遠藤さんへ

小林です

ハイレベルの前にローレベルなお話からですみません。

FirmataでのI2Cなのですが、今の所特にプロポーザルがでていないようですので、この機会に提案してみようかと思っています。とりあえず、たたき台として次のようなものを考えてみましたが、いかがでしょうか?既にこの辺りは試されたところだと思いますので、ご意見など是非お聞かせください。

読み取りに関して、↓の案では一度writeでdata
addressを指定してから読み取りを指定、という普通にI2Cで操作する時の方法に従ったものにしています。これを1個ですませた方が簡便ではあるのですが、最終的にライブラリでラップしてしまうのであれば、できるだけローレベルに近いものにした方が、後々の自由度があっていいかな、とは思っております。


/* IC2 read/write
* -------------------------------
* 0 START_SYSEX (0xF0) (MIDI System Exclusive)
* 1 I2C (0x76)
* 2 read/write (0 => write, 1 => read)
* 3 slave address (7bit)
* 4 data 0 (LSB)
* 5 data 0 (MSB)
* 6 data 1 (LSB)
* 7 data 1 (MSB)
* ...
* n END_SYSEX (0xF7) (MIDI End of SysEx - EOX)
*/


example read a sensor value of a slave device

Host => Arduino (1/2)
/* IC2 read/write
* -------------------------------
* 0 START_SYSEX (0xF0) (MIDI System Exclusive)
* 1 I2C (0x76)
* 2 0 (write)
* 3 0x13 (slave address)
* 4 data address to read (LSB)
* 5 data address to read (MSB)
* 6 END_SYSEX (0xF7) (MIDI End of SysEx - EOX)
*/

Host => Arduino (2/2)
/* IC2 read/write
* -------------------------------
* 0 START_SYSEX (0xF0) (MIDI System Exclusive)
* 1 I2C (0x76)
* 2 1 (read)
* 3 0x13 (slave address)
* 4 END_SYSEX (0xF7) (MIDI End of SysEx - EOX)
*/

Ardino => Host
/* IC2 read/write
* -------------------------------
* 0 START_SYSEX (0xF0) (MIDI System Exclusive)
* 1 I2C (0x76)
* 2 0 (write)
* 3 0x13 (slave address)
* 5 data 0 LSB
* 6 data 0 MSB
* ...
* n END_SYSEX (0xF7) (MIDI End of SysEx - EOX)
*/

takanori endo

unread,
Oct 19, 2008, 9:19:40 AM10/19/08
to funnel-de...@googlegroups.com
現状テストしているものは、commandに直接スレーブアドレスを指定('I' = 0x49)、レジスタをセット('S'=0x53)みたいな感じで
commandを分けてしまっていますが、
確かにI2Cのコマンドをまとめてしまってデータで表現したほうが、何か追加がでてきたときとか、汎用的でよいと思います。
それにいくつも、スレーブデバイスをつける場合にはパケットごとにスレーブアドレスも必要になるでしょうから、
このようなやり方がよいと思います。(この辺はまったく考えてませんでした。)


遠藤孝則


2008/10/19 22:06 Shigeru Kobayashi <koto...@gmail.com>:

--
endo takanori

Shigeru Kobayashi

unread,
Oct 19, 2008, 9:34:21 AM10/19/08
to funnel-de...@googlegroups.com
遠藤さん

小林です

了解です。とりあえず、先ほどの案でArduinoのdev
listに投げておきました。SysExですので、独自にインプリして使うというのでも問題ないといえばないのですが、できれば早い段階で標準化された方がいろいろな意味で良いかなぁと思いますので…。

また何か展開があればこちらでもお知らせします。


2008/10/19 takanori endo <sweeta...@gmail.com>:

takanori endo

unread,
Oct 19, 2008, 8:01:05 PM10/19/08
to funnel-de...@googlegroups.com
遠藤です。
そんなに重要ではないかもしれませんが、
パケットが明らかに間違っている、たとえば、read/writeのところに0か1以外になっているとか、
スレーブアドレスが7ビットでないとか、そんなときにエラーコードを返すようなものもあれば
よいと思いました。
何も返事がないと、間違っているときの特定が難しくなりますので。

遠藤孝則


2008/10/19 22:34 Shigeru Kobayashi <koto...@gmail.com>:

--
endo takanori

takanori endo

unread,
Oct 19, 2008, 10:55:44 PM10/19/08
to funnel-de...@googlegroups.com
あとからですいませんが、ちょっと疑問です。

> Host => Arduino (1/2)
> /* IC2 read/write
> * -------------------------------
> * 0 START_SYSEX (0xF0) (MIDI System Exclusive)
> * 1 I2C (0x76)
> * 2 0 (write)
> * 3 0x13 (slave address)
> * 4 data address to read (LSB)
> * 5 data address to read (MSB)
> * 6 END_SYSEX (0xF7) (MIDI End of SysEx - EOX)
> */

これは、I2Cのレジスタに書き込むときのパケットですよね?
書き込む先のアドレスは、4,5に指定しますが、書き込むデータの指定が必要に
なるのではないでしょうか?
4 data address to write (LSB)
5 data address to write (MSB)
6 data 0 (LSB)
7 data 0 (MSB)
8 END_SYSEX (0xF7) (MIDI End of SysEx - EOX)
となりますか?

> Host => Arduino (2/2)
> /* IC2 read/write
> * -------------------------------
> * 0 START_SYSEX (0xF0) (MIDI System Exclusive)
> * 1 I2C (0x76)
> * 2 1 (read)
> * 3 0x13 (slave address)
> * 4 END_SYSEX (0xF7) (MIDI End of SysEx - EOX)
> */

同様に読み出す先のアドレスが必要で、


4 data address to read (LSB)

5 data address to read (MSB)

6 END_SYSEX (0xF7) (MIDI End of SysEx - EOX)

> Ardino => Host


> /* IC2 read/write
> * -------------------------------
> * 0 START_SYSEX (0xF0) (MIDI System Exclusive)
> * 1 I2C (0x76)
> * 2 0 (write)
> * 3 0x13 (slave address)
> * 5 data 0 LSB
> * 6 data 0 MSB
> * ...
> * n END_SYSEX (0xF7) (MIDI End of SysEx - EOX)
> */

これは、Arduinoからの返事で、読み込んだ結果を返す時は、
1 I2C (0x76)
2 1 (read)
3 0x13 (slave address)
5 data 0 LSB
6 data 0 MSB
7 END_SYSEX (0xF7) (MIDI End of SysEx - EOX)

となるのでしょうか?
ちなみに戻りが2byteの場合は、
7 data 1 LSB
8 data 2 MSB
9 END_SYSEX (0xF7) (MIDI End of SysEx - EOX)

という感じになるのでしょうか?


基本的なI2Cの考え方がまちがってたらすいません。
遠藤孝則


--
endo takanori

Shigeru Kobayashi

unread,
Oct 20, 2008, 9:49:49 AM10/20/08
to funnel-de...@googlegroups.com
遠藤さん

このサンプルですが、

1. I2Cで読み出したいアドレスを指定(write)
2. I2Cで読み出しを実行
3. 1で指定したアドレスのデータが読み出される

という流れを想定していました。参考にしたのはこちらのページですが、私が勘違いしているかもしれません。

http://wiki.livedoor.jp/yamamaya_com/d/I2C%A5%D0%A5%B9%A4%F2%BB%C8%A4%C3%A4%C6%A4%DF%A4%E8%A4%A6


こちらのサンプルなどの方法だと

http://www.makingthingstalk.com/chapter8/20/

・レジスタのセット
・読み出し

の2つに分かれているのですが、これに加えて書き込みを用意するよりは

・アドレスとレジスタを指定した書き込み
・アドレスとレジスタとバイト数を指定した読み出し

のように用意してしまった方がシンプルでいいでしょうか(恐らく遠藤さんが想定されているのはこれですよね)?デメリットとしては、毎回レジスタを設定するために転送量が増える、ということかなとは思いますが…。整理すると、以下のような感じになるでしょうか?

/* I2C read


* 0 START_SYSEX (0xF0) (MIDI System Exclusive)
* 1 I2C (0x76)
* 2 1 (read)

* 3 slave address
* 4 register to read (LSB)
* 5 register to read (MSB)
* 6 bytes to read
* 7 END_SYSEX (0xF7) (MIDI End of SysEx - EOX)
*/

/* I2C read (reply)


* 0 START_SYSEX (0xF0) (MIDI System Exclusive)
* 1 I2C (0x76)
* 2 1 (read)

* 3 slave address
* 4 register (LSB)
* 5 register (MSB)
* 6 data 0 (LSB)
* 7 data 0 (MSB)
* 8 data 1 (LSB)
* 9 data 1 (MSB)


* ...
* n END_SYSEX (0xF7) (MIDI End of SysEx - EOX)
*/

/* I2C write


* 0 START_SYSEX (0xF0) (MIDI System Exclusive)
* 1 I2C (0x76)
* 2 0 (write)

* 3 slave address
* 4 register to write (LSB)
* 5 register to write (MSB)
* 6 data 0 (LSB)
* 7 data 0 (MSB)
* 8 data 1 (LSB)
* 9 data 1 (MSB)


* ...
* n END_SYSEX (0xF7) (MIDI End of SysEx - EOX)
*/


2008/10/20 takanori endo <sweeta...@gmail.com>:

takanori endo

unread,
Oct 20, 2008, 9:58:50 AM10/20/08
to funnel-de...@googlegroups.com
遠藤です。
わかりました。

僕が思っていたのは、
レジスタ読み出し
レジスタ書き込み
という処理でプロトコルを決めるということで、
実際は、レジスタ読み出しにも


> 1. I2Cで読み出したいアドレスを指定(write)
> 2. I2Cで読み出しを実行
> 3. 1で指定したアドレスのデータが読み出される

こういう処理になっていますね。

I2Cに慣れている人はこちらでも問題ない気がします。
確かに毎回レジスタを設定するために転送量が増えるというデメリットがありそうなので、
昨日までの、小林さんの案で、進めたいと思います。

なにか疑問があったらまた聞きますね。
よろしくお願いします

遠藤孝則

2008/10/20 22:49 Shigeru Kobayashi <koto...@gmail.com>:

--
endo takanori

Shigeru Kobayashi

unread,
Oct 20, 2008, 10:11:09 AM10/20/08
to funnel-de...@googlegroups.com
遠藤さん

小林です

> I2Cに慣れている人はこちらでも問題ない気がします。
> 確かに毎回レジスタを設定するために転送量が増えるというデメリットがありそうなので、
> 昨日までの、小林さんの案で、進めたいと思います。

ここが実際のところどうなのか、というのは自信がないところではあります。コンパス1個のように常に同じレジスタの値を読み出すのであれば転送量は減らせますが、複数のとびとびのレジスタの値を読む、とかだと逆に増えてしまいますよね…。

とりあえず、昨日の案でテストしてみていただけますでしょうか。なお、昨日のものではリードの際のバイト数を指定し忘れていましたので、そこを修正しました。

#define I2C 0x76 // I2C read/write message

/* IC2 read/write
* -------------------------------
* 0 START_SYSEX (0xF0) (MIDI System Exclusive)
* 1 I2C (0x76)

* 2 read/write (0 => write, 1 => read)
* 3 slave address (7bit)
* 4 data 0 (LSB)
* 5 data 0 (MSB)
* 6 data 1 (LSB)

* 7 data 1 (MSB)


* ...
* n END_SYSEX (0xF7) (MIDI End of SysEx - EOX)
*/


example: read a value of a slave device

1. Host => Arduino (1/2)


* 0 START_SYSEX (0xF0) (MIDI System Exclusive)
* 1 I2C (0x76)
* 2 0 (write)
* 3 slave address

* 4 register to read (LSB)
* 5 register to read (MSB)

* 6 END_SYSEX (0xF7) (MIDI End of SysEx - EOX)

2. Host => Arduino (2/2)


* 0 START_SYSEX (0xF0) (MIDI System Exclusive)
* 1 I2C (0x76)
* 2 1 (read)
* 3 slave address

* 4 bytes to read
* 5 END_SYSEX (0xF7) (MIDI End of SysEx - EOX)

3. Ardino => Host


* 0 START_SYSEX (0xF0) (MIDI System Exclusive)
* 1 I2C (0x76)
* 2 0 (write)
* 3 slave address

* 5 data 0 LSB
* 6 data 0 MSB
* ...
* n END_SYSEX (0xF7) (MIDI End of SysEx - EOX)


2008/10/20 takanori endo <sweeta...@gmail.com>:

takanori endo

unread,
Oct 21, 2008, 10:56:39 PM10/21/08
to funnel-de...@googlegroups.com
一応、この方式で、サーバー経由でI2Cのレジスタを参照することができました。

しかし、とってきたデータをどうやって持っていればいいのかをちょっと悩んでいます。

単純に
Arduinoクラスに、
byte[] I2Cdata
をつくって持っているのが、簡単そうですが問題ありそうでしょうか?

遠藤孝則


2008/10/20 23:11 Shigeru Kobayashi <koto...@gmail.com>:

--
endo takanori

Shigeru Kobayashi

unread,
Oct 21, 2008, 11:25:56 PM10/21/08
to funnel-de...@googlegroups.com
遠藤さん

小林です

おお、すばらしいですね。


> しかし、とってきたデータをどうやって持っていればいいのかをちょっと悩んでいます。
>
> 単純に
> Arduinoクラスに、
> byte[] I2Cdata
> をつくって持っているのが、簡単そうですが問題ありそうでしょうか?

他の方法とすると、I2C系のイベント用のイベントリスナを登録できるようにして、イベントが届いた時にコールバックされるような形でしょうか。このあたり、実装の都合としてはいかがでしょうか。

あと、この機能自体は同じFirmataを使うFIOでも同様に利用できると思いますので、digitalPinなどと同様にIOModuleクラスに実装してしまうのがいいかなと思います。

・・・

現状ではあくまでテスト用の実装ということで

/sysex

のみですませているのですが

/sysex/string
/sysex/i2c

のようにもう1階層設けた方が受信側がシンプルになるかなと思いますが、いかがでしょうか。

・・・

あれこれ同時で恐縮ですが、アナログピンやデジタルピンと同様に、I2Cデバイスのアドレス、レジスタ、バイト数をセットすると以降自動的にレポートしてくれる、というようにファーム側に実装した方が良いかなとも思っているのですが、この点はいかがでしょうか。コール&レスポンスですと、複数のレジスタを読み出すようなことになった場合、パフォーマンスがちょっと心配かなと思うのと、無線になった時に最適にパケット化するのが難しいかなと思いまして…。


五月雨式で申し訳ありませんが、ご意見お待ちしております。:)


2008/10/22 takanori endo <sweeta...@gmail.com>:

Shigeru Kobayashi

unread,
Oct 26, 2008, 8:24:35 AM10/26/08
to funnel-de...@googlegroups.com
遠藤さん

小林です

ちょっと遅くなってしまいましたが、変更後のI2CコマンドプロポーザルをArduinoの開発者向けMLにポストしてみました。StarndardFirmataにこれを組込んだものは明日用意してみようと思います。

http://arduino.cc/pipermail/developers_arduino.cc/2008-October/000163.html

ちょっと面倒な点があるとすれば、連続読み取りで、しかも複数デバイス&レジスタをサポートしようとするとリクエストされたもののリストをArduino側で保持しておく必要がある、ということでしょうか。とりあえず、固定長のリストで実装しようと思っています。


2008/10/22 Shigeru Kobayashi <koto...@gmail.com>:

Shigeru Kobayashi

unread,
Nov 1, 2008, 9:15:41 AM11/1/08
to funnel-de...@googlegroups.com
主に遠藤さんへ

小林です

大変遅くなってしまいましたが、先ほどコミットしたr505~r507でFunnel
Serverで対応しつつ、テスト用にhardware/arduino/SimpleI2CFirmataを追加しています。まだ、read
continuouslyには対応できていないのですが、SparkFunのコンパスモジュールに関しては、以下のような感じで読み取れることを確認しています。

aio.send_sysex 0x76, [0, 0x21, 0x47, 0x74, 0x51] #write, 'G'
aio.send_sysex 0x76, [0, 0x21, 0x41] #write, 'A'

10.times do
aio.send_sysex 0x76, [1, 0x21, 0x7F, 0x02] #read
sleep 0.5
end

以下が最新の仕様です。何かお気づきの点などありましたらお知らせください。

#define I2C 0x76 // I2C read/write message

/* IC2 read/write
* -------------------------------
* 0 START_SYSEX (0xF0) (MIDI System Exclusive)
* 1 I2C (0x76)
* 2 read/write

0 => write
1 => read once
2 => read continuously
3 => stop reading


* 3 slave address (7bit)
* 4 data 0 (LSB)
* 5 data 0 (MSB)
* 6 data 1 (LSB)
* 7 data 1 (MSB)
* ...
* n END_SYSEX (0xF7) (MIDI End of SysEx - EOX)
*/


example: read a value of a slave device

1. Host => Arduino


* 0 START_SYSEX (0xF0) (MIDI System Exclusive)
* 1 I2C (0x76)
* 2 1 (read)
* 3 slave address
* 4 register to read (LSB)
* 5 register to read (MSB)

* 6 bytes to read (LSB)
* 7 bytes to read (MSB)
* 8 END_SYSEX (0xF7) (MIDI End of SysEx - EOX)

2. Ardino => Host


* 0 START_SYSEX (0xF0) (MIDI System Exclusive)
* 1 I2C (0x76)

* 2 slave address (LSB)
* 3 slave address (MSB)


* 4 register (LSB)
* 5 register (MSB)

* 6 data 0 LSB
* 7 data 0 MSB


* ...
* n END_SYSEX (0xF7) (MIDI End of SysEx - EOX)


2008/10/26 Shigeru Kobayashi <koto...@gmail.com>:

Reply all
Reply to author
Forward
0 new messages