RX64MマイコンでI2C通信

# はじめに
RX64MマイコンでI2C通信を試した際のポイントをまとめた記事です。

# 構成
* RXマイコンに搭載されている__SCI0__ を __I2Cマスター__ に設定
* RXは3.3V 信号なので3.3Vでプルアップ
* Arduinoが5V信号なのでケーブルの途中で __[I2Cレベルシフタ](https://www.switch-science.com/catalog/2396/)__を挟む


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204268/106bc4b2-1f83-51b0-30c8-b8fd649219a6.png)

# SCI0の設定

* スマートコンフィグレータを使用してSCI0を__I2Cマスター__ にします。
* 設定は下図の通り（対向デバイスが変わる場合は最適化必要）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204268/18341d4b-c5db-303a-326d-76ec8079045f.png)


# 生成されるコード
スマートコンフィグレータが吐き出したコードのプロトタイプ宣言を以下に示します。
先頭の「R_rx64m_SCI0」の部分は、__コンポーネント追加ダイアログで入力した名前__が反映されますので
デフォルトの名称とはことなっています。

```c:ヘッダファイル
void R_rx64m_SCI0_I2C_Create(void);
void R_rx64m_SCI0_I2C_Start(void);
void R_rx64m_SCI0_I2C_Stop(void);
void R_rx64m_SCI0_I2C_Create_UserInit(void);
void R_rx64m_SCI0_I2C_IIC_Master_Send(uint8_t adr, uint8_t * const tx_buf, uint16_t tx_num);
void R_rx64m_SCI0_I2C_IIC_Master_Receive(uint8_t adr, uint8_t * const rx_buf, uint16_t rx_num);
void R_rx64m_SCI0_I2C_IIC_StartCondition(void);
void R_rx64m_SCI0_I2C_IIC_StopCondition(void);
void r_rx64m_SCI0_I2C_transmitend_interrupt(void);
static void r_rx64m_SCI0_I2C_callback_transmitend(void);
static void r_rx64m_SCI0_I2C_callback_receiveend(void);
```

このうち使用するのは以下

関数| 説明
---|---
R_rx64m_SCI0_I2C_Create|各種レジスタの設定、起動時初期化で１回コールします。
R_rx64m_SCI0_I2C_Start|使用開始前に１回コールします。
R_rx64m_SCI0_I2C_IIC_Master_Send|ライト用関数。マスター(CPU)からスレーブ(Arduino)へデータを送りつけます。
R_rx64m_SCI0_I2C_IIC_Master_Receive|リード用関数。マスター(CPU)からアドレスとR/WビットをReadにした内容を送信し、スレーブからの応答を受け取ります。

# テストコード
## RXマイコン側

__R_rx64m_SCI0_I2C_IIC_Master_Send__ と __R_rx64m_SCI0_I2C_IIC_Master_Receive__の２つの関数の__第一引数であるadr__ にはI2Cのアドレスを入れます。

I2Cの規格では最初の１Byteは __アドレス7bit__ + __方向１bit__ (0がWrite 1がRead) となっています。
Send と Receive ２つの関数があるので、方向を示すbitは関数内で処理していると予想しましたが、実際は第一引数がそのまま出ている様子でした。（オシロで確認しました）

よって

* __R_rx64m_SCI0_I2C_IIC_Master_Send__の第一引数のLSBは__常に0__
* __R_rx64m_SCI0_I2C_IIC_Master_Receive__の第一引数のLSBは__常に1__

とすると上手く動作します。。。

３Byte送信し、３Byte受信、送信データを受信データで書き換える動作をします。

```c:main.c
void main(void){
    uint8_t     adr         =0      ;//7bit address
    uint8_t     dir         =0      ;//0:Write 1:Read
    uint8_t     tx_buf[4]   ={}     ;//
    uint8_t     rx_buf[4]   ={}     ;//
    
    R_rx64m_SCI0_I2C_Create();
    R_rx64m_SCI0_I2C_Start();
    
    while(1){
	//---- I2C Send RX to Arduino ----
        adr     =0x08    ;//7bit address
        dir     =0x00    ;//0:Write 1:Read
        adr     =(adr << 1) | (dir & 0x00);
        R_rx64m_SCI0_I2C_IIC_Master_Send(adr,&tx_buf[0],3);
        delay_ms(10);

        //---- I2C Send RX to Arduino ----
        adr     =0x08    ;//7bit address
        dir     =0x01    ;//0:Write 1:Read
        adr     =(adr << 1) | (dir & 0x01);
        R_rx64m_SCI0_I2C_IIC_Master_Receive(adr,rx_buf,3);
	
        printf("[0]=%02x , [1]=%02x , [2]=%02x\n" , rx_buf[0] , rx_buf[1] , rx_buf[2]);
        tx_buf[0] = rx_buf[0];
        tx_buf[1] = rx_buf[1];
        tx_buf[2] = rx_buf[2];
	delay_ms(10);
    }
}
```
## Arduino側のコード

受け取った３Byteのデータを
* 1Byte目 は＋1してリード時返す
* 2Byte目 は＋2してリード時返す
* 3Byte目 は＋3してリード時返す

```c:
#include <Wire.h>

byte dt[4]={};

//-----------------------------------------------
// データを受信時の処理
//-----------------------------------------------
void I2C_ReceiveHandler(int howMany) {
    int i=0;
    Serial.print("Receive :") ;
    while( Wire.available() ){
         dt[i] = Wire.read();
         i++;
    }
    Serial.print(dt[0] , HEX);
    Serial.print(" ");
    Serial.print(dt[1] , HEX);
    Serial.print(" ");
    Serial.println(dt[2] , HEX);
}
//-----------------------------------------------
//リクエスト受付時の処理
//-----------------------------------------------
void I2C_RequestHandler(){
    Serial.println("Responce :") ;
    Wire.write(dt[0] + 1) ;
    Wire.write(dt[1] + 2) ;
    Wire.write(dt[2] + 3) ;
    }
//-----------------------------------------------
//初期化
//-----------------------------------------------
void setup(){
    Serial.begin(9600); 
    Wire.begin(0x08);  //I2C Address set
    Wire.onRequest(I2C_RequestHandler);
    Wire.onReceive(I2C_ReceiveHandler);
    Serial.println(" Start");
}
//-----------------------------------------------
// main loop
//-----------------------------------------------
void loop(){
  delay(10);
  // no operate
}
```

# 動作確認

Arduinoの加算結果が反映されてRXマイコンに戻ってきました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204268/ca8f496d-abe8-5441-1d69-f426e5dbf12e.png)

アドレスの後３Byte送っている様子
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204268/a0f3507f-11de-f6d1-dc08-53b1ecdde2ad.png)