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

I2CでEEPROMを使う
− I2Cをプログラムで実装 (PIC16F88 XC8) −
作成日2012.6.10



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

使用するPICはPIC16F88ですが、PIC16F88はI2Cのマスターモードをサポートしていません。
そこで、プログラムでI2Cのマスターモードを実装し、EEPROMを使用します。

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

以降、今回のEEPROMを使用するために必要な内容を説明します。

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


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

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

どのデバイスもマスタに成り得ますが、通常はPICなどのマイクロコンピュータがマスタとなり、EEPROMやリアルタイムクロックモジュールなどがスレーブになります。 EEPROMなどには、マスタとして動作する機能は無く、常にスレーブとして使用します。

(2) バスの制御とビット転送方式
I2Cでは、SCLとSDAの信号の組み合わせでデバイス間の通信を行います。
下図は代表的な通信の例です。
以降、マスタの動作を中心に説明します。

マスタがSTART conditionで通信開始を宣言し、引き続きデータ(8ビット)を送信します。
その後、受信側からのACKを受け、マスタがSTOP conditionで通信を終了します。
実際にはACKを受けた後、データの送受信があります。((3) データフォーマットで説明)


状態SCL/SDAの変化マスタ側の処理内容
START conditionSCL/SDAともHにしておき、SDAのみLにする。
これにより、無通信状態から通信状態に遷移する。
ビット"1"送信SDAをH(ビット"1"の状態)にし、SCLをH→Lと変化させる。
ビット"0"送信SDAをL(ビット"0"の状態)にし、SCLをH→Lと変化させる。
ACK

相手デバイスからの
肯定応答
SDAを解放(PICのポートを入力に設定)し、SCLをHにして
SDAの状態を読み込む。(LならACK)
その後SCLをLにする。
NO ACK

相手デバイスからの
否定応答
SDAを解放(PICのポートを入力に設定)し、SCLをHにして
SDAの状態を読み込む。(HならNO-ACK)
その後SCLをLにする。
STOP conditionSDAをL、SCLをHにしておき、SDAをHにする。
これにより、通信状態から無通信状態に遷移する。

以上のように、SCL/SDAの2つのバスラインを制御して通信を行います。

ここでは、時間関係についてふれていませんが、実際にはSCLのHの最低時間やLの最低時間、SDAのデータ保持時間などがあります。
使用するデバイスのタイミングチャートを見て設計する事になります。


(3) データフォーマット
次に、実際にデバイス間で通信するときのフォーマットについて説明します。

最も単純なフォーマットは以下のようになっています。(マスタからスレーブに1バイト送信の例)
青は、マスタからスレーブへの送信、オレンジはスレーブからマスタへの送信を意味しています。

ここで、START/ACK/STOPは、(2)で説明したSTART condition/ACK/STOP conditionの事です。
また、ACKまでの8ビットは、(2)で説明したビット送信の事です。
幅を狭くするために表現方法を変えています。
・アドレス
アドレスは、通信対象デバイスのアドレスで、7ビットで指定します。
ただし、以下のビットパターンは別目的に割り当てられており使用できません。
  0000xxx
  1111xxx
・R/W
マスタからスレーブにデータを送信するのか受信するのかをビットで指定します。
  0:Writeアドレスに続くデータをマスタからスレーブに送る
  1:Readアドレスの後、ACKに続けてスレーブからマスタにデータを送る
・データ
Writeの場合は、マスタからスレーブに送信するデータです。
Readの場合は、スレーブからのデータになります。


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


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

プログラムの仕様

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

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


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

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

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


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

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

DEVICE ADDRESS
デバイスアドレスは以下のようになります。
 1010aaP

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

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

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

I2Cを実装するために、いくつかの関数を作成しました。
その関数の役割を下図に記載します。


終わりに
今回はPIC16F88でEEPROMを使う目的で、I2Cをプログラムで実装しました。実装した機能は最低限にしています。

タイムアウトなどの異常系は対応していません。
また、マスタが複数存在するような場合の衝突対応も行っていません。
その他、10ビットアドレス対応など、I2Cには今回使わなかった多くの機能があります。

I2Cのマスタ機能を内蔵したPICもたくさん有りますので、いずれPICのI2Cを使ったページも作ろうかと思っています。
I2Cをプログラムで実装する事に比べると、バスの制御をPICに任せられるので考え方が容易になります。