ArduinoとESP32（M5Cameraとか）間でI2C通信する方法

**I2C communication method between Arduino and ESP32 (M5Camera etc.)**
Click [here](https://github.com/saka-guchi/I2C_Between_Arduino_and_ESP32 "I2C_Between_Arduino_and_ESP32") for English commentary and sample code.

# 前提
下記については説明を省略します。
- Arduino IDEでのESP32（M5Camera含む）の開発環境の構築
- C言語の基礎知識

※[Arduino同士でI2C通信する方法](https://qiita.com/hikoalpha/items/7bf563ee286a59bfd2f4"Arduino同士でI2C通信する方法")を先に読むと理解しやすいです。

# 解決する課題

ArduinoとESP32（M5Cameraとか）を接続（今回はI2C）してデータをやり取りしたい！

対応後のイメージ
![I2C_Code.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691672/52840fdf-1814-b1fb-4076-cd6ab8ee7913.png)

左側がMaster（以後、**Main**）のESP32（M5Camera）
右側がSlave（以後、**Sub**）のArduino（M0 PRO）
の間でデータを送受信している様子

# 手順概要

1. 2つのマイコンをI2Cで接続する
1. スケッチ例を参考にしてESP32に対応する
1. スケッチを環境に合わせて編集する
1. I2C経由でのデータの受け渡しを確認する

# 手順詳細
## 1. 2つのマイコンをI2Cで接続する
![circuit_diagram.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691672/42155a07-967a-29ac-6242-868eabb6dfbf.jpeg)
両方ともUSB経由でPCに接続しています。

- M5CameraはGroveコネクタを利用
- M5CameraからArduinoへ電源を供給

| ESP32 M5Camera | Arduino M0 PRO |
| --- | --- |
| GND | GND |
| 5V | Vin |
| SDA (13) | SDA (16) |
| SCL (4) | SCL (17) |

## 2. スケッチ例を参考にしてESP32に対応する

1. 参考にしたライブラリたち
    - [I2cScanner](https://playground.arduino.cc/Main/I2cScanner/)
    - [Master Writer/Slave Receiver](https://www.arduino.cc/en/Tutorial/MasterWriter)
        - [File] > [Examples] > [Wire] > [master_writer]
        - [File] > [Examples] > [Wire] > [slave_receiver]
    - [Master Reader/Slave Sender](https://www.arduino.cc/en/Tutorial/MasterReader)
        - [File] > [Examples] > [Wire] > [master_reader]
        - [File] > [Examples] > [Wire] > [slave_sender]
2. 修正（数行レベル）したコードがこちら
    - I2Cスキャン用：[I2C_Scanner.ino](https://github.com/saka-guchi/I2C_Between_Arduino_and_ESP32/blob/master/I2C_Scanner/I2C_Scanner.ino)
    - Mainマイコン用：[I2C_Main.ino](https://github.com/saka-guchi/I2C_Between_Arduino_and_ESP32/blob/master/I2C_Main/I2C_Main.ino)
    - Subマイコン用：[I2C_Sub.ino](https://github.com/saka-guchi/I2C_Between_Arduino_and_ESP32/blob/master/I2C_Sub/I2C_Sub.ino)

## 3. スケッチを環境に合わせて編集する
### 3-1. アップロードするマイコンに合わせる
上記3ファイルすべてに下記の定義があるので、

```
#define MICON_ESP32              // undefined if Arduino
```

Arduinoの場合は、コメントアウトする。

```
// #define MICON_ESP32              // undefined if Arduino
```

### 3-2. サブマイコンのアドレスを変更する

[I2C_Sub.ino](https://github.com/saka-guchi/I2C_Between_Arduino_and_ESP32/blob/master/I2C_Sub/I2C_Sub.ino)の下記定義を変更する。

```
#define ADDRESS 0x8
```

## 4. I2C経由でのデータの受け渡しを確認する
### 4-1. I2Cで接続できていることを確認する
1. 下記の通り、スケッチをアップロードして実行
2. [I2C_Sub.ino](https://github.com/saka-guchi/I2C_Between_Arduino_and_ESP32/blob/master/I2C_Sub/I2C_Sub.ino) で定義したアドレスが見つかればOK

| (Main) ESP32 M5Camera | (Sub) Arduino M0 PRO |
| --- | --- |
| [I2C_Scanner.ino](https://github.com/saka-guchi/I2C_Between_Arduino_and_ESP32/blob/master/I2C_Scanner/I2C_Scanner.ino) | [I2C_Sub.ino](https://github.com/saka-guchi/I2C_Between_Arduino_and_ESP32/blob/master/I2C_Sub/I2C_Sub.ino) |
![I2C_Scanner.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691672/07446b6b-61c7-7de9-777f-fc202809b398.png)
Main側のシリアルモニタ出力の抜粋

```
I2C device found at address 0x08  ! ← Sub
I2C device found at address 0x28  ! ← Main
```

### 4-2. マイコン間でデータを渡せるか確認する
1. 下記の通り、スケッチをアップロードして実行
2. Main、Subのシリアルモニタに期待した出力が表示されればOK

| (Main) ESP32 M5Camera | (Sub) Arduino M0 PRO |
| --- | --- |
| [I2C_Main.ino](https://github.com/saka-guchi/I2C_Between_Arduino_and_ESP32/blob/master/I2C_Main/I2C_Main.ino) | [I2C_Sub.ino](https://github.com/saka-guchi/I2C_Between_Arduino_and_ESP32/blob/master/I2C_Sub/I2C_Sub.ino) |

Arduino IDEでのコードとシリアルモニタの様子
![I2C_Code.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691672/52840fdf-1814-b1fb-4076-cd6ab8ee7913.png)

Main側のシリアルモニタ出力の抜粋

```
writer:                   ← write("x is 16");
reader: hello             ← read();
```

Sub側のシリアルモニタ出力の抜粋

```
receiveEvent: x is 16     ← read();
requestEvent:             ← write("hello\n");
```



# まとめ
MainとSub、各1ファイルで下記の対応を実施した。
1. **ArduinoとESP32の両方に対応**
2. **Writer/ReceiverとReader/Senderの両方に対応**

但し、ESP32は標準ライブラリ(TwoWire)にI2C Slave機能が搭載されていないため[^1]、対応はしていない[^2]。

どうしても使いたい場合は、下記ライブラリを利用するとよい。

- [ESP32 I2C Slave](https://www.arduino.cc/reference/en/libraries/esp32-i2c-slave/)
    - 合わせて、I2C Slave機能が公式サポートされるかの議論へのリンクが下の方に掲載されている

[^1]: 2020/08/15時点
[^2]: コンパイルエラーが出力される