I2C (Inter – Integrated Circuit) 概要
I2C とは、フィリップ社が提唱した方式で、2本の接続線で1個のマスタに対して複数のスレーブとの通信が可能です。PICマイコンでもI2Cを使用して、様々な周辺機器を操作することができます。
I2C には通信速度があり、100kbps、400kbps、1Mbpsが標準となっています。
マスタとスレーブ間でデータの通信を行うSDA信号線と、マスタがスレーブにクロック送信するSCL信号線の2つで I2C が成り立っています。
また、SCL、SDA信号線には、数kΩのプルアップ抵抗が必要になります。
前提
I2Cの詳しい通信フォーマットや、仕組みについては割愛して、PICでI2Cを動かすことのみを記載します。
今回は、マスターモードの7ビットアドレス設定を前提として話を進めていきます。
SDA、SCLにつけるプルアップ抵抗は、PICに内蔵されているプルアップ抵抗で設定します。
また、MSSPは2を使用します。
MSSPとは、PICマイコンでI2Cピンが複数ある場合に使用するピンを選択できる機能のことです。
今回使用するPIC16F1827はI2Cピンが2つあります。MSSPの2を使用するということは、RB2ピンのSDA2とRB5のSCL2ピンをI2Cとして使用するということになります。
使用機器
- PICマイコン : PIC16F1827
I2C の初期設定プログラム
#include "mcc_generated_files/mcc.h"
void main(void)
{
// initialize the device
SYSTEM_Initialize();
WPUB = 0x24; //SDA2、SCL2にプルアップ抵抗を設定
OPTION_REGbits.nWPUEN = 0; //プルアップ抵抗を有効化
SSP2ADD = 0x13;
SSP2CON1 = 0x28;
SSP2CON2 = 0x0;
SSP2STAT = 0;
}
I2C 制御のヘッダプログラム
#include <xc.h>
void i2c_wait();
void i2c_start();
void i2c_stop();
void i2c_repeated_start();
void i2c_write(uint8_t data);
uint8_t i2c_read(uint8_t ack);
I2C 制御のプログラム
#include "i2c.h"
void i2c_wait(){
while((SSP2CON2 & 0x1F) || (SSP2STAT & 0x04));
}
void i2c_start(){
i2c_wait();
SSP2CON2bits.SEN = 1;
while(SSP2CON2bits.SEN);
}
void i2c_stop(){
SSP2CON2bits.PEN = 1;
while(SSP2CON2bits.PEN);
}
void i2c_repeated_start(){
i2c_wait();
SSP2CON2bits.RSEN = 1;
while(SSP2CON2bits.RSEN);
}
void i2c_write(uint8_t data){
SSP2BUF = data;
while(SSP2STATbits.BF);
while(SSP2CON2bits.ACKSTAT);
i2c_wait();
}
uint8_t i2c_read(uint8_t ack){
uint8_t data;
SSP2CON2bits.ACKDT = ack;
SSP2CON2bits.RCEN = 1;
while(!SSP2STATbits.BF);
SSP2CON2bits.ACKEN = 1;
data = SSP2BUF;
SSP2CON1bits.SSPOV = 0;
i2c_wait();
return data;
}
I2C を使用するためのレジスタ
上記にI2Cをマスターモードで動作させる初期設定を記述しましたが、どういう設定をしたか忘れないように詳しい設定を以下に残します。
I2C通信を制御するレジスタは以下の通りです。SSPx(xは1か2のどちらかを選択 )
※PICマイコンによる xに値を入れないPICもある
今回のサンプルプログラムでは、2を選択
SSPxADDレジスタ
SSPxADDレジスタは、マスタとスレーブで使用目的が異なります。今回はマスターモードの設定方法を説明します。
マスタの場合は、下位7bitがI2Cの通信速度を設定するレジスタとなります。
速度設定の計算式は以下のようになります。
I2Cの通信速度 = Fosc(PICのクロック周波数) / ( 4 * (SSPxADD値 + 1 ))
ですが、計算するのも面倒なので、よく使う設定値を残します。
PICのクロック周波数 | SSPxADD 設定値 | I2Cの通信速度 |
32MHz | 0x13 | 400kbps |
0x4F | 100kbps | |
16MHz | 0x09 | 400kbps |
0x27 | 100kbps | |
8MHz | 0x13 | 100kbps |
4MHz | 0x09 | 100kbps |
PICのクロック周波数を8MHzにして、I2Cの通信速度を100kbpsに設定する場合は以下のようにします。
SSP2ADD = 0x13;
SSPxSTATレジスタ
bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 |
SMP | CKE | D/A | P | S | R/W | UA | BF |
I2Cをマスタモードで使用する場合、ほとんどSSPxSTATレジスタで設定することはありません。
7bit目のSMPの部分のみを変更するのみです。あとは全部0で動きました。
SSP2STAT = 0x0; //400kbps
SSP2STAT = 0x01; //100kbps
一応説明を載せておきます。
- SMP (スルーレート制御)
- 1:無効 (I2Cの通信速度が、100kbpsの場合)
- 0:有効 (I2Cの通信速度が、400kbpsの場合)
- CKE (SMbus互換入力有効化)
- 1:有効
- 0:無効
- D/A (受信データ区別)
- 1:データ
- 0:アドレス
- P (Stop Condition検出)
- 1:検出した
- 0:未検出
- S (Start Condition検出)
- 1:検出した
- 0:未検出
- R/W (Read/Write検出) スレーブの場合
- 1:Read受信
- 0:Write受信
- R/W (Read/Write検出) マスタの場合
- 1:送信中
- 0:レディ
- UA (アドレス更新) 10ビットモード
- 1:SSPxADDの更新必要
- 0:不要
- BF (ブッファフル状態)
- 1:データ転送中
- 0:転送完了
SSPxCON1レジスタ
bit7 | bit6 | bit5 | bit4 | bit3~bit0 |
WCOL | SSPOV | SSPEN | CKP | SSPM<3:0> |
- WCOL (Writeの衝突検出)
- 1: 衝突発生
- 0: 衝突なし
- SSPOV (受信オーバーフロー検出)
- 1:オーバーフロー発生
- 0:正常
- SSPEN (SSPモジュール使用許可/禁止)
- 1:SDAとSCLピンとして使用
- 0:汎用I/Oポートとして使用
- CKP (SCKクロック制御)
- 1:ストレッチオフ
- 0:ストレッチオン
- SSPM<3:0> (SSPxのI2Cモード設定)
- 0110 : I2Cのスレーブモード (7ビットアドレス)
- 0111 : I2Cのスレーブモード (10ビットアドレス)
- 1000 : I2Cマスタモード
- 1011 : I2C FW制御マスターモード
- 1110 : I2Cスレーブモード Start/Stop割り込み許可 (7ビットアドレス)
- 1111 : I2Cスレーブモード Start/Stop割り込み許可 (10ビットアドレス)
SSPxCON1レジスタの設定は上記のようになっています。
(例)I2Cをマスターモードで使用したい場合は以下のように書きます。
WCOL | SSPOV | SSPEN | CKP | SSPM | SSPM | SSPM | SSPM |
bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 |
0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 |
SSP2CON1 = 0x28;
SSPxCON2レジスタ
bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 |
GCEN | ACKSTAT | ACKDT | ACKEN | RCEN | PEN | RSEN | SEN |
I2Cをマスタモードで使用する場合、特に特別な設定をしない限りSSPxCON2レジスタで設定することはありません。
以下のようにコードを書けば大丈夫です。
SSP2CON2 = 0x0;
一応説明を以下に残します。
- GCEN (同報検出許可) スレーブのみ
- 1:許可
- 0:禁止 (アドレス0000H)
- ACKSTAT (ACK検出)
- 1:ACK未受信
- 0:受信済み
- ACKDT (送信するACK設定)
- 1:NACK
- 0:ACK
- ACKEN (ACKシーケンス開始) マスタ受信中のみ
- 1:ACKDTビットを送信する (送信後自動クリア)
- RCEN (受信許可) マスタのみ
- 1:受信許可
- 0:禁止 Idleに
- PEN (Stop Condition開始) マスタのみ
- 1:Stop Condition送信 (送信後自動クリア)
- RSEN (Repeat Start Condition開始) マスタのみ
- 1:Repeat Start Condition (送信後自動クリア)
- SEN (Start Condition / Stretch開始)
- 1:Start Conditionを送信、完了で自動的に0 (マスタのみ)
- 1:Stretchを許可 (スレーブのみ)
- 0:禁止 (スレーブのみ)