Prismjs

2019年9月1日日曜日

SPI通信とは

SPI通信について、自分用メモとして調べたこと、経験したことをまとめる。

SPI通信の概要

SCLK、MOSI、MISO、CSの4線式(電源、GND除く)のデータ通信方法。
マスター側デバイス(マイコン、Arduino、ラズパイ等)とスレーブ側デバイス(温度センサーやA/Dコンバータ等)でデータのやり取りをする。
似たような通信方法としてはI2Cがある。設定や構成にもよるが、SPI通信はI2C通信に比べて高速で動作させることができる。
1つのマスターに対して複数のスレーブをつなげることができる。しかしスレーブの数だけマスターのCSピン数が増えてしまう。
送信用と受信用の線(MOSI・MISO)があるので、コマンドを送りながらデータを受け取ること(全二重通信)が可能(デバイスにより非対応な場合もある)。
I2C等と同様、基本的に同じ基板内のIC同士の通信や隣り合う基板間の通信など近距離通信向けなので長距離伝送には向かない(ノイズがのってしまうので)。ただしSPI通信の信号を差動信号で伝える等の対策でノイズ耐性を上げてやれば数十メートル級の長距離通信も可能(わざわざそこまでして長距離通信する人はほとんどいないようであるが)。
SPI通信は規格がかなりガバガバなので、デバイスにSPI対応と書いてあっても通信できないことがある。たいていの場合は問題ないが、まれにトリッキーな動きをするSPI対応デバイスもあるので気を付けよう。




SPI通信の各信号について

SCLK:デバイスによってはSCKと表現されることがある。データを伝えるためのクロック信号。
SCLKの立ち上がりエッジでラッチする(データを取り込む)デバイスと立ち下りエッジでラッチするデバイスがある。またIDLE時(非通信時、定常時)はHIGHであるデバイスとLOWであるデバイスがある。詳しくは別項目参照(POLとPHA)

MOSI:Master Out Slave Inの頭文字をとってMOSIと表現される信号。名前の通りマスターがデータを送信(スレーブがデータを受信)するためのピンである。
デバイスによって呼び名が異なることがある。マスター側デバイスの場合SDO(Serial Data Out)、スレーブ側デバイスの場合SDI(Serial Data In)と表現されることがあるので注意が必要。

MISO:Master In Slave Outの頭文字をとってMISOと表現される信号。名前の通りマスターがデータを受信(スレーブがデータを送信)するためのピンである。
デバイスによって呼び名が異なることがある。マスター側デバイスの場合SDI(Serial Data In)、スレーブ側デバイスの場合SDO(Serial Data Out)と表現されることがあるので注意が必要。
このSDOとSDIという呼称はデバイスがマスターかスレーブかでややこしくなるので注意すること。

CS:Chip Selectの頭文字をとってCSと表現される信号。CS信号はLOWアクティブであることが一般的である。(これ以降、CSはLOWアクティブとして話を進める)
通信を有効にするにはスレーブデバイスのCSをLOWにする必要がある。
マスターにはスレーブの数だけこのCSピンが必要になる
この信号の意図は、複数のスレーブをつなげたときに通信したいスレーブのCSだけLOWにしてやることで、通信したいスレーブのみ有効にさせるためである。書き込みだけなら複数のスレーブのCSをLOWにしてもよいが、読み込み時は各スレーブからのデータが衝突するため複数スレーブのCSをLOWにするのは推奨しない。
スレーブがひとつだけの時、スレーブのCSをLOW固定にして、マスターではCSを管理しなければ線を1本削減できる。しかしデバイスによってはCSのLOW固定が不可な場合もあるので要注意。(僕はこれが原因で解決に数日つぶしたことがある。)


SPI通信のCPOLとCPHA

SPI通信のマスターから出力される信号SCLKは、スレーブのCPOLとCPHAと呼ばれる項目を考慮して出力してやる必要がある。
CPOL:POLなどとも呼ばれたりする。IDLE状態のSCLKの極性を表す項目。通信していない間SCLKはLOWなのかHIGHなのか、の項目のこと。
CPHA:PHAなどとも呼ばれたりする。デバイスはSCLKの立ち上り立下りどちらのエッジでデータをラッチする(取り込む)のか、の項目のこと。

