SPI通信の使い方 


【SPI通信とは】

 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間の通信が目的になっており、
装置間のような距離のある通信には向いていません。
そのため「オンボードシリアル通信」とも呼ばれています。



《SPI通信の仕組み》
 MSSPをSPIモードで使う時の通信のしくみは下図のようになっています。
2つのSPIのモジュールが互いに3本または4本(SS信号を使う場合)の線で接続され、
片方がマスタもう一方がスレーブとなります。
グランド線を含めると4本または5本の線となります。



 通信は、マスタが出力するクロック信号(SCK)を基準にして、互いに向かい合わせて
接続したSDIとSDOで、同時に1ビット毎のデータの送受信を行います。
常にマスタが主導権を持ち、次のような8ビット単位のデータ通信が行われます。

@ マスタからの送信
 スレーブが受信すると同時に、スレーブからダミーデータが送られるのでマスタ側に
 ダミーデータが受信される。

A マスタ、スレーブ同時に送信
 マスタが送ると、同時にスレーブ側も有効なデータを送信する。従ってマスタ、
 スレーブ両方にデータが受信される。

B マスタが受信する
 ダミーデータがマスタから送信され、同時にスレーブから有効なデータが送信され
 マスタに届く。

このようにSPI通信を使うと2つのPICマイコン同士で簡単に高速通信をしてデータ交換を行うことができます。

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

 下図はSPIモードの時のMSSPの内部構成の詳細です。
図のようにSDIとSDOをお互いに接続することで、同時にデータの送受信が行われます。
したがって片方は不要な送受信が行われることもあります。




 このとき、SSピンを使うことによって、スレーブ側からの送信を制御できます。したがって、
例えばマスタがこのSSピンを制御することで、余計なデータを受信しないようにしたり、
複数のスレーブを接続して、特定のスレーブを選択してデータ転送したりすることもできます。

 SPI通信用のクロック出力回路部はマスタ側だけが動作することになり、スレーブ側は、
単純にマスタ側から送られてくるクロックに合わせて動作するだけになります。
このため、SPIスレーブはスリープ中でも動作可能です。

【SPI関連レジスタ】

 SPI通信を行うのに必要な制御レジスタは下図の通りです。
 I2Cモードの設定と一緒になっているので、やや複雑な構成をしていますので、
図ではSPI通信に関係する部分だけを記述しています。
また、MSSPモジュールが複数実装されているデバイスもあるため、xを1または2として
区別しています。


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

@ SPIモードの設定
 SSPxCON1レジスタの中のSSPM<3:0>ビットで色々なモードを設定できます。
 マスタ/スレーブの区別とクロック指定によって6種類の設定があります。
 SPIモードを決めるには、まずマスタにするかスレーブにするかを決め、次に、
 クロックのレートを決めればSPIモードが決定できます。
 当然ながら、SSPENはイネーブルにしておく必要があります。

A TRISレジスタで入出力モードを設定
 SDI、SDO、SCKに相当する各ピンの入出力をSPIの設定モードがマスタか
 スレーブかに従って適切な方向に設定します。
 マスタの場合はSDOピンとSCKピンを出力モード、SDIを入力モードにします。
 スレーブの場合には、SDOピンを出力モードに、SDIとSCKを入力モードにします。

B クロックの極性とエッジを設定
 まず、SSPxCON1レジスタのCKPビットで、クロックの論理を正にするか負にするか
 を決めます。次にSSPxSTATレジスタにあるCKEビットで、データをシフトする
 タイミングをクロック信号の立ち上がりにするか立下りにするかを設定します。

C割り込みの設定
  割り込みを使う場合には、SSPxIEビットを1にしてMSSPの割り込みを許可し、
 次にINTCONレジスタのPEIEビットとGIEビットを1にしてグローバル割り込みを
 許可します。


【通信タイミングと使用例】

 このSPI通信の信号タイミングは、マスターモードの時は下図のようになります。


 図(a)のように常にマスタ側が制御権をもっていますので、マスタ側から送信する場合には
SSPxBUFに書き込んだ時点ですぐ送信が始まります。
マスタが受信する場合にも、マスタ側でSSPxBUFにダミーデータを書き込んで送信し、
SCKを出力してやる必要があります。

 いずれの場合にも8ビット送信完了した時点ですぐSSPxSTATレジスタの
BFビットが「1」になると同時にSSPxIFビットも「1」になって割込み要因が発生します。
(このときマスタ、スレーブ両者の受信が完了しています)

 クロックのSCKのサンプリングタイミングについては、CKPビットとCKEビットの設定
によってかなり異なって来ます。
 CKP=0とした場合、SCKピンは常時Lowで、CKP=1とした場合、SCKピンは常時High
となります。
 CKE=1とした時は、最初のSCKのエッジでマスタ側がデータを取り込むので、
その前にスレーブ側がデータの出力準備を完了している必要があります。

 さらにマスタは、図(b)のようにSSピンを先にLowにしてからSSPxBUFに書き込むこと
が必要です。
このため、1バイト送受信完了ごとにSSピンをHighに戻し、SSPxBUFに書き込む直前に
Lowにするという制御をする必要があります。

 多くの場合CKP=0、CKE=0として使い、この条件を「00モード」と呼んでいます。
 00モードの場合でも、通信の開始、終了を明確に指定スレーブに伝えるため
SSピンをチップ選択(CS)用として使います。
これで例えば途中で通信エラーが起きてもSSピンをHighにすることで、
次のLowが通信の開始であることを明確にできます。


【プログラム例】

実際にSPIをマスタモードで使って送受信するプログラム例が下記となります。

SPIRead()関数が1バイトのRead関数です。
 最初にCS信号をLowにしてスレーブを選択します。
SPIのバッファに過去のデータが残っているとエラーになりますので、空読み出しをして
バッファを空の状態にしてから、読み出すデータのアドレス指定を送信しています。

 スレーブはこのアドレス受信で送信する準備ができますので、マスタは受信バッファを
空読みして空にしてから、ダミーデータを送信してスレーブからのデータを受信します。

 このように受信する場合にも何らかのデータを送信しないとクロックが出力されませんから、
ダミーデータを送信する必要があります。最後にCSをHighに戻して完了です。

 SPIWrite()関数が1バイトの送信関数です。こちらも最初にCSをLowにしてスレーブを
選択します。
 空読み出しをしてSPIバッファを空にしてからアドレスとデータを続けて送信しています。
この送信の場合も毎回ダミー読み出しをしてバッファを空にする必要があります。