obniz, arduino, espでのI2C書き方比較

同じことをしたくてもマイコンごとに言語や書き方が違って，せっかく学んでも使うマイコンが変わったらもう一度やり直しということがあります．

特にI2Cがマイコンごとの個性が出てるイメージがあったので，比較してみました.

比較したのは下３つです
- [obniz](https://obniz.io)
- [arduino](https://www.arduino.cc)
- [esp32](https://github.com/espressif/esp-idf)

## 初期化(master)

i2cのmasterとしての初期設定です．
クロックの設定や，ピンの設定を行います

obniz

```javascript
obniz.i2c0.start({mode:"master", sda:2, scl:3, clock:400000}); 
```

arduino

```c

Wire.begin(); 
Wire.setClock(400000); 
//対応ピンはボードごとに固定
```


esp32 

```c

int i2c_master_port = I2C_EXAMPLE_MASTER_NUM;
i2c_config_t conf;
conf.mode = I2C_MODE_MASTER;
conf.sda_io_num = I2C_EXAMPLE_MASTER_SDA_IO;
conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
conf.scl_io_num = I2C_EXAMPLE_MASTER_SCL_IO;
conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
conf.master.clk_speed = I2C_EXAMPLE_MASTER_FREQ_HZ;
i2c_param_config(i2c_master_port, &conf);
i2c_driver_install(i2c_master_port, conf.mode,
                   I2C_EXAMPLE_MASTER_RX_BUF_DISABLE,
                   I2C_EXAMPLE_MASTER_TX_BUF_DISABLE, 0);
```

espだけ設定項目が多いですね．
クロックの設定以外にもバッファとかプルアップの設定とかをしています
いろいろカスタマイズしたいときに融通がききそうです．

arduinoのi2cライブラリが`Wire`となっているのも混乱しやすい点かもしれません



## 書き込み（レスポンスなし書き込み）

次のようなコマンドを送る場合で比較します

1. start
2. SLASVE_ADDR + wr_bit
3. write 2 byte (SEND_DATA1,SEND_DATA2)
4. stop


obniz

```javascript
obniz.i2c0.write(slave_addr, [SEND_DATA1, SEND_DATA2]);
```

arduino

```c
Wire.beginTransmission(slave_addr);
Wire.write(SEND_DATA1);
Wire.write(SEND_DATA2);
Wire.endTransmission();
```

esp32

```c
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, SLASVE_ADDR << 1 | WRITE_BIT, ACK_CHECK_EN);
i2c_master_write_byte(cmd, SEND_DATA1, ACK_CHECK_EN);
i2c_master_write_byte(cmd, SEND_DATA2, ACK_CHECK_EN);
i2c_master_stop(cmd);
int ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
```


esp32はSLASVE_ADDRにwriteかreadかのフラグを自分で付加してbyte単位で書いていきます．
obnizとarduinoはそこは意識せずにSLASVE_ADDRを指定するだけですね

esp32だけ送信するコマンドを作る→送信するとなっているところも違いますね


## 読み込み（書き込みなしの読み込み）

受信は次のようなコマンドを送る場合で比較します

1. start
2. SLASVE_ADDR + read_bit
3. receive 3 byte 
4. stop

あんまりこれに対応してるデバイスは無いかもしれません

obniz

```javascript
var ret = await obniz.i2c0.readWait(SLASVE_ADDR, 3); //3byte読み込み
//ret = [data1,data2,data3]
```

arduino

```c
Wire.requestFrom(SLASVE_ADDR, 3);  //3byte読み込み命令

byte val1 = Wire.read(); //データ受信
byte val2 = Wire.read(); //データ受信
byte val3 = Wire.read(); //データ受信
```

esp32

```c
uint8_t data_rd[3];
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, ( SLASVE_ADDR << 1 ) | READ_BIT, ACK_CHECK_EN);
i2c_master_read(cmd, data_rd, 2, ACK_VAL); //2byteはackありで受信
i2c_master_read_byte(cmd, &data_rd[2], NACK_VAL); //3byteで終了なので最後はnackで受信
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
```

やはりespだけ設定が細かいですね．
obnizとarduinoは受信したいバイト数だけ書けばあとは内部でやってくれてますが，
espは自分でackとnackを考えながらコマンドを作る必要があるようです


## アドレス指定読み込み（レスポンスあり書き込み）

これが一番使うんじゃないでしょうか，

1. start
2. SLASVE_ADDR 
3. write 1 byte (WRITE_DATA)
4. receive 3 byte 
5. stop


obniz

```javascript
 obniz.i2c0.write(SLASVE_ADDR, [WRITE_DATA]);
 let val = await obniz.i2c0.readWait(SLASVE_ADDR, 3);
```


arduino

```c
Wire.beginTransmission(SLASVE_ADDR);
Wire.write(WRITE_DATA);
Wire.endTransmission(false);

Wire.requestFrom(0x1E, 3, true);

byte val1 = Wire.read();
byte val2 = Wire.read();
byte val3 = Wire.read();

```

esp32

```c
uint8_t data_rd[3];
i2c_cmd_handle_t cmd = i2c_cmd_link_create();

i2c_master_start(cmd);
i2c_master_write_byte(cmd, (SLASVE_ADDR << 1) | I2C_MASTER_WRITE, true);
i2c_master_write_byte(cmd, WRITE_DATA, true);

i2c_master_start(cmd);
i2c_master_write_byte(cmd, (SLASVE_ADDR << 1) | I2C_MASTER_READ, true);


i2c_master_read(cmd, data_rd, cnt-1, ACK_VAL);
i2c_master_read_byte(cmd, &data_rd[2], NACK_VAL);
i2c_master_stop(cmd);

i2c_master_cmd_begin(i2c_num, cmd,  1000 / portTICK_RATE_MS);

i2c_cmd_link_delete(cmd);
```


どれもwriteとreadをつなぎ合わせた形になっています
接続部分がそれぞれ違ってますね

obnizはそのままつなげていて，arduinoは`Wire.endTransmission(false);`と引数が入っています．
espは`i2c_master_stop(cmd)`をスキップしてつなげているようですね


## まとめ
それぞれ違いがありますが，espがダントツで難しいですね
その分，使いこなせばいろいろ細かくできるのでしょうが，規格が決まってるのでカスタマイズ項目って少ないような．．．

obnizもarduinoもi2cの簡単さという点では似たり寄ったりのレベルですね
arduinoだとWireって言葉になれるのが大変・・・ぐらいでしょうか，

## 参考文献

[obniz ドキュメント](https://obniz.io/doc/sdk/doc/i2c)
[arduino ドキュメント](https://www.arduino.cc/en/Reference/HomePage)
[esp ドキュメント](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/i2c.html)