TOP > MPLAB XC8編(PIC16F886) > I2CでEEPROMを使う(PIC16F886 XC8)

I2CでEEPROMを使う
(PIC16F886 XC8)
作成日2012.6.24



ここでは、シリアルインタフェースの一つである、I2C(Inter-Integrated Circuit、アイ・スクエア・シー)でEEPROMを使ってみます。

使用するPICはPIC16F886です。
PIC16F886が保有するI2Cのマスタモードを使用します。
このページの目次
1.I2Cの使い方
  (1) I2Cの概要
  (2) I2Cで使用するレジスタ
  (3) データの送信方法
  (4) データの受信方法
2.実験回路
3.プログラムの仕様
  ・プログラムの流れ
  ・EEPROMへの書き込み
  ・EEPROMからの読み出し
  ・DEVICE ADDRESS
  ・EEPROMのメモリアドレス指定
4.プログラム全体

1.I2Cの使い方
I2Cは、フィリップス社により開発されたシルアル通信の規格です。
シリアル通信には、RS-232、IEEE 1394、シリアルATAなど多くの規格がありますが、I2Cは主に近距離のデバイス(PICやEEPROMなどのIC)間通信に利用されています。

(1) I2Cの概要
I2Cは、下図のようにSCL(シリアルクロックライン)とSDA(シリアルデータライン)という2本のバスライン上に複数のデバイスを接続した構成になっています。 SCL/SDAともに抵抗でプルアップします。


各デバイスの動作モードには、マスタモードスレーブモードがあります。
通信を開始するデバイスマスタとなり、通信先として選択されたデバイススレーブとなって、同時には1対1で通信を行います。
通常は、PICなどのマイクロコンピュータがマスタとなって、EEPROMなどのデバイスをスレーブとして制御します。

各デバイスには、バス上で一意になるアドレスを付与し、マスタはこのアドレスを指定して通信先のデバイスを選択します。

今回は、PICでEEPROMを使用しますので、PICをマスタモード、EEPROMをスレーブモードとして動作させます。

I2Cのバス制御やデータフォーマットなどについては、I2Cをプログラムで実装を参照して下さい。

(2) I2Cで使用するレジスタ
PIC16F886には、MSSP(Master Synchronous Serial Port)モジュールが内蔵されています。 このMSSPモジュールでI2Cをサポートしています。
I2Cの動作は、マスタモード/スレーブモードの両方をサポートしていますが、ここではマスタモードのみ使用します。

I2Cで使用するレジスタは以下の通りです。マスタモードの動作を中心に記述します。
具体的な使い方は、(3) データの送信方法/(4) データの受信方法で例示します。

レジスタ概要
SSPSTAT同期シリアルポートステータスレジスタ
I2Cの状態などが設定される。
SSPCON同期シリアルポートコントロールレジスタ
I2Cの動作モードなどを設定する。
SSPCON2同期シリアルポートコントロールレジスタ2
I2Cの動作を制御する。
SSPADDSSP アドレスレジスタ
マスタモードの場合は、クロック設定のパラメータとして使われる。
SSPBUFシリアル受信/送信バッファ
送信するデータを格納する。または、受信したデータが格納される。
この他に、SSP(I2C)の割込み機能を使う場合は、割込み関連のレジスタ(INTCON、PIR1、PIE1)も影響します。
割込み機能を使わない場合でも、PIR1レジスタのSSPIFビットの判定やクリアが必要です。

SSPSTAT
bit7bit6bit5bit4bit3bit2bit1bit0
SMPCKED/^APSR/^WUABF
RWRWRRRRRR
RW:読み書き可能、R:参照専用

SMPサンプルビット
1=標準速度モード(100kHz および1MHz)、スルーレート制御は行わない
0=高速モード(400kHz)、スルーレート制御を行う
CKE0 (I2Cでは未使用)
D/^Aデータ/アドレスビット
1=最後に受信または送信したバイトはデータであった
0=最後に受信または送信したバイトはアドレスであった
Pストップビット
1=最後に検出されたのはストップビットであったことを示す(このビットはリセット時には「0 」になる)
0=最後に検出されたのはストップビットではなかった
Sスタートビット
1=最後に検出されたのはスタートビットであったことを示す(このビットはリセット時には「0」になる)
0=最後に検出されたのはスタートビットではなかった
R/^Wリード/ ライトビット情報
1=送信中
0=送信していない
UAアドレス更新(10 ビットアドレスのI2Cモードのみ)
1=SSPADD レジスタのアドレスを更新する必要があることを示す
0=アドレスを更新する必要はない
BFバッファフルステータスビット
受信時
 1=受信完了、SSPBUF はフル
 0=受信は未終了、SSPBUF は空
送信時
 1=データ送信中(ACKおよびストップビットは除く)、SSPBUF はフル
 0=データ送信完了(ACKおよびストップビットは除く)、SSPBUF は空


