I2C通信の使い方 


【I2C通信とは】

 F1ファミリに内蔵されているMSSP(Master Synchronous Serial Port)モジュールは、
シリアルEEPROMやD/Aコンバータなどの周辺ICを専用のシリアルインターフェースで
接続し、高速の同期式通信を可能とします。
このMSSPモジュールの使い方には下記の2種類があります。

@ SPI(Serial Peripheral Interface)モード
 モトローラ社が提唱した方式で、3本または4本の接続線で構成し、数Mbpsの通信が可能    

A I2C(Inter−Integrated Circuit)モード
 フィリップス社が提唱した方式で、2本の接続線で1個のマスタに対し複数のスレーブ
 との間でパーティーラインを構成し、最大1Mbpsの通信が可能です。

 この2方式のシリアル通信はいずれもオンボードでのIC間の通信が目的になっており、
装置間のような距離のある通信には向いていません。
そのため「オンボードシリアル通信」とも呼ばれています。



《I2Cとは》
 I2C(Inter-Integrated Circuit)は、フィリップス社が提唱した周辺デバイスとのシリアル通信の方式で、
シリアルEEPROMメモリなどとの高速通信を実現する方式です。
 シリアルEEPROM以外にも表示制御デバイスや、A/D変換ICなど、I2Cインターフェースで接続する
製品が各社から発売されています。

 I2Cはパーティーライン構成が可能となっており、1つのマスタで複数のスレーブデバイスと通信する
ことが可能です。マスタ側とスレーブ側を明確に分け、マスタ側が全ての制御の主導権を持っています。
 I2C通信の速度は100kbps、400kbps、1Mbpsが標準となっています。
 詳しい規格などは、フィリップスが設立したNXP社のWebサイトから日本語の仕様書がダウンロードできます
のでそちらを参考にして下さい。

《I2C通信のしくみ》
 I2C通信の場合の接続構成は下図の構成を基本としています。図のように1台のマスタと1台または
複数のスレーブとの間を、SCLとSDAという2本の線でパーティーライン状に接続します。
 マスタが常に権限を持っており、マスタが送信するクロック信号SCLを元にして、データ信号が
SDAライン上で転送されます。ワイアードORで接続するため数kΩのプルアップ抵抗を必要とします。

 通信方式でSPIと大きく異なるのは、個々のスレーブがアドレスを持っていて、マスタからアドレス指定
して特定のスレーブを選択し、1バイト転送ごとに受信側からACK信号の返送をして、互いに確認を
取りながらデータ転送を行っていることです。



《I2C通信の基本のデータ転送手順》
 I2C通信の基本的な通信フローは下図のようになります。2本の信号のHigh、Lowの変化の仕方により
次の4つの条件が決められています。

 @SCLがHighのときに、SDAが立ち下がると通信開始(Start Condition)
 ASCLがLowの間に送信側が次のビットを送信する
 BSCLの立ち上がりで受信側がSDAのビットを取り込む
 CSCLがHighのときに、SDAが立ち上がると通信終了(Stop Condition)


 この4つの条件で下図のタイミングチャートを説明します。
マスタ側からSCLがHighの間にSDAをLowにするとスタートコンディションとなり通信開始となります。

その後マスタがクロックの供給を続けながらデータの通信を行います。
 データの通信では、SCLのクロックの立下りごとに送信側から順次8ビットのデータが出力され、
受信側がSCLの立ち上がりごとにこのビットを受信し、受信完了により9ビット目のクロックに合わせて
アクノリッジ(ACK)信号を返送します。

 この後、受信側で次のデータ受信準備ができるまで送信側を待たせる必要がある場合は、
受信側からSCLを強制的にLowにします。この間は見かけ上クロックがなくなるので、
送信側はデータを出力するのを待つことになります。

 最後のデータを送り終わりACKの返送をしたあと受信側がSDAを開放してHighとなるので、
マスタがSDAをLowにします。
その後マスタがクロックを停止してSCLをHighにしてから、SDAをHighにすることでストップコンディション
となり通信が完了します。




【MSSPモジュールの内部構成(SPIモード)】

 MSSPモジュールをI2Cスレーブモードで使う時の内部構成は下図のような構成となります。
図のように、SCLとSDAの2本の信号線ですべてのデータの送受信を行います。

 SCLピン、SDAピンともに複数のスレーブが接続されますので、I2Cモードを選択した場合、
自動的に両ピンともオープンドレイン構成で入力モードとなりますので、TRISxレジスタの設定は
敢えて必要ありませんが通常は入力モードにしておきます。

 通信の開始は、マスタ側が開始指示に続いてスレーブのアドレスとRead/Write要求を出力します。
全スレーブがSCLのクロックを元にこのSDAのデータを受信し、下図のSSPxADDレジスタに
あらかじめセットされたアドレスと一致したスレーブだけがその後のデータの送受信を継続します。

SSPxMSKレジスタでアドレスの一部をマスクして比較範囲を制限することができます。
 受信側がデータを受信完了すると自動的にACKビットを返送することで確認を取り合います。





【I2C通信の通信フォーマット】

 I2C通信の通信データフォーマットをみてみましょう。
通信データの最初はアドレスがマスタ側から送信されます。このアドレス部は下図のようになっていて、
7ビットモードと10ビットモードの2種類があります。
このアドレス部の1バイト目の最後のビットが送信、受信を区別するRead/Writeビットになっています。

10ビットモードの時の1バイト目の上位5ビットは固定パターンになっていて、スレーブ側は、
これで7ビットモードと10ビットモードを区別しています。
図中のACKビットは受信スレーブから返信されるビットです。


 通信データ全体のフォーマットは7ビットアドレスモードの場合と10ビットアドレスモードの場合で
