はじめに
I2Cの設定諸々についての記述.マスター用.マイコンボードはGR-CITRUSとする.ハードウェアマニュアルの参考先はHM *.*.*と表記する(例:HM 3.3.4ならばハードウェアマニュアルの3.3.4節を参考).
資料(必需品)
・ RX63Nグループ、RX631グループ ユーザーズマニュアル
・ GR-CITRUS回路図
I2Cとは
クロックとデータの2本の信号線で行うシリアル通信の手法.
I2C設定
I2Cのための初期化とデータ送受信のための関数の作成を行う.回路図とHM 1.5 表1.10より,端子P12,P13をSCL0,SDA0として設定していく.
マスターの初期化関数
初期化の方法はHM 36.3.2 図36.5 に記載されている.
流れ
- 端子機能の設定
- リセット
- スレーブ・マスター設定
- 通信ビットレート設定
- タイムアウト設定
- NACKACKの送信許可
- その他設定
- 内部リセット解除
void RIIC0_init(void);
void HardwareSetup(void)
{
RIIC0_init();
}
/*=================================
* 関数名 : 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;
}
マスターでの受信のための関数
/*=================================
* 関数名 : 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;
}
# 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);
}
}
マスターでの送信のための関数
/*=================================
* 関数名 : 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;
}
# 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. リセット
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. スレーブ・マスター設定
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. 通信ビットレート設定
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やRC回路等を見て自分で立ち上がり時間を設定しても良い.
5. タイムアウト設定
RIIC0.ICMR2.BYTE = 0x00;
HM 36.2.4より,タイムアウト機能を設定する.
6. NACK/ACKの送信許可
RIIC0.ICMR3.BIT.ACKWP = 1;
HM 36.2.5より,NACK/ACKを送信できるようにする.
7. その他設定
RIIC0.ICFER.BIT.NFE = 1;
RIIC0.ICIER.BYTE = 0x00;
HM 36.2.6より,デジタルノイズフィルタを有効にする.
HM 36.2.8より,割り込み設定をする.
8. 内部リセット解除
RIIC0.ICCR1.BIT.IICRST = 0;
HM 36.2.1より,内部リセットを解除する.
マスターでの受信のための関数
HM 36.3.4 マスター送信動作の図36.10に従う.受信した順番に配列に格納されるので必要に応じてビット演算を行う.
マスターでの送信のための関数
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/
- C言語の計算式と条件式 http://www3.nit.ac.jp/~tamura/ex2/expression.html