SSPCON
bit7bit6bit5bit4bit3bit2bit1bit0
WCOLSSPOVSSPENCKPSSPM3SSPM2SSPM1SSPM0

WCOLライト衝突検出ビット
マスタモードの場合
1=I2Cの状態が有効でないときに、SSPBUFへのライトを実行した。
0=衝突なし
SSPOV受信オーバーフロー表示ビット
1=受信モードのとき、SSPBUF が以前のバイトを保持しているときにバイトを受信した。
  (ソフトウエアでクリアする必要がある)
0=オーバーフローなし
SSPEN同期シリアルポート有効ビット
1=シリアルポートを動作させ、SDAとSCLピンをシリアルポートピンにする。
0=シリアルポートを停止して、上記のピンをI/O ポートピンにする。
CKPクロック極性選択ビット
マスタモードでは未使用
SSPM3
  |
SSPM0
0000 = SPI マスターモード、クロック= FOSC/4
0001 = SPI マスターモード、クロック= FOSC/16
0010 = SPI マスターモード、クロック= FOSC/64
0011 = SPI マスターモード、クロック= TMR2 出力/2
0100 = SPI スレーブモード、クロック= SCK ピン。SS ピン制御を動作させる
0101 = SPI スレーブモード、クロック= SCK ピン。SS ピン制御は停止。SS はI/O ピンとして使用可能。
0110 = I2C スレーブモード、7 ビットアドレス
0111 = I2C スレーブモード、10 ビットアドレス
1000 = I2C マスターモード、クロック= FOSC / (4 * (SSPADD+1) ) ===今回はこれを使用
1011 = I2C ファームウエア制御のマスターモード(スレーブはアイドル)
1110 = I2C スレーブモード、7 ビットアドレス、スタートおよびストップビット割り込み発生あり
1111 = I2C スレーブモード、10 ビットアドレス、スタートおよびストップビット割り込み発生あり


SSPCON2
bit7bit6bit5bit4bit3bit2bit1bit0
GCENACKSTATACKDTACKENRCENPENRSENSEN

GCENゼネラル・コールイネーブルビット(I2Cスレーブモードのみ)
1=ゼネラル・コールアドレス(0000h)を受信したとき割込み発生させる
0=ゼネラル・コールアドレスは発生させない
ACKSTATアクノレッジステータスビット(I2Cマスターモードのみ)
1=アクノレッジをスレーブから受信しなかった
0=アクノレッジをスレーブから受信した
ACKDT受信応答データビット(I2Cマスターモードの受信時のみ)
受信の終わりで応答シーケンスを開始するときに送信する値。
1=NO-ACK
0=ACK
ACKENアクノレッジシーケンスイネーブルビット(I2Cマスターモードの受信時のみ)
1=SDA およびSCL ピンでアクノレッジシーケンスを開始して、ACKDT データビットを送信する。
  ハードウエアで自動的にクリアされる。
0=アクノレッジシーケンスがアイドル中
RCEN受信イネーブルビット(I2Cマスターモードのみ)
1=I2C 受信モードを動作させる
0=受信がアイドル中
PENストップコンディションイネーブルビット(I2Cマスターモードのみ)
1=SDAおよびSCLピンのストップコンディションを開始する。ハードウエアで自動的にクリアされる。
0=ストップコンディションがアイドル中
RSEN繰り返しスタートコンディションイネーブルビット(I2Cマスターモードのみ)
1=SDAおよびSCLピンの繰り返しスタートコンディションを開始する。ハードウエアで自動的にクリアされる。
0=繰り返しスタートコンディションがアイドル中
SENスタートコンディションイネーブルビット(I2Cマスターモードのみ)
1=SDAおよびSCLピンのスタートコンディションを開始する。ハードウエアで自動的にクリアされる。
0=スタートコンディションがアイドル中

SSPADD
bit7bit6bit5bit4bit3bit2bit1bit0
-クロックパラメータ(マスタモードの場合)

クロックパラメータは、I2Cのクロック(SCL)を設定します。
クロック= FOSC / (4 * (SSPADD+1) )
SSPBUF
bit7bit6bit5bit4bit3bit2bit1bit0
送受信データ

送信時は、送信するデータを格納します。
受信時は、受信したデータが格納されます。

(3) データの送信方法
I2Cでデータを送信するときの手順は以下のようになります。(1バイト送信の場合)
  1. I2Cの初期化
  2. スタートビット送信
  3. スレーブアドレス送信、writeモード
  4. ACK受信チェック
  5. データ送信
  6. ACK受信チェック
  7. ストップビット送信

No処理コーディング例備考
1I2Cの初期化 TRISC = 0x3F;
PORTC = 0x00;
SSPCON = 0x28;
SSPADD = 0x03;
SDA/SCL:input