大きく異なりますが大部分は7ビットモードが使われていますので7ビットモードだけを説明します。

 最初にマスタから7ビットアドレスとReadかWriteを指定する1ビットを追加した8ビットデータが送信されます。
スレーブ側はこれを受信したらSSPxADDレジスタに設定されているアドレスデータと一致するかを確認します。
アドレスが一致したらACKを返送して次の受信を継続します。

その後は、ReadかWriteかによって手順が分かれます。
マスタから送信(Write)の場合は、1バイト送信ごとにスレーブからACKが返されますので、これを確認しながら
送信を繰り返します。
最後にマスタがStop Conditionを出力すると終了となります。

 マスタが受信(Read)する場合は、アドレスが一致したスレーブから1バイト送信されますから
マスタはこれを受信したらACKを返送します。
これを必要回数繰り返し最後のデータを受信したら、マスタはNACKを返送します。
これでスレーブ側は送信が完了したことを認識して送信処理を終了します。
さらに続けてマスタがStop Conditionを出力して通信終了となります。

 スレーブ側が送受信する場合には、処理時間を確保するために、クロックストレッチによってマスタを
待たせることができます。
さらにマスタ側は、送信終了のStop Conditionを発行する代わりに、Repeated Start Conditionを発行する
ことで、連続して別のスレーブとの通信を行うこともできます。


 MSSPでは同報アドレスで、マスタ側から全スレーブに一斉に送信を行うことができます。
これを「General Call Address」と呼んでいます。
このためのアドレスは、"0000 000"(7ビットアドレスの場合)または"00 0000 0000"(10ビットアドレスの場合)で
R/W=0(Write要求)となっています。つまりアドレス部がすべて0のときは一斉同報として扱います。

 同報機能を使うには、スレーブ側のSSPxCON2GCENビットが1になっていることが必要です。
このGCENが1のスレーブは、アドレスが同報アドレスの場合には、無条件で引き続くデータを受信し割込みを
発生するので、これらを順次取り込みます。スレーブの受信手順は通常受信と同じです。

【I2C制御レジスタ】

 8ビットファミリのI2C通信を制御するレジスタについて説明します。
MSSPx(xは1か2)を制御するレジスタには、まずモード設定にはSSPxCON1、SSPxCON2、SSPxCON3、
SSPxMSK、SSPxADDの5つのレジスタがあります。
状態を保持するレジスタがSSPxSTATレジスタで、送受信用バッファがSSPxBUFレジスタです。
これらのレジスタの詳細は下図のようになっています。

 SSPxADDレジスタは、マスタとスレーブで使用目的が異なっています。スレーブの場合には、
スレーブアドレスを格納するレジスタで、ここに設定したアドレスと受信したアドレスが一致した場合のみ、
その後に続くデータの送受信が実行されます。
マスタの場合には、下位7ビットが通信速度を設定するレジスタとなります。
ボーレートは Fosc÷(4×(SSPxADD値+1 ))で決定されます





これらの制御レジスタを使ってI2C通信を使うための設定は次のようにします。

@ 初期化でI2Cのモード設定を行う
 I2C通信のマスタにするかスレーブにするかを決めます。さらにスレーブの場合は、アドレスが7ビットか
 10ビットか、スタート/ストップコンディションの割込みを使うか使わないかを決め、
 それをSSPxCON1レジスタとSSPxCON2レジスタに設定します。
 当然ながら、SSPENビットを1にしてSSPxを使うことを指定します。

A 入出力ピンのモード設定を行う
 入出力モードは自動的に設定されますので、SCL、SDAとも入力モードに設定してハイインピーダンス
 の状態にしておきます。

B マスタの場合には通信速度をSSPxADDレジスタに設定します。
  スレーブの場合にはスレーブアドレスをSSPxADDに設定します。


C 割り込みを使う場合
  PIE1レジスタのSSP1IEビットか、PIE4レジスタのSSP2IEビットを1にしてMSSPの割り込みを許可し、
  さらにINTCONレジスタのPEIEビットとGIEビットを1にしてグローバル割り込みを許可します。

【プログラム例】

 例えばマスタの場合で基本的なプログラムフローは下図のようにします。
それぞれの処理でレジスタの設定ビットや状態ビットを使います。ここではこれらの制御プログラムを
基本にしてI2C用のライブラリを作成しています。


 このI2Cの制御プログラムはライブラリになっています。下記でダウンロードできます。

   F1ファミリ用I2Cライブラリ ダウンロード




 実際のマスタ側のプログラム例では、送信の場合が下記リストとなります。
SendByte()関数は転送関数内で実際に1バイトの送信を実行する関数です。
SendI2C()関数は指定アドレスのスレーブに1バイトのデータを送信する基本の関数です。
CmdI2C()関数は指定アドレスのI2Cスレーブ内の指定されたアドレスの内蔵レジスタに
1バイトのデータを送信します。

 I2Cがアイドルの状態であることをチェックするための関数を共通関数として作成しています。
この関数ではすべての動作条件をチェックしてアイドルであることを確認しています。




 受信の例が下記リストとなります。
RcvByte()関数が受信関数内で実際に1バイトを受信する関数です。応答にACKかNACKを
指定して使います。
GetDataI2C()関数が、指定したI2Cスレーブから指定バイト数のデータを受信してバッファに格納します。
アイドルチェックには送信のときと同じ関数を使っています。
最後のデータ受信でNACKを返送してからStop Conditionを出力しています。