このPOLとPHAはデバイスによって異なるため、デバイスのデータシートをチェックしてやる必要がある。データシートによっては「このデバイスのPOL、PHAはモード3です」とか「POLは0、PHAは1です」みたいに書いてあったりするが、そもそもモード3がどういうPOLとPHAの組み合わせなのかもメーカーによって違う可能性があるのであまりあてにならない。あるメーカーはモード3はIDLEがHIGH・立ち上がりでラッチのことを指すのに、別のメーカーはモード3はIDLEがHIGH・立下りでラッチのことを指すとかいうことがありえる。
データシートの波形の図を確認して、自分で判断するのが確実である。
マスターがスレーブのPOL・PHAの動作に対応していなければ当然接続できない。(たいていのマスターは設定やコマンドでPOL・PHAの設定を切り替えられる。)また、複数スレーブのPOLとPHAが異なる場合、マスター側でのPOL・PHAの設定の切り替えやタイミングを考慮しなければならずマスターのソフト記述が大変になる。
SPI通信の規格がガバガバゆえに起こる弊害である。


SPI通信とI2C通信との主な違い

I2CはSCLとSDAの2線式(電源、GNDを除く)なので、I2Cなら線数を減らせる。またI2C通信はスレーブデバイスの切り替えをアドレスで行うため、SPI通信のようにスレーブが増えるたびにマスターから出る線が増えるということがない。
上記だけ見るとI2Cのほうが優れて見えるが、I2Cは通信速度がハイスピードモード時にMAXで3.4Mbp(実際は素人が電子工作でセンサーをワイヤでつなげたりするなら400kbps出ればいいほう)と上限があり、SPIは基本的にデバイス依存で上限はない(デバイスが対応していれば普通の電子工作でも2Mbpsくらいは出る)。また大差はないがI2CよりSPIのほうが長距離で通信できる。
I2CのSDAは通信中にINとOUTが切り替わる(半二重通信)ため自作でI2Cドライバを作ろうとすると大変だったりする。I2Cは半二重通信なので送信受信を同時に行えないが、SPIは全二重通信なので送信受信を同時に行える。
SPI通信とI2C通信どちらを選択すべきか迷った場合は、できるだけpin数を節約したいならI2C、できるだけ高速で通信したいならSPIを選択する。
例えば温度センサーをI2C or SPIで通信しようとするとき、1秒ごとに温度を取得するとか数分おきに温度を取得するとか(いわゆる室温計や室温ロガー)の場合はI2C、10usごとに温度を取得するとか高速でデータを取得する(温度変化が急激なものの測定)の場合はSPIを選択する。普通の電子工作レベルならSPIじゃないと対応できない速度の通信をすることはあんまりないと思うので、デバイスがI2CでもSPIでもどっちでも使えるなら基本的に線数が少なく済むI2Cを選べばいいように思う。そもそもセンサーのサンプリングレートが低かったらSPIで高速に通信したところで意味がない場合もある。


SPI通信のプロトコル(波形)

以下の図にSPI通信の波形の一例を示す。ちなみにこの時のCPOL・CPHAは非通信時SCLKはHIGH、立ち上がりエッジでラッチする設定となっている。

この波形の時のマスターからの出力データ(MOSI)は01000111であり、スレーブから受け取ったデータ(MISO)は00100000となる。
基本的にスレーブはコマンドを受け取ったらレスポンスを返すというような動作をするため、図でのMISOのデータは、図の前の(図には示されていない)通信のコマンドに対するレスポンスのデータということになる。
ちなみに図ではMOSIはSCLKの立下りエッジで変化しているが、スレーブデバイスのデータシート等に書いてあるタイミングに違反(前データラッチ時のSCLK立上り直後や、次のSCLK立上りの直前ではダメ)していなければ、いつでも良い。MISOも同様。規定はないが、SCLK立下り(ラッチ時とは逆のエッジ)をきっかけにMOSIもしくはMISOの出力を変化させるデバイスがほとんどのようだった。ものによってはSCLK立上りから規定時間後に(SCLKの立下りは監視せずに)出力が変化するデバイスもあるのかもしれない。

0 件のコメント:

コメントを投稿