SSP enable & I2C Master mode, clock = FOSC / (4 * (SSPADD+1))
2スタートビット送信 SEN = 1;
while (SEN) {}
3スレーブアドレス送信 SSPIF = 0;
SSPBUF = addr;
while (!SSPIF) {}
addrの上位7ビットにスレーブアドレスを設定する。
最下位の1ビットには0(write)を設定する。
4ACK受信チェック if (ACKSTAT) {
  NO-ACK受信時処理;
} else {
  ACK受信時処理;
}
5データ送信 SSPIF = 0;
SSPBUF = send_data;
while (!SSPIF) {}
6ACK受信チェック if (ACKSTAT) {
  NO-ACK受信時処理;
} else {
  ACK受信時処理;
}
7ストップビット送信 SSPIF = 0;
PEN = 1;
while (PEN) {}
SSPIF = 0;


(4) データの受信方法
I2Cでデータを受信するときの手順は以下のようになります。(1バイト受信の場合)
  1. I2Cの初期化
  2. スタートビット送信
  3. スレーブアドレス送信、readモード
  4. ACK受信チェック
  5. データ受信
  6. NO-ACK送信
  7. ストップビット送信

No処理コーディング例備考
1I2Cの初期化 TRISC = 0x3F;
PORTC = 0x00;
SSPCON = 0x28;
SSPADD = 0x03;
SDA/SCL:input

SSP enable & I2C Master mode, clock = FOSC / (4 * (SSPADD+1))
2スタートビット送信 SEN = 1;
while (SEN) {}
3スレーブアドレス送信 SSPIF = 0;
SSPBUF = addr;
while (!SSPIF) {}
addrの上位7ビットにスレーブアドレスを設定する。
最下位の1ビットには1(read)を設定する。
4ACK受信チェック if (ACKSTAT) {
  NO-ACK受信時処理;
} else {
  ACK受信時処理;
}
5データ受信 SSPIF = 0;
RCEN = 1;
while (RCEN) {}
read_data = SSPBUF;
6NO-ACK送信 ACKDT = 1;
ACKEN = 1;
while (ACKEN) {}
7ストップビット送信 SSPIF = 0;
PEN = 1;
while (PEN) {}
SSPIF = 0;


2.実験回路
今回の実験回路です。
EEPROMは、AT24C1024B(128KByte)を使用しました。


こちらは、ブレッドボードに組んだ状態。


3.プログラムの仕様

今回のプログラムは、I2CでEEPROMにアクセスする事だけを目的としました。
プログラムの大まかな流れは以下の通りです。
1. PICとLCDを初期化する。
2. LCDに0xAAを表示する。
3. EEPROMの0x00A100番地に0xAAを書き込む。
4. LCDに0xBBを表示する。
5. EEPROMの0x01A100番地に0xBBを書き込む。
6. EEPROMの0x00A100番地のデータを読み込みLCDに表示する。
7. EEPROMの0x01A100番地のデータを読み込みLCDに表示する。

EEPROMへの1バイト書込みは、以下のデータフォーマットになります。


AT24C1024Bのデータシートより抜粋。

(1) DEVICE ADDRESSにより、通信先としてEEPROMを選択する。R/WはWRITEを設定。
(2) P0,上位バイトアドレス,下位バイトアドレスにより、EEPROMのメモリアドレスを指定する。
(3) 書き込むDATAを送る。

EEPROMから1バイト読み込むときのデータフォーマットは以下の通りです。


AT24C1024Bのデータシートより抜粋。(2番目のSTARTは、Repeated Start)

(1) DEVICE ADDRESSにより、通信先としてEEPROMを選択する。R/WはWRITEを設定。
(2) P0,上位バイトアドレス,下位バイトアドレスにより、EEPROMのメモリアドレスを指定する。
(3) DEVICE ADDRESSにより、通信先としてEEPROMを選択する。R/WはREADを設定。
(4) EEPROMから1バイト読み込む。(DATAn)

DEVICE ADDRESS
今回使用した、AT24C1024Bではデバイスアドレスを以下のよう設定します。(ビット表記)
1010aaP

1010 : 固定
aa   : A1/A2ピンの状態。今回の回路では共にGND接続しているため、00とする。
P    : EEPROMのメモリアドレス上位1ビット(下記を参照)

EEPROMのメモリアドレス指定
AT24C1024Bは、128KByteのメモリを保有しています。従って、全てのメモリにアクセスするためには、アドレスとして17ビットが必要になります。
この17ビットを、デバイスアドレスの下位1ビット+上位バイトアドレス8ビット+下位バイトアドレス8ビットで表現しています。
デバイスアドレスの下位1ビットは、上のデータフォーマットではP0と表現しています。

4.プログラム全体
プログラムはこちらです。

プログラム内のI2C関連関数は、「1.I2Cの使い方」の「(3) データの送信方法/(4) データの受信方法」で例示した内容とほぼ同じです。