概要
SPI (Serial Peripheral Interface) は、マスター・スレーブ方式を採用するシリアル通信インターフェースの一種であり、主にマイコンとペリフェラル (周辺機器) 間の通信に使用される。
同期式通信で、マスターがクロック信号を生成する。
全二重 (双方向) 通信が可能であり、少ないピン数で高速なデータ通信を実現することができる。
SPIの主な特徴を以下に示す。
- マスター・スレーブ方式
- マスター・スレーブ方式を採用しており、通常1つのマスターデバイスが1つ以上のスレーブデバイスを制御する。
- 全二重通信
- 全二重通信が可能であり、マスターとスレーブが同時にデータを送受信できる。
- 3本以上の信号線
- SPIは、以下に示す信号線を使用する。
- SCLK (Serial Clock)
- マスターが生成するクロック信号
- MOSI (Master Output, Slave Input)
- マスターからスレーブへのデータ送信線
- MISO (Master Input, Slave Output)
- スレーブからマスターへのデータ送信線
- SS (Slave Select)
- マスターがスレーブを選択するための信号線
- SCLK (Serial Clock)
- デイジーチェーン接続
- 複数のスレーブを接続する場合、デイジーチェーン接続が可能である。
- これにより、マスターは最小限の信号線でスレーブを制御することができる。
- 高速通信
- SPIは比較的高速な通信が可能であり、一般的にはMHz単位のクロック周波数で動作する。
- 柔軟性
- SPIはクロック極性(CPOL)とクロック位相(CPHA)を設定できるため、様々なデバイスに対応可能です。
SPIは、EEPROM、フラッシュメモリ、センサ、ディスプレイ等、多様なペリフェラルとの通信に広く使用されている。
ただし、シンプルな構成と高速性が特徴であるが、デバイス数の増加に伴い信号線が増えるため、大規模なシステムには不向きな場合がある。
MSP430G2553のSPI通信
MSP430G2553のSPIモジュール
MSP430G2553におけるSPIモジュールは、USCI_A0レジスタ (Universal Serial Communication Interface) を使用することにより、実現することができる。
MSP430マイコンでは、マスターおよびスレーブとして動作可能である。
7つの動作モードが選択できる。 (3線式SPI、4線式SPI、I2C等)
データ長は7ビット、または、8ビットが選択可能である。
MSP430G2553のSPIは、センサ、メモリ、ディスプレイ等の外部デバイスとの高速なデータ通信に適している。
適切な設定と通信プログラムにより、効率的なデータ交換が可能である。
SPI通信で使用する信号線
- SCLK (Serial Clock)
- マスターが生成するクロック信号
- MOSI (Master Out, Slave In)
- マスターからスレーブへのデータ送信線
- MISO (Master In, Slave Out)
- スレーブからマスターへのデータ送信線
- CS (Chip Select)
- スレーブを選択するための信号線
SPI通信の動作概要
まず、マスターがクロック信号を生成し、通信を開始する。
マスターとスレーブは、MOSIとMISOを介して同時にデータを送受信する。
次に、マスターはCSを使用して通信するスレーブを選択する。
クロックの極性 (CPOL) とフェーズ (CPHA) は設定可能である。
SPI通信の設定手順
- SPIに使用するピンの機能を選択する。 (UCA0SIMO、UCA0SOMI、UCA0CLK)
- クロック源の選択とボーレートを設定する。
- SPIモード (マスター / スレーブ) を選択する。
- データ長、クロックの極性とフェーズを設定する。
- 必要に応じて、割り込みを設定する。
- マスターの場合は、CSピンを制御する。
サンプルコード : データの送信
以下の例では、MSP430G2553がマスターとしてSPI通信を行い、スレーブデバイスにデータ (0x55) を繰り返し送信している。
以下に示す手順により、SPI通信を行っている。
- まず、spi_init関数でSPIの初期化を行う。
- spi_init関数では、SPIに使用するピンの機能選択、クロック源の選択、ボーレートの設定、SPIモードの設定等を行う。
- メインループ内で、以下の処理を繰り返す。
- CSピンをLowにしてスレーブを選択する。
- spi_send_byte関数を実行して、データ (例: 0x55) をスレーブに送信する。
- spi_send_byte関数では、送信バッファが空になるまで待機して、データを送信バッファに書き込む。
- CSピンをHighにしてスレーブを解放する。
- 100[ms]の遅延を入れる。
スレーブデバイスの種類や接続方法に応じて、サンプルコードを適宜変更すること。
#include <msp430.h>
#define SPI_SCLK_PIN BIT5 // P1.5 (UCB0CLK)
#define SPI_MOSI_PIN BIT7 // P1.7 (UCB0SIMO)
#define SPI_MISO_PIN BIT6 // P1.6 (UCB0SOMI)
#define SPI_CS_PIN BIT4 // P1.4 (CS)
void spi_init(void);
void spi_send_byte(unsigned char data);
int main(void)
{
WDTCTL = WDTPW | WDTHOLD; // ウォッチドッグタイマを停止
spi_init(); // SPIの初期化
while (1) {
P1OUT &= ~SPI_CS_PIN; // CSをLowにしてスレーブを選択
spi_send_byte(0x55); // データ (例: 0x55) を送信
P1OUT |= SPI_CS_PIN; // CSをHighにしてスレーブを解放
__delay_cycles(100000); // 100[ms]の遅延
}
}
void spi_init(void)
{
P1SEL |= SPI_SCLK_PIN | SPI_MOSI_PIN | SPI_MISO_PIN; // SPI用のピンを選択
P1SEL2 |= SPI_SCLK_PIN | SPI_MOSI_PIN | SPI_MISO_PIN;
P1DIR |= SPI_CS_PIN; // CSピンを出力に設定
P1OUT |= SPI_CS_PIN; // CSをHighに設定
UCB0CTL1 |= UCSWRST; // UCB0をリセット
UCB0CTL0 |= UCCKPH | UCMSB | UCMST | UCSYNC; // MSBファースト, マスターモード, 同期モード
UCB0CTL1 |= UCSSEL_2; // SMCLK
UCB0BR0 = 0x02; // ボーレートを設定 (SMCLK / 2)
UCB0BR1 = 0;
UCB0CTL1 &= ~UCSWRST; // UCB0をリセット解除
}
void spi_send_byte(unsigned char data)
{
while (!(IFG2 & UCB0TXIFG)); // 送信バッファが空になるまで待機
UCB0TXBUF = data; // データを送信バッファに書き込む
}
サンプルコード : データの受信 (マスターデバイス側)
以下の例では、MSP430G2553がマスターとしてSPI通信を行い、スレーブデバイスからデータを繰り返し受信している。
以下に示す手順により、SPI通信を行っている。
- まず、spi_init関数でSPIの初期化を行う。
- spi_init関数では、SPIに使用するピンの機能選択、クロック源の選択、ボーレートの設定、SPIモードの設定等を行う。
- メインループ内で、以下の処理を繰り返す。
- CSピンをLowにしてスレーブを選択する。
- spi_receive_byte関数を実行して、スレーブからデータを受信する。
- 受信バッファ (1[byte]) にデータが受信されるまで待機する。
- 受信したデータを変数received_dataに格納する。
- CSピンをHighにしてスレーブを解放する。
- 100[mS]の遅延を入れる。
スレーブデバイスの種類や接続方法に応じて、サンプルコードを適宜変更すること。
#include <msp430.h>
// マクロは、データ送信の場合と同様のため省略
void spi_init(void);
unsigned char spi_receive_byte(void);
int main(void)
{
WDTCTL = WDTPW | WDTHOLD; // ウォッチドッグタイマを停止
spi_init(); // SPIの初期化
unsigned char received_data;
while (1) {
P1OUT &= ~SPI_CS_PIN; // CSをLowにしてスレーブを選択
received_data = spi_receive_byte(); // データを受信
P1OUT |= SPI_CS_PIN; // CSをHighにしてスレーブを解放
// 受信したデータを処理
// ...略
__delay_cycles(100000); // 100[mS]の遅延
}
}
void spi_init(void)
{
// データ送信の場合と同様のため省略
}
unsigned char spi_receive_byte(void)
{
while (!(IFG2 & UCB0RXIFG)); // 受信バッファ (1[byte]) にデータが入るまで待機
return UCB0RXBUF; // 受信バッファからデータを読み込む
}
送信と受信で異なる設定が必要な場合
一般的に、SPIの初期化 (ピンの機能選択、クロック源の選択、ボーレートの設定、SPIモードの設定等) において、送信および受信で同じ設定を行う。
しかし、以下に示すシナリオでは、送信用と受信用で異なる設定が必要になる。
そのため、SPIの初期化において、送信用と受信用に分けて実装する、または、送信と受信の切り替え時に動的に設定を変更する必要がある。
ただし、多くの場合、送信と受信で同じ設定を使用できるため、共通化することが一般的である。
- クロックの位相 (CPHA) や 極性 (CPOL) が異なる場合
- スレーブデバイスによっては、クロックの位相や極性の要件が異なる場合がある。
- 送信時と受信時で、クロックの位相や極性を変更する必要がある場合は、送信用と受信用で異なる設定が必要になる。
- ボーレート (通信速度) が送信時と受信時で異なる場合
- スレーブデバイスによっては、送信時と受信時でボーレートが異なる場合がある。
- 送信時と受信時で異なるボーレートを使用する必要がある場合は、送信用と受信用で異なる設定が必要になる。
- データ長が異なる場合
- スレーブデバイスによっては、送信時と受信時でデータ長が異なる場合がある。
- 送信時と受信時で異なるデータ長を使用する必要がある場合は、送信用と受信用で異なる設定が必要になる。
- 送信と受信で異なるSPIモードを使用する場合
- マスターとスレーブの役割が固定されている場合は、送信と受信で同じSPIモードを使用できる。
- ただし、マスターとスレーブの役割が動的に切り替わる場合は、送信時と受信時で異なるSPIモードを使用する必要がある。
- 送信と受信で異なるチップセレクト (CS) ピンを使用する場合
- 複数のスレーブデバイスを接続する場合、送信先と受信先で異なるCSピンを使用することがある。
- 送信時と受信時で異なるCSピンを使用する必要がある場合は、送信用と受信用で異なる設定が必要になる。