インターフェース・バス(有線)

SPI

高速な同期式シリアル通信。ディスプレイやフラッシュに。

概要

SPI(Serial Peripheral Interface:エス・ピー・アイ)は、Motorolaが1980年代に開発した同期式フルデュプレックスシリアルバスです。SCK(クロック)、MOSI(マスター→スレーブデータ)、MISO(スレーブ→マスターデータ)、CS/SS(チップセレクト)の4本の信号線で構成されます。

I2Cと比べて高速(数MHz〜数百MHz)で、フルデュプレックス(同時送受信)が可能なため、TFTディスプレイ・NORフラッシュ・SDカード・DAC・ADC・無線モジュールなど、速度が求められる用途に広く使われます。

アドレス指定の仕組みを持たず、デバイスごとに独立したCSピンで選択する方式のため、接続デバイス数が増えるほどCSピンが必要になります。一方、プロトコルがシンプルで実装しやすく、マイコン側のペリフェラルサポートも充実しています。

歴史・背景

SPIはMotorola(現NXP)が1980年代に68000系マイコン向けに開発しました。当初は正式な規格書がなく、Motorolaのデータシートの説明が事実上の標準として普及しました。そのため、各社がやや異なる実装を行った歴史があり、クロック極性(CPOL)とクロック位相(CPHA)の組み合わせによる4つのモード定義につながっています。

2000年代以降、SDカード・各種無線モジュール・フラッシュメモリなどがSPIを採用したことで爆発的に普及しました。現代のマイコンはほぼ全機種がSPIペリフェラルを内蔵しており、DMA転送にも対応しています。

高速化への需要から、QSPI(Quad SPI:4本のデータ線)やOctal SPI(8本のデータ線)も登場し、フラッシュメモリとの接続では広く使われています。

技術仕様

信号線の構成

信号名別名方向説明
SCKSCLK, CLKマスター→スレーブクロック信号
MOSISDO, DI, SDAマスター→スレーブマスター送信データ
MISOSDI, DO, SDOスレーブ→マスタースレーブ送信データ
CSSS, CE, NSSマスター→スレーブチップセレクト(Active Low)

SPIモード(CPOL/CPHA)

クロック極性(CPOL)とクロック位相(CPHA)の組み合わせで4つのモードがあります:

モードCPOLCPHAアイドル時SCKサンプリングエッジ
Mode 000Low立ち上がり
Mode 101Low立ち下がり
Mode 210High立ち下がり
Mode 311High立ち上がり

最も一般的なのはMode 0です。デバイスのデータシートで必ず確認します。

通信速度

  • 標準的なマイコンSPI: 1〜50MHz
  • SDカード: 最大50MHz(SDモード)、25MHz(SPIモード)
  • 高速フラッシュ(QSPIなど): 数百MHz
  • STM32H7のSPIペリフェラル: 最大150MHz

マルチスレーブ接続

複数スレーブを接続する場合、各スレーブに独立したCSピンが必要です:

マスター
├─ SCK  ────── SCK(スレーブ1) ── SCK(スレーブ2)
├─ MOSI ────── MOSI(スレーブ1)── MOSI(スレーブ2)
├─ MISO ────── MISO(スレーブ1)── MISO(スレーブ2)
├─ CS1  ────── CS(スレーブ1)
└─ CS2  ────────────────────── CS(スレーブ2)

デイジーチェーン接続(MOSIとMISOをリング状に接続)も可能ですが、全デバイスが同じデータ幅を持つ場合に限られます。

動作原理

SPIの基本動作は以下の流れです:

  1. マスターがCSをLowに引き下げ(スレーブ選択)
  2. マスターがSCKでクロックを発生
  3. MOSI(マスター→スレーブ)とMISO(スレーブ→マスター)が同時にビット転送
  4. 転送完了後、CSをHighに戻す

フルデュプレックスのため、送信と受信は常に同時に行われます。スレーブへの書き込みだけが目的でも、MISOにはダミーデータが返ってきます(多くの場合0x00や0xFF)。

// STM32 HALを使ったSPI通信例

// 単純な送受信(1バイト)
uint8_t tx_data = 0xAB;
uint8_t rx_data;

HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET);  // CS Low(スレーブ選択)
HAL_SPI_TransmitReceive(&hspi1, &tx_data, &rx_data, 1, HAL_MAX_DELAY);
HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET);    // CS High(選択解除)

