🐧 Linux 総合学習プラットフォーム
実機制御 GPIO/I2C/SPI・RT ・ 上級

SPIの概要

SPIはMOSI・MISO・SCLK・CSの4線を使う高速なシリアル通信で、I2Cよりも速度が出る反面、デバイスごとにCS(チップセレクト)線が必要になります。Raspberry Piでは有効化すると /dev/spidev0.0 のようなデバイスファイルが現れ、ここを通じてディスプレイやADコンバータと通信します。マスタがクロックを供給し、全二重で同時に送受信できるのが特徴です。アドレス指定がない代わりにCSで相手を選ぶため、複数デバイス接続時はCS線の本数とピン割り当てを設計段階で決めておきます。

SPI(Serial Peripheral Interface)は、I2Cと並んでよく使われるシリアル通信方式で、速度を重視する場面で活躍します。使う信号線は基本4本です。マスタからデバイスへデータを送る MOSI(Master Out Slave In)、デバイスからマスタへ返す MISO(Master In Slave Out)、タイミングを合わせる SCLK(シリアルクロック)、そして相手を選ぶ CS(Chip Select、SSとも呼ぶ)です。MOSIとMISOという送信路と受信路が別々にあるおかげで、送信と受信を同時に行える「全二重」通信ができ、1本の線を共有して半二重で動くI2Cより高速にデータを流せます。グラフィック液晶(LCD/OLED)、ADコンバータ、SDカード、各種高速センサなど、まとまったデータを速くやり取りしたいデバイスでよく採用されます。同じシリアル通信でもI2Cとは得意分野が分かれており、両者の違いを押さえておくと選定で迷いません。

I2Cがアドレスで相手を選んだのに対し、SPIは物理的なCS線で相手を選ぶのが大きな違いです。マスタは話したいデバイスのCS線をLOWにして「あなたと通信します」と知らせ、その間だけそのデバイスが応答します。CSがHIGHのデバイスは共有線を無視するので、複数台つないでも混信しません。この方式は仕組みが単純で高速な反面、つなぐデバイスが増えるほどCS線が1本ずつ必要になります。デバイスが3つあればCSも3本要る、という具合です。そのため複数デバイスを接続するときは、CSに割り当てるGPIOの本数とピン配置を、設計の早い段階で決めておく必要があります。MOSI・MISO・SCLKの3本は全デバイスで共有し、CSだけを分ける、というのが基本構成です。ここはアドレスで動的に選べるI2Cとの設計上の大きな違いで、配線本数と引き換えに速度と単純さを得ている、と捉えると両者の住み分けが見えてきます。

Raspberry Piでの有効化とデバイスファイル

Raspberry PiでSPIを使うには、I2Cと同様にまず有効化します。`sudo raspi-config` の Interface Options で SPI を有効にするか、config.txt に `dtparam=spi=on` を記述して再起動します。有効になると、SPIコントローラが /dev/spidev0.0 や /dev/spidev0.1 といったデバイスファイルとして現れます。この名前は「spidev(バス番号).(CS番号)」という構成で、spidev0.0 はSPIバス0のCS0につながるデバイス、spidev0.1 はCS1のデバイスを意味します。Piの標準ヘッダではCS0とCS1の2本が用意されているため、何もしなければ最大2デバイスまでをハードウェアのCSで扱え、それ以上は任意のGPIOを手動でCSとして使う構成にします。

通信のしくみ

SPIの通信は、マスタが供給するクロックSCLKに同期して、1ビットずつデータがやり取りされます。クロックが1拍刻むごとに、MOSIで1ビット送り出すのと同時にMISOで1ビット受け取る——これが全二重の意味です。送信専用・受信専用ではなく、つねに送りながら受ける形になるため、たとえ受信だけが目的でも何かしらのダミーデータを送ってクロックを供給する、という考え方になります。たとえばADコンバータから値を読むときは、マスタが「変換結果をください」という指示をMOSIで送りつつ、同じやり取りの中でMISO経由で結果を受け取ります。

SPIで取り違えやすいのがクロックの「モード」です。クロックの極性(アイドル時にHIGHかLOWか=CPOL)と位相(クロックのどの縁でデータを確定して読むか=CPHA)の組み合わせで、モード0からモード3までの4種類があります。どのモードを使うかはデバイスごとにデータシートで決まっており、相手に合わせて設定する必要があります。ここがずれると、配線がすべて正しくてもビットの読み取り位置がずれてデータが化けます。そのため、SPIで「まったく通信できない」のではなく「読めるが値がおかしい」ときは、まずこのモード設定が相手と合っているかを疑うのが定石です。クロック周波数も、相手が対応する上限を超えると不安定になるため、データシートの最大値以下に設定します。

確認と実務の勘どころ

有効化できたかは `ls /dev/spidev*` でデバイスファイルの有無を確かめるのが手軽です。spidev0.0 などが見えれば、カーネルがSPIを認識しています。I2Cの i2cdetect のような「つないだ相手を自動で一覧する」コマンドはSPIには無く、これはアドレスではなくCSで相手を選ぶ方式上、バスを走査して相手を探す概念がそもそも無いためです。したがってSPIデバイスの確認は、対応するドライバやライブラリ(PythonのspidevモジュールやCのspidev経由のioctl)を使って実際に1回読み書きし、期待した応答が返るかで判断します。たとえばADコンバータのMCP3008なら、決まった3バイトを送って返ってくる値を読み、もっともらしい範囲の数値が出るかを見ます。

配線の注意として、MOSIとMISOはクロス(送信側の出力が相手の入力につながる関係)になるため接続の向きを取り違えないこと、CS線をデバイスごとに確実に分けること、信号電圧を相手に合わせること(多くは3.3V系)が要点です。Raspberry PiのSPIピンは3.3V系なので、5V論理のデバイスをつなぐ場合はレベル変換が要ります。高速で長い配線はノイズに弱く、波形が鈍ってデータが化けるので、クロックを上げすぎず配線を短く保つのが安定動作のコツです。「読めるが値がおかしい」ときはモード設定、「まったく読めない」ときは配線やCSの取り違えを、と症状で原因を絞ります。まとめると、速度や大きなデータ転送が要るならSPI、配線本数を節約して多数のセンサをつなぎたいならI2C、と用途で使い分けるのが実務の判断になります。

この項目に出てくる用語

SPIえすぴーあい
MOSI/MISO/SCLK/CSの4線を使う高速な全二重シリアル通信。

関連コマンド

ls

▶ 学習アプリでこの続きを学ぶ・演習する