はじめに (対象読者・この記事でわかること)
この記事は、ArduinoでSPI通信を扱うエンジニアや学生、 hobbyist の方を対象にしています。特に、MOSI(Master Out Slave In)や SCK(Serial Clock)信号がオシロスコープやロジックアナライザに波形として現れないというトラブルに直面した人に向けて執筆しました。この記事を読むことで、以下のことが分かります。
- SPI の基本構成と Arduino 側の設定方法
- MOSI・SCK が出力されない代表的なハード・ソフトウェア要因
- 実際の配線チェックからコード修正、IDE 設定までの具体的な対策手順
この問題はハードウェアの接続ミスやライブラリ設定のミスが原因となることが多く、原因を突き止めるのが意外と骨折りです。本稿では、失敗例を踏まえて効率的に原因を特定し、正常な波形を取得できるようになるまでの流れを解説します。
前提知識
この記事を読み進める上で、以下の知識があるとスムーズです。
- Arduino の基本的なプログラミング(
setup()/loop()の概念) - SPI の概念と 4 本の信号線(MOSI, MISO, SCK, SS)についての基礎知識
- Arduino IDE のインストールとシリアルモニタの使用経験
SPI通信の基礎と問題点
SPI(Serial Peripheral Interface)は、マスター側がクロック(SCK)を生成し、データを MOSI で送信、MISO で受信する全二重通信規格です。Arduino では SPI ライブラリが標準で提供されており、SPI.begin() でマスター側の初期化、SPI.transfer() でデータ送受信を行います。
しかし、MOSI と SCK が実際にピンから出力されていないという症状は、ハードウェアとソフトウェアのどちらか、あるいは両方に問題が潜んでいることが多いです。代表的な原因は次の通りです。
-
配線ミス
- MOSI(Arduino Uno では D11)や SCK(D13)を誤ったピンに接続している。
- ピンがブレッドボードのトラクト上でショート/オープンしている。 -
ピンモード設定の忘れ
-pinMode()で出力に設定し忘れると、デフォルトで入力になり波形が出ません。
- Arduino IDE の「Arduino as ISP」や「プログラマ」設定が関係する場合も。 -
SPI ライブラリの呼び出しミス
-SPI.begin()が呼ばれていない、またはSPI.setClockDivider()でクロックが極端に遅い/速すぎる。 -
電源・接地不良
- デバイスの VCC と GND が不安定だと、SPI バス全体が機能しなくなる。 -
IDE のボード設定ミス
- 正しいボード(例: Arduino Uno)とポートが選択されていないと、アップロード自体が失敗し、コードが走らないケース。
このように、問題は多岐にわたりますが、系統的にチェックリストを作成し、一つずつ検証することで確実に原因を絞り込むことが可能です。
MOSI・SCK が出力されない原因と対策
以下では、実際に「波形が出ない」現象が起きたときの具体的な対策手順を、配線確認からコード修正、IDE 設定まで段階的に解説します。
ステップ1:配線とハードウェア確認
-
ピン配置の再確認
- Arduino Uno の MOSI はデジタルピン 11、SCK はピン 13 です。ボードのシルク印刷や公式ピンマップを参照し、確実に接続してください。 -
ブレッドボードの導通チェック
- マルチメータの導通モードで、MOSI・SCK 端子から外部デバイスへの配線が正しく接続されているか確認します。
- 特に、同じ列に複数の線が交差している場合は、ショートしやすいので注意。 -
プルアップ/プルダウンの有無
- SPI バスはプルアップが不要ですが、外部デバイスが内部でプルダウン抵抗を持つことがあります。必要に応じて 10kΩ のプルアップを SCK に追加してみてください。 -
電源と GND の確認
- デバイスと Arduino が同じ GND に接続されているか、電源が安定しているか測定器で確認します。
ステップ2:Arduino IDE の設定とコード確認
Cpp#include <SPI.h> void setup() { // SPI マスターとして初期化 SPI.begin(); // MOSI, MISO, SCK を自動設定 // 必要に応じてクロック速度を設定(例: 4MHz) SPI.setClockDivider(SPI_CLOCK_DIV4); // デバッグ用にシリアルモニタを開始 Serial.begin(115200); while (!Serial) ; // シリアルポートが開くまで待つ Serial.println("SPI 初期化完了"); } void loop() { // 例として 0x55 を送信し、受信データを表示 uint8_t sendByte = 0x55; uint8_t recvByte = SPI.transfer(sendByte); Serial.print("送信: 0x"); Serial.print(sendByte, HEX); Serial.print(" 受信: 0x"); Serial.println(recvByte, HEX); delay(500); }
- 重要ポイント
1.SPI.begin()が必ず呼ばれているか。これが無いと MOSI と SCK は無効です。
2.SPI.setClockDivider()でクロックが極端に遅すぎると、オシロスコープで波形が見えにくくなることがあります。デフォルトは 4MHz(Arduino Uno)ですが、必要に応じて調整してください。
3. シリアルモニタで「SPI 初期化完了」のメッセージが出ていれば、コードは正しく走っています。
ハマった点やエラー解決
| 現象 | 原因 (仮説) | 解決策 |
|---|---|---|
| MOSI が全く変化しない | pinMode(MOSI, OUTPUT) が抜けている |
SPI.begin() が内部で設定するため pinMode は不要。ただし、マニュアルで pinMode を上書きした場合は再確認 |
| SCK が一定の LOW で止まる | クロック分周設定が SPI_CLOCK_DIV128 になっている(クロックが 125kHz) |
SPI.setClockDivider(SPI_CLOCK_DIV4) へ変更 |
アップロード成功でも Serial.println が出ない |
ボード選択が間違っている(例: Arduino Nano の代わりに Arduino Uno) | 「ツール > ボード」で正しいボードを選択し、再度アップロード |
| オシロスコープでノイズだけが見える | GND が適切に接続されていない | Arduino とオシロスコープの GND を同一に接続 |
解決策
- 配線再確認:MOSI と SCK を正しいピンに接続し、導通テストを実施。
- コードの最低構成:
SPI.begin()とSPI.transfer()だけのシンプルスケッチで動作確認。 - IDE のボード・ポート設定:ボードとポートが正しく選択されているか再チェック。
- クロック速度の調整:デフォルトが速すぎる場合は
SPI.setClockDivider()で下げ、波形が見えるか確認。 - デバッグ情報の活用:シリアルモニタに「SPI 初期化完了」や送受信データを出力し、コードが実行中かどうかを可視化。
上記手順を順に実施すれば、MOSI と SCK が正常に出力されるようになります。問題が解消したら、実際の外部デバイス(例: SD カード、OLED ディスプレイ)と接続し、データ転送が期待通りに行えるか最終確認してください。
まとめ
本記事では、Arduino で SPI 通信を行う際に MOSI と SCK が波形として出力されない典型的な原因と、具体的な解決手順を解説しました。
- 配線ミスや導通不良が最も多いことを確認し、ピン配置の再チェックを推奨。
SPI.begin()の呼び忘れやクロック分周設定の誤りがコード側の主因であることを実例と共に示した。- IDE のボード・ポート設定やシリアルデバッグを活用し、ソフト側のトラブルシュート手順を体系化した。
これらのポイントを押さえることで、無駄な試行錯誤を減らし、すぐに正常な SPI 波形を取得できるようになります。次回は、実際に外部デバイス(SD カードや液晶)を接続した「フルスタック」な SPI プロジェクトに挑戦する記事を執筆予定です。
参考資料
- Arduino SPI ライブラリ公式リファレンス
- Arduino Uno ピンマップ (公式サイト)
- 「Make: Arduinoのはじめ方」(技術書出版社, 2022)
- SPI バスのタイミングとトラブルシューティング (EE Times)
