はじめに
SPI(Serial Peripheral Interface)は、マイクロコントローラをセンサー、ディスプレイ、メモリチップに接続するために広く使用される同期式シリアル通信プロトコルです。このチュートリアルでは、Velxioシミュレータを使用してSPIループバックテストを構築します。ループバックテストは、SPI経由でバイトを送信し、応答を読み戻すことで、プロトコルが正しく動作することを確認します。物理的なスレーブデバイスがないため、シミュレータは送信したバイトを返すため、ハードウェアなしでSPIを学ぶのに最適な方法です。
回路のウォークスルー
まずは回路をセットアップしましょう。必要なコンポーネントはArduino Unoのみで、これをキャンバス上に配置します。

Arduino Unoを追加するには、キャンバスツールバーの「+」アイコンをクリックしてコンポーネントピッカーを開きます。

「Arduino Uno」を検索してキャンバスに配置します。Arduino Unoには専用のSPIピンがあります:
- MOSI(Master Out Slave In)– ピン11
- MISO(Master In Slave Out)– ピン12
- SCK(Serial Clock)– ピン13
- SS(Slave Select)– ピン10(これをチップセレクトとして使用します)
このループバックテストでは、SPI信号はArduino内部で完結するため、外部配線は必要ありません。ただし、SSピン(ピン10)を出力として設定し、初期状態でHIGH、通信中はLOWにする必要があります。コードでこれを処理します。
コードのウォークスルー
次にコードを見ていきましょう。エディタツールバーの「Code」タブをクリックしてコードエディタを開きます。

コードはArduino C++で記述されており、組み込みのSPI.hライブラリを使用しています。外部ライブラリは必要ありません。
// SPI Loopback Test
// Sends bytes via SPI and logs the exchange.
// Without a physical slave, the emulator returns the sent byte.
#include <SPI.h>
#define SS_PIN 10
void setup() {
Serial.begin(9600);
Serial.println("========================");
Serial.println(" SPI Protocol Test");
Serial.println("========================");
Serial.println();
pinMode(SS_PIN, OUTPUT);
digitalWrite(SS_PIN, HIGH);
SPI.begin();
SPI.setClockDivider(SPI_CLOCK_DIV16);
Serial.println("SPI initialized.");
Serial.print("Clock divider: 16 (");
Serial.print(F_CPU / 16);
Serial.println(" Hz)");
Serial.println();
// Send test pattern
Serial.println("Sending test pattern via SPI:");
byte testData[] = {0xAA, 0x55, 0xFF, 0x00, 0x42, 0xDE, 0xAD, 0xBE};
digitalWrite(SS_PIN, LOW); // Select slave
for (int i = 0; i < sizeof(testData); i++) {
byte sent = testData[i];
byte received = SPI.transfer(sent);
Serial.print(" TX: 0x");
if (sent < 16) Serial.print("0");
Serial.print(sent, HEX);
Serial.print(" RX: 0x");
if (received < 16) Serial.print("0");
Serial.print(received, HEX);
if (sent == received) {
Serial.println(" (loopback OK)");
} else {
Serial.println();
}
}
digitalWrite(SS_PIN, HIGH); // Deselect slave
Serial.println();
Serial.println("SPI test complete.");
}
void loop() {
delay(1000);
}
主要部分を解説します:
#include <SPI.h>:Arduino SPIライブラリをインクルードします。#define SS_PIN 10:スレーブセレクトピンをピン10として定義します。setup():シリアル通信を9600ボーで初期化し、SSピンを出力として設定してHIGHに駆動し、SPI.begin()を呼び出してSPIペリフェラルを初期化します。クロック分周器は16に設定され、クロック周波数はF_CPU / 16(16 MHz Arduinoでは1 MHz)になります。- テストパターン:8バイトの配列(
0xAA, 0x55, 0xFF, 0x00, 0x42, 0xDE, 0xAD, 0xBE)を1バイトずつ送信します。 digitalWrite(SS_PIN, LOW):スレーブを選択します(ループバックでは、これは論理的なステップにすぎません)。SPI.transfer(sent):バイトを送信すると同時にバイトを受信します。ループバックでは、受信バイトは送信バイトと等しくなります。- シリアル出力:各送信が16進数形式で表示され、送信バイトと受信バイトが一致した場合は「(loopback OK)」が追加されます。
digitalWrite(SS_PIN, HIGH):転送後にスレーブの選択を解除します。loop():テストはsetup()で一度だけ実行されるため、遅延以外は空です。
主要な概念
- SPIプロトコル:SPIは同期式全二重プロトコルで、MOSI、MISO、SCK、SSの4本のワイヤを使用します。マスターがクロックを生成し、スレーブセレクトを制御します。
- ループバック:MOSIをMISOに接続する(またはエコーするシミュレータを使用する)ことで、外部スレーブなしでSPIハードウェアをテストできます。
- クロック分周器:
SPI.setClockDivider()関数は、システムクロックに対するSCK周波数を設定します。分周器が小さいほど通信速度が速くなります。 SPI.transfer():この関数はバイトを同時に送受信します。SPI通信の中核です。
よくある落とし穴とデバッグのヒント
- SSピンの設定:SSピンは出力として設定する必要があります。そうしないと、SPIハードウェアが自動的にスレーブモードに切り替わる可能性があります。必ず
pinMode(SS_PIN, OUTPUT)を設定し、アイドル時はHIGHに駆動してください。 - ボーレートの不一致:シリアルモニタのボーレートが
Serial.begin(9600)と一致していることを確認してください。Velxioでは、シリアルモニタは自動的に開きます。 - クロック極性と位相:デフォルトのSPIモード(モード0)は、SCKアイドルLow、データは立ち上がりエッジでサンプリングされます。スレーブが異なるモードを期待する場合は、
SPI.setDataMode()を使用してください。 - 外部配線不要:このループバックテストでは配線は不要です。実際のスレーブを接続する場合は、MOSI同士、MISO同士、SCK同士、SS同士の接続を再確認してください。
推奨される拡張
- 外部スレーブを追加する:2台目のArduinoをスレーブとして追加し、スレーブスケッチを書くことで、センサーやディスプレイをシミュレートします。
- クロック速度を変更する:異なるクロック分周器(例:
SPI_CLOCK_DIV2、SPI_CLOCK_DIV128)を試し、伝送速度への影響を観察します。 - より大きなデータを送信する:テストパターンを変更して、文字列やセンサーの読み取り値を送信します。
- 割り込みを使用する:ノンブロッキング転送のために、割り込みを使用したSPI通信を実装します。
自分で試してみよう
さあ、始めましょう。Velxioでライブサンプルを開き、シミュレーションを実行してください。送信および受信された各バイトを示すシリアル出力が表示され、ループバックが確認できます。
楽しいシミュレーションを!