// TFT液晶ディスプレイへのコマンド送信(ST7735例)
void lcd_write_cmd(uint8_t cmd) {
    HAL_GPIO_WritePin(DC_GPIO_Port, DC_Pin, GPIO_PIN_RESET);  // DC=Low(コマンド)
    HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET);
    HAL_SPI_Transmit(&hspi1, &cmd, 1, HAL_MAX_DELAY);
    HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET);
}

void lcd_write_data(uint8_t *data, uint16_t len) {
    HAL_GPIO_WritePin(DC_GPIO_Port, DC_Pin, GPIO_PIN_SET);    // DC=High(データ)
    HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET);
    HAL_SPI_Transmit_DMA(&hspi1, data, len);                  // DMAで高速転送
    // 完了はDMA転送完了コールバックで確認
}

DMAを使った高速転送

大量データ(ディスプレイフレームバッファ、フラッシュ読み書きなど)にはDMAが必須です:

// DMAを使ったSPI送信(フレームバッファ転送)
uint8_t frame_buffer[320 * 240 * 2];  // 320x240, 16bpp

void lcd_flush_full(void) {
    HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET);
    HAL_SPI_Transmit_DMA(&hspi1, frame_buffer, sizeof(frame_buffer));
    // 転送完了はHAL_SPI_TxCpltCallbackで通知
}

void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi) {
    HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET);
    // 次のフレーム準備
}

用途・ユースケース

SPIが活躍する主な場面:

  • TFT/OLEDディスプレイ: ST7735・ILI9341・SSD1351など多くのディスプレイドライバICはSPI接続。フレームバッファのDMA転送で高いフレームレートを実現
  • フラッシュメモリ: SPIフラッシュ(W25Qシリーズなど)のプログラム記憶や外部ストレージ
  • SDカード: SDカードのSPIモードで低速だが簡易アクセス
  • 無線モジュール: nRF24L01(2.4GHz RF)、RFM95(LoRa)などはSPIで制御
  • ADC: MCP3204(12ビット4ch ADC)などSPI接続の高精度ADC
  • IMU/センサー: MPU-9250、LSM6DS(高速サンプリングが必要な場合)
  • DAC: MCP4922(12ビット2ch DAC)など

実装・開発のポイント

CSピンの管理

CSピンはGPIOで手動制御するのが一般的です。マイコンによってはハードウェアCSが使えますが、送信バイト数の境界でのCS制御に制限がある場合があります:

// CS管理マクロ
#define CS_ASSERT()   HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET)
#define CS_DEASSERT() HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET)

// 複数バイトのトランザクション
CS_ASSERT();
HAL_SPI_Transmit(&hspi1, cmd_buf, cmd_len, 100);
HAL_SPI_Receive(&hspi1, rx_buf, rx_len, 100);
CS_DEASSERT();

クロック速度の注意

デバイスの最大SPI速度をデータシートで確認します。多くのセンサーは最大10〜20MHz程度ですが、フラッシュやディスプレイは数十MHzまで対応します。ケーブルが長い場合は速度を下げ、ノイズ対策としてFerrite beadや終端抵抗を検討します。

SPIバスの共有

複数デバイスが同じSPIバス(SCK/MOSI/MISO共有)を使う場合、CSピンで排他制御します。RTOSを使う場合はSPIバスのMutexによる排他制御が必要です:

// RTOSでのSPIバス排他制御
osMutexAcquire(spi_mutex, osWaitForever);
CS_ASSERT();
HAL_SPI_TransmitReceive(&hspi1, tx, rx, len, 100);
CS_DEASSERT();
osMutexRelease(spi_mutex);

QSPI/OctalSPIとの使い分け

通常のSPIが1本のデータ線(MOSI/MISO)を使うのに対し、QSPI(Quad SPI)は4本のデータ線を使い理論上4倍の帯域を実現します。STM32のQSPIペリフェラルは外部フラッシュをXIPモード(メモリ直接アクセス)でも利用できます。

他技術との比較

SPI vs I2C

項目SPII2C
速度数十〜数百MHz最大3.4Mbps
配線数4本+デバイス数分のCS2本(全共有)
全二重ありなし
プロトコルシンプルACK/アドレス管理が必要
用途ディスプレイ・フラッシュ・高速センサー低速センサー・EEPROM

SPI vs QSPI

通常のSPIは1ビット/クロックの転送ですが、QSPIは4ビット/クロック。外部フラッシュへのアクセス速度が大幅に向上します。ただし対応デバイスと専用ペリフェラルが必要です。

関連用語

参考リンク