I2C（マスター）

# はじめに
I2Cの設定諸々についての記述．マスター用．マイコンボードはGR-CITRUSとする．ハードウェアマニュアルの参考先はHM ＊.＊.＊と表記する（例：HM 3.3.4ならばハードウェアマニュアルの3.3.4節を参考）．

資料（必需品）
・ [RX63Nグループ、RX631グループ ユーザーズマニュアル](https://www.marutsu.co.jp/contents/shop/marutsu/datasheet/R5F563.pdf)
・ [GR-CITRUS回路図](https://www.renesas.com/jp/ja/doc/gr/gr-citrus/citrus-1.0.pdf)

# I2Cとは

クロックとデータの2本の信号線で行うシリアル通信の手法．

# I2C設定
I2Cのための初期化とデータ送受信のための関数の作成を行う．回路図とHM 1.5 表1.10より，端子P12，P13をSCL0，SDA0として設定していく．

### マスターの初期化関数

初期化の方法はHM 36.3.2 図36.5 に記載されている．
流れ
1. 端子機能の設定
2. リセット
3. スレーブ・マスター設定
4. 通信ビットレート設定
5. タイムアウト設定
6. NACKACKの送信許可
7. その他設定
8. 内部リセット解除

```c:"hwsetup.c"
void RIIC0_init(void);

void HardwareSetup(void)
{
	RIIC0_init();
}
```
```c:
/*=================================
 * 関数名 : RIIC0_init
 * 機能 : R2C0の初期化
 * 引数 : なし
 * 戻り値 : なし
 * 備考 :通信速度 400kbps
 * ===============================*/
void RIIC0_init(void)
{
	/*=== プロテクト解除 ===*/
	SYSTEM.PRCR.WORD = 0xA502;
	/*=== RIIC0を有効化 ===*/
	MSTP(RIIC0) = 0;
	/*=== プロテクト ===*/
	SYSTEM.PRCR.WORD = 0xA500;
	/*=== 端子機能の有効化 ===*/
	PORT1.PMR.BIT.B2 = 1;
	PORT1.PMR.BIT.B3 = 1;
	/*=== 入力プルアップの有効化 ===*/
	PORT1.PDR.BIT.B2 = 0;
	PORT1.PDR.BIT.B3 = 0;
	PORT1.PCR.BIT.B2 = 1;
	PORT1.PCR.BIT.B3 = 1;
	/*=== ピン機能設定 プロテクト解除===*/
	MPC.PWPR.BIT.B0WI = 0;
	MPC.PWPR.BIT.PFSWE = 1;
	/*=== ピン機能設定 ===
	 * P12 > SCL0
	 * P13 > SDA0
	 * ================*/
	MPC.P12PFS.BIT.PSEL = 0x0F;
	MPC.P13PFS.BIT.PSEL = 0x0F;
	/*=== ピン機能設定 プロテクト===*/
	MPC.PWPR.BIT.PFSWE = 0;
	MPC.PWPR.BIT.B0WI = 1;
	/*=== RIIC0駆動停止 ===*/
	RIIC0.ICCR1.BIT.ICE = 0;
	/*=== RIIC0リセット ===*/
	RIIC0.ICCR1.BIT.IICRST = 1;
	/*=== 内部リセット ===*/
	RIIC0.ICCR1.BIT.ICE = 1;
	/*=== スレーブ設定 ===
	 * マスターとして使うため全て無効とする
	 * ===============*/
	RIIC0.SARU0.BIT.FS = 0;
	RIIC0.SARL0.BIT.SVA = 1;
	RIIC0.ICSER.BYTE = 0;
	/*=== 通信ビットレート設定 ===
	 * 転送速度 400kbps
	 * ===============*/
	RIIC0.ICMR1.BIT.CKS = 2;
	RIIC0.ICBRH.BIT.BRH = 7;
	RIIC0.ICBRL.BIT.BRL = 15;
	/*=== タイムアウト設定 > 無効 ===*/
	RIIC0.ICMR2.BYTE = 0x00;
	/*=== NACK/ACKの送信許可 ===*/
	RIIC0.ICMR3.BIT.ACKWP = 1;
	/*=== デジタルノイズフィルタの有効 ===*/
	RIIC0.ICFER.BIT.NFE = 1;
	/*=== 割り込み設定 > 全て禁止===*/
	RIIC0.ICIER.BYTE = 0x00;
	/*=== リセット解除 ===*/
	RIIC0.ICCR1.BIT.IICRST = 0;
}
```

### マスターでの受信のための関数

```c:"iic.c"
/*=================================
 * 関数名 : IIC_read
 * 機能 : マスターでの受信
 * 引数 : なし
 * 戻り値 : スレーブアドレス7bit，データ配列，データの要素数
 * 備考 :
 * ===============================*/
void IIC_read(unsigned char address, unsigned char data[],int data_num)
{
	int i;
	unsigned char dummy;
	/*=== I2Cバス占有状態判定 > 解放状態か？ ===*/
	while(RIIC0.ICCR2.BIT.BBSY);
	/*=== 開始条件発行 ===*/
	RIIC0.ICCR2.BIT.ST = 1;
	/*=== 送信データの有無 > 無しか？ ===*/
	while(!RIIC0.ICSR2.BIT.TDRE);
	/*=== スレーブアドレス+readの送信 ===*/
	RIIC0.ICDRT = (address << 1) | 0x01;
	/*=== ACK待機 ===*/
	while(!RIIC0.ICSR2.BIT.RDRF);
	/*=== NACKの検出判定 ===*/
	if(RIIC0.ICSR2.BIT.NACKF == 0) //NACK未検出
	{

		/*=== ダミーリード ===*/
		dummy = RIIC0.ICDRR;
		/*=== 受信 ===*/
		for(i=0;i<data_num-1;i++)
		{
			/*=== ACK待機 ===*/
			while(!RIIC0.ICSR2.BIT.RDRF);
			/*=== 最終データ受信準備 ===*/
			if(i==data_num-2) //最後-1のデータ
			{
				/*=== データ受信完了（NACK送信） ===*/
				RIIC0.ICMR3.BIT.ACKBT = 1;
			}
			if(i==data_num-3) //最後-2のデータ
			{
				/*=== waitありに変更 ===*/
				RIIC0.ICMR3.BIT.WAIT = 1;
			}
			/*=== 受信データ格納 ===*/
			data[i] = RIIC0.ICDRR;
		}
		/*=== ACK待機 ===*/
		while(!RIIC0.ICSR2.BIT.RDRF);
		/*=== ストップコンディション未検出 ===*/
		RIIC0.ICSR2.BIT.STOP = 0;
		/*=== 停止条件の発行 ===*/
		RIIC0.ICCR2.BIT.SP = 1;
		/*=== 最終受信データ格納 ===*/
		data[data_num-1] = RIIC0.ICDRR;
		/*=== waitなしに変更 ===*/
		RIIC0.ICMR3.BIT.WAIT = 0;
		
	}else{ //NACK検出
		/*=== 停止条件未検出 ===*/
		RIIC0.ICSR2.BIT.STOP = 0;
		/*=== 停止条件の発行 ===*/
		RIIC0.ICCR2.BIT.SP = 1;
		/*=== ダミーリード ===*/
		dummy = RIIC0.ICDRR;
	}
	/*=== 停止条件確認 ===*/
	while(!RIIC0.ICSR2.BIT.STOP);
	/*=== NACK未検出 ===*/
	RIIC0.ICSR2.BIT.NACKF = 0;
	/*=== 停止条件未検出 ===*/
	RIIC0.ICSR2.BIT.STOP = 0;
}

```

```c:"main.c"
#include"iodefine.h"
#include"main.h"
#include"icu_cmt.h"
#include"iic.h"
void main(void)
{
	unsigned char data[2];
	unsigned short angle = 0;

	while(1)
	{
		IIC_read(0x36, data,2);
		angle = (data[1] << 8) & 0x0F00;
		angle |= data[0];
		LED = LED_ON;
		Delay(angle);
		LED = LED_OFF;
		Delay(angle);

	}

}
```

### マスターでの送信のための関数
```c:"iic.c"
/*=================================
 * 関数名 : IIC_write
 * 機能 : マスターでの送信
 * 引数 : なし
 * 戻り値 : スレーブアドレス7bit，データ配列，データの要素数
 * 備考 :
 * ===============================*/
void IIC_write(unsigned char address, unsigned char data[],int data_num)
{
	int i;
	/*=== I2Cバス占有状態判定 > 解放状態か？ ===*/
	while(RIIC0.ICCR2.BIT.BBSY);
	/*=== 開始条件発行 ===*/
	RIIC0.ICCR2.BIT.ST = 1;
	/*=== NACKの検出判定 ===*/
	if(RIIC0.ICSR2.BIT.NACKF == 0) //NACK未検出
	{
		/*=== 送信データの有無 > 無しか？ ===*/
		while(!RIIC0.ICSR2.BIT.TDRE);
		/*=== スレーブアドレス+readの送信 ===*/
		RIIC0.ICDRT = (address << 1) | 0x00;
		/*=== 送信 ===*/
		for(i=0;i<data_num;i++)
		{
			/*=== 送信待機 ===*/
			while(!RIIC0.ICSR2.BIT.TDRE);
			/*=== 送信データ格納 ===*/
			RIIC0.ICDRT = data[i];
		}
		/*=== 送信完了待機 ===*/
		while(!RIIC0.ICSR2.BIT.TEND);
	}
	/*=== ストップコンディション未検出 ===*/
	RIIC0.ICSR2.BIT.STOP = 0;
	/*=== 停止条件の発行 ===*/
	RIIC0.ICCR2.BIT.SP = 1;
	/*=== 停止条件確認 ===*/
	while(!RIIC0.ICSR2.BIT.STOP);
	/*=== NACK未検出 ===*/
	RIIC0.ICSR2.BIT.NACKF = 0;
	/*=== 停止条件未検出 ===*/
	RIIC0.ICSR2.BIT.STOP = 0;
}

```

```c:"main.c"
#include"iodefine.h"
#include"iic.h"

void main(void)
{
	unsigned char sign[1] = {0x0C};
	unsigned char address = 0x36;
	IIC_write(address, sign,1);

}
```

# 詳細

#### マスターの初期化関数

##### 1. 端子機能の設定

```
SYSTEM.PRCR.WORD = 0xA502;
```
**プロテクト解除**
HM 13.1.1より，保護するレジスタへの書き込み許可を選択する．`PRCR`は16bit構成で以下のような内容である．`WORD`で一括で設定している．
b0 > 0 :クロック発生回路関連レジスタへの書き込み禁止
b1 > 1 :動作モード、消費電力低減機能、ソフトウェアリセット関連レジスタへの書き込み許可
b2 > 0 :予約ビット
b3 > 0 :LVD関連レジスタへの書き込み禁止
b7-4 > 0 :予約ビット
b15-8 > A5 : PRCキーコードビット 

```
MSTP(RIIC0) = 0;
```
**モジュールストップ解除**
HM 11.4より，レジスタの読み出し書き込みができる状態にする必要がある．`=0`で解除となる．

```
SYSTEM.PRCR.WORD = 0xA500;
```
**プロテクト**
HM 13.1.1より，保護するレジスタへの書き込みを禁止する．

```
PORT1.PMR.BIT.B2 = 1;
PORT1.PMR.BIT.B3 = 1;
```
**端子機能の有効化**
HM 1.5 表1.10より，必要な機能が備わっている端子を選定する．HM 21.3.4より，`=1`で端子機能を有効化する．

```
PORT1.PDR.BIT.B2 = 0;
PORT1.PDR.BIT.B3 = 0;
PORT1.PCR.BIT.B2 = 1;
PORT1.PCR.BIT.B3 = 1;
```
**入力プルアップの有効化**
HM21.3.1より，入力端子として設定する．HM21.3.7より，`=1`で入力プルアップ抵抗有効にする．

```
MPC.PWPR.BIT.B0WI = 0;
MPC.PWPR.BIT.PFSWE = 1;
```
**ピン機能設定 プロテクト解除**
HM 22.2.1より，初めに`B0WI = 0`でPFSWEレジスタへの書き込みを許可する．次に，`PFSWE = 1`でPFSレジスタへの書き込みを許可する．許可順番は必ず守る．

```
MPC.P12PFS.BIT.PSEL = 0x0F;
MPC.P13PFS.BIT.PSEL = 0x0F;
```
**ピン機能設定**
HM 22.2.3より，周辺機能を設定する．ここでは，P12をSCL0，P13をSDA0として設定している．レジスタへの値は表で指定されたものを書き込む．

```
MPC.PWPR.BIT.PFSWE = 0;
MPC.PWPR.BIT.B0WI = 1;
```
**ピン機能設定 プロテクト**
HM 22.2.1より，順次プロテクトする．プロテクト順番は必ず守る．

##### 2. リセット
```c
RIIC0.ICCR1.BIT.ICE = 0;
RIIC0.ICCR1.BIT.IICRST = 1;
RIIC0.ICCR1.BIT.ICE = 1;
```
HM 36.2.1より，RIICリセットと内部リセットを行う．`ICE=0`でIICの非駆動状態する．次に，`IICRST=1`でRIICリセットする．`IICRST=1`の時に`ICE=1`で内部リセットとなる．

##### 3. スレーブ・マスター設定
```c
RIIC0.SARU0.BIT.FS = 0;
RIIC0.SARL0.BIT.SVA = 1;
RIIC0.ICSER.BYTE = 0;
```
HM 36.2.12より，`FS=0`でアドレスを7ビットに設定する．HM 36.11より，スレーブアドレスを設定する．マスターとして使用する場合は適当な値を入れておく．HM 36.2.7より，スレーブアドレスを無効としてマスターとして設定する．

##### 4. 通信ビットレート設定
```c
RIIC0.ICMR1.BIT.CKS = 2;
RIIC0.ICBRH.BIT.BRH = 7;
RIIC0.ICBRL.BIT.BRL = 15;
```
HM 36.2.3より，PCLKの分周比を決定し，内部クロックを設定する．
HM 36.2.14より，highとlowの幅を決定することで，転送速度を設定する．

転送速度 = 1 / {[ (ICBRH+1) ＋ (ICBRL+1) ] / IICφ（注 1）＋ SCLn ライン立ち上がり時間 [tr] ＋SCLn ライン立ち下がり時間 [tf] }

表36.5に設定例が示されているので，そこを見本に設定するのが良い．[UM10204 I2C](http://pgstudynotes.blogspot.com/2017/05/initriic0rx63n.html)や[RC回路](https://algorithm.joho.info/denki-denshi/rc-circuit-time-constant/)等を見て自分で立ち上がり時間を設定しても良い．

##### 5. タイムアウト設定
```c
RIIC0.ICMR2.BYTE = 0x00;
```
HM 36.2.4より，タイムアウト機能を設定する．

##### 6. NACK/ACKの送信許可
```c
RIIC0.ICMR3.BIT.ACKWP = 1;
```
HM 36.2.5より，NACK/ACKを送信できるようにする．

##### 7. その他設定
```c
RIIC0.ICFER.BIT.NFE = 1;
RIIC0.ICIER.BYTE = 0x00;
```
HM 36.2.6より，デジタルノイズフィルタを有効にする．
HM 36.2.8より，割り込み設定をする．

##### 8. 内部リセット解除
```c
RIIC0.ICCR1.BIT.IICRST = 0;
```
HM 36.2.1より，内部リセットを解除する．

#### マスターでの受信のための関数
HM 36.3.4 マスター送信動作の図36.10に従う．受信した順番に配列に格納されるので必要に応じて[ビット演算](http://www3.nit.ac.jp/~tamura/ex2/expression.html)を行う．

#### マスターでの送信のための関数
HM 36.3.3 マスター送信動作の図36.6に従う．

# 参考文献

- I2C通信の使い方 http://www.picfun.com/c15.html
- 東芝MCUの7種類のシリアルインタフェース https://toshiba.semicon-storage.com/jp/design-support/e-learning/mcupark/village/serial-interface-2.html
- 【備忘録】RX62N I2C(RIIC) 通信用プログラム http://kmtsatisfy.hatenablog.com/entry/2015/08/06/005024
- UM10204 I2C バス仕様およびユーザーマニュアル　https://www.nxp.com/docs/ja/user-guide/UM10204.pdf
- RC回路とは https://algorithm.joho.info/denki-denshi/rc-circuit-time-constant/
- Ｃ言語の計算式と条件式 http://www3.nit.ac.jp/~tamura/ex2/expression.html