シリアル・ペリフェラル・インターフェース(SPI)を使用して、ATmega48/88/168と周辺デバイス間、または複数のAVRデバイス間での高速同期データ通信を行うことができます。
USARTをマスターSPIモードで使用することもできます(「USARTのSPIモード」(p.198)を参照)。SPIモジュールを有効にするには、「消費電力を最小にするために」(p.40)に記載されているPRSPIビットをゼロにしておく必要があります。
Figure 18-1. SPI ブロック図(1)
注: 1. SPI各端子の配置については、Figure 1-1 (p.2)、Table 13-3 (p.77)を参照
Figure18-2に、マスターCPUとスレーブCPUをSPIで接続したものを記します。このシステムは、二つのシフトレジスタとマスター・クロック・ジェネレータにより構成されています。SPIマスターは、対象のSPIスレーブのスレーブ・セレクト(/SS)ピンをLowにすることにより通信サイクルを開始します。マスターとスレーブは、各々のシフトレジスタ上に転送データを準備し、そして、マスターがSCKライン上にデータ交換に必要なクロック・パルスを生成します。データは、マスター・アウト・スレーブ・イン(MOSI)ラインでは、常にマスター側からスレーブ側へと、そして、マスター・イン・スレーブ・アウト(MISO)ライン上では、スレーブ側からマスター側へと、シフトされます。それぞれのデータ・パケット終了後、マスターは、スレーブ・セレクト(/SS)ラインをHighにして、スレーブと同期をとります。
マスターとして設定した場合、SPIインターフェースが/SSラインを自動的に制御することはありません。この制御はユーザー・ソフトウェアにより、通信を開始する前に行わなければなりません。この制御が完了してから、SPIデータ・レジスタへ1バイトの書き込みを行うことで、SPIクロック・ジェネレータが動作開始し、ハードウェアによる8ビット分のデータのシフトがスレーブ側へと行われます。1バイトのシフトが完了すると、SPIクロック・ジェネレータは停止し、転送終了フラグ(SPIF)がセットされます。SPCRレジスタのSPI割込み有効ビット(SPIE)がセットされている場合、割込み要求が発生します。マスターは、SPDRレジスタに次のバイトを書き込んで転送を継続するか、あるいは、スレーブ・セレクト(/SS)ラインをHighにしてパケット終了の合図を送ることができます。最後に受信したバイトは、後で利用できるように、バッファ・レジスタに保存されています。
スレーブとして設定した場合、SPIインターフェースは/SS端子がHighになっている間、MISOをハイ・インピーダンスにしてスリープ状態のまま待機します。この状態では、ソフトウェアによりSPIデータ・レジスタ(SPDR)の内容を更新することができますが、/SS端子がLowにならない限り、SCK端子のクロック・パルスによってデータが外部へシフトされることはありません。1バイトのシフトが完了すると、転送終了フラグ(SPIF)がセットされます。SPCRレジスタのSPI割込み有効ビット(SPIE)がセットされている場合、割込み要求が発生します。スレーブは、受信したデータを読み取る前に、転送する次のデータをSPDRレジスタに書き込むことができます。最後に受信したバイトは、後で利用できるように、バッファ・レジスタに保存されています。
Figure 18-2. SPI マスター・スレーブ接続
SPIのシステム構成は、送信方向では単一バッファになっており、受信方向では二重バッファになっています。送信については、シフト・サイクルが完全に完了するまでは、SPIデータ・レジスタに次に送信するバイト・データを書き込んではいけません。一方、データ受信の際は、受信したバイト・データを、次のデータが完全にシフトされてくる前に、SPIデータ・レジスタから読み取らなければならない、ということです。そうしないと、最初のバイト・データは失われてしまいます。
SPIスレーブ・モードでは、制御ロジックにより、SCK端子への入力クロック信号をサンプリングします。クロック信号を正しくサンプリングできるように、信号のLow期間、High期間は以下のように設定しなければなりません。
SPIが有効になっているとき、MOSI、MISO、SCK、/SS各端子の入出力方向は、Table18-1 (p.162)のように切り換わります。ポート端子の自動的な機能切り換えについての詳細は、「ポートの機能切り換え」(p.75)を参照してください。
Table 18-1. SPI端子の入出力方向切り換え(注)
端子 | マスターSPI側の入出力方向 | スレーブSPI側の入出力方向 |
---|---|---|
MOSI | ユーザー定義 | 入力 |
MISO | 入力 | ユーザー定義 |
SCK | ユーザー定義 | 入力 |
/SS | ユーザー定義 | 入力 |
注: ユーザー定義のSPI端子の入出力方向を設定する方法の詳細については、「13.3.1 ポートBの機能切り替え」(p.77)を参照してください。
下記のコーディング例では、SPIをマスターとして初期化し、単純なデータ転送を行う方法を表しています。コーディング例中のDDR_SPIは、実際にSPI端子に関係するデータ入出力方向レジスタに置き換える必要があります。DD_MOSI、DD_MISO、DD_SCKは、各端子に相当する入出力方向レジスタのビットに置き換えてください。例えば、MOSIがPB3端子に配置されている場合は、DD_MOSIをDDB3に、DDR_SPIをDDRBに置き換えてください。
アセンブリ言語での例(1) |
SPI_MasterInit: ; MOSIとSCKを出力に、他のすべてを入力に設定 ldi r17,(1<<DD_MOSI)|(1<<DD_SCK) out DDR_SPI,r17 ; SPIをマスターとして有効に設定、クロック・レートをfck/16に設定 ldi r17,(1<<SPE)|(1<<MSTR)|(1<<SPR0) out SPCR,r17 ret SPI_MasterTransmit: ; データ(r16)の転送を開始 out SPDR,r16 Wait_Transmit: ; 転送完了を待つ in r16, SPSR sbrs r16, SPIF rjmp Wait_Transmit ret |
C言語での例(1) |
void SPI_MasterInit(void) { /* MOSIとSCKを出力に、他のすべてを入力に設定 */ DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK); /* SPIをマスターとして有効に設定、クロック・レートをfck/16に設定 */ SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0); } void SPI_MasterTransmit(char cData) { /* 転送を開始 */ SPDR = cData; /* 転送完了を待つ */ while(!(SPSR & (1<<SPIF))) ; } |
注: 1. 「サンプル・コードについて」(p.7)を参照
下記の例は、SPIをスレーブとして設定し、単純なデータ受信を行う方法について示したものです。
アセンブリ言語での例(1) |
SPI_SlaveInit: ; MISOを出力に、他のすべてを入力に設定 ldi r17,(1<<DD_MISO) out DDR_SPI,r17 ; SPIを有効にする ldi r17,(1<<SPE) out SPCR,r17 ret SPI_SlaveReceive: ; 受信が完了するまで待つ sbis SPSR,SPIF rjmp SPI_SlaveReceive ; 受信データを読み取り、リターン in r16,SPDR ret |
C言語での例(1) |
void SPI_SlaveInit(void) { /* MISOを出力に、他のすべてを入力に設定 */ DDR_SPI = (1<<DD_MISO); /* SPIを有効にする */ SPCR = (1<<SPE); } char SPI_SlaveReceive(void) { /* 受信が完了するまで待つ */ while(!(SPSR & (1<<SPIF))) ; /* 受信データを読み取り、リターン */ return SPDR; } |
注: 1. 「サンプル・コードについて」(p.7)を参照
SPIがスレーブに設定されている場合、スレーブ・セレクト(/SS)端子は常に入力となります。/SSがLowになっているときSPIが動作状態になり、ユーザー・プログラムで出力になるように設定されていれば、MISOが出力となります。他のすべての端子は入力です。/SSがHighになると、すべての端子は入力となり、SPIは待機状態になり、データ受信を行いません。SPIの回路は、/SSをHighにすると一旦リセットされることに注意してください。
/SS端子は、スレーブのビット・カウンターをマスターのクロック・ジェネレータと同期させる、パケット/バイトの同期をとるのに便利です。/SS端子がHighになると、SPIスレーブは即座に送受信回路をリセットし、シフト・レジスタ中にある受信途中のデータをすべて破棄します。
SPIがマスターに設定されている(SPCRレジスタのMSTRビットがセットされている)場合、ユーザーにより/SS端子の入出力方向を決定することができます。
/SS端子を出力として設定すると、同端子はSPIシステムに影響をおよぼさない汎用の出力端子となります。一般的な例では、この出力端子をSPIスレーブの/SS端子を制御するために使います。
/SS端子を入力として設定した場合、SPIマスターとして動作させるためには、この端子をHighに保持しなければなりません。/SS端子を入力としてSPIマスターに設定している時に/SS端子が周辺回路によりLowになった場合、他のマスターがSPIをスレーブとして選択してデータを送信しようとしている、とSPIシステムは解釈します。バスの競合を回避するために、SPIシステムは以下のような動作を行います。
したがって、割込みによって処理されているSPIデータ転送がマスター・モードで行われており、/SS端子がLowになる可能性がある場合、その割込み処理では常にMSTRビットがセットされているかどうかをチェックする必要があります。MSRTビットがスレーブ・セレクト信号によりクリアされた場合、ユーザー・プログラムによって再びSPIマスター・モードを有効にしなければなりません。
シリアル・データに対するSCKの位相と極性には4種類の組み合わせがあり、これはCPHAとCPOLの制御ビットにより決定されます。Figure18-3とFigure18-4に、SPIデータ転送フォーマットを示します。SCK信号の逆のエッジにおいて、データ・ビットのシフト出力とラッチ入力がそれぞれ行われており、データ信号が安定するまでに十分な時間を確保しています。この様子は、下記のTable18-3とTable18-4に図示したものを見ると明確にわかります。
Table 18-2. CPOLビットの機能
前方エッジ | 後方エッジ | SPIモード | |
---|---|---|---|
CPOL=0, CPHA=0 | ラッチ動作(立ち上がりエッジ) | シフト動作(立ち下がりエッジ) | 0 |
CPOL=0, CPHA=1 | シフト動作(立ち上がりエッジ) | ラッチ動作(立ち下がりエッジ) | 1 |
CPOL=1, CPHA=0 | ラッチ動作(立ち下がりエッジ) | シフト動作(立ち上がりエッジ) | 2 |
CPOL=1, CPHA=1 | シフト動作(立ち下がりエッジ) | ラッチ動作(立ち上がりエッジ) | 3 |
Figure 18-3. SPI転送フォーマット (CPHA = 0)
Figure 18-4. SPI転送フォーマット (CPHA = 1)
ビット | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
0x2C (0x4C) | SPIE | SPE | DORD | MSTR | CPOL | CPHA | SPR1 | SPR0 | SPCR |
Read/Write | R/W | R/W | R/W | R/W | R/W | R/W | R/W | R/W | |
初期値 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
このビットのセットによって、SPSRレジスタのSPIFビットがセットされたとき、SREGのグローバル割込み有効ビット(Iビット)がセットされていると、SPI割込みが実行されます。
SPEビットに1が書き込むと、SPIが有効になります。SPIを動作させる場合には、必ずこのビットをセットしなければなりません。
DORDビットに1を書き込むと、データ・ワードのLSBが先に転送されます。
DORDビットに0を書き込むと、データ・ワードのMSBが先に転送されます。
このビットが1の場合SPIマスター・モード、0の場合SPIスレーブ・モードが選択されます。MSTRビットがセットされている間に、入力として設定されている/SS端子がLowになると、MSTRビットはクリアされ、SPSRレジスタのSPIFビットがセットされます。この場合、ユーザー・プログラムにおいてMSTRビットをセットし、再度SPIマスター・モードを有効にする必要があります。
このビットに1を書き込むと、SCK端子がHighのときにシフト・レジスタが静止状態となります。0を書き込むと、SCK端子がLowのときに静止状態となります。動作例については、Figure18-3、およびFigure18-4を参照してください。CPOLビットの機能について、下記の表にまとめます。
Table 18-3. CPOLビットの機能
CPOL | 前方エッジ | 後方エッジ |
---|---|---|
0 | 立ち上がりエッジ | 立ち下がりエッジ |
1 | 立ち下がりエッジ | 立ち上がりエッジ |
クロック位相ビット(CPHA)の設定により、データのサンプリングをSCKの前方エッジで行うか、後方エッジで行うかを決定します。動作例については、Figure18-3、およびFigure18-4を参照してください。CPHAビットの機能について、下記の表にまとめます。
Table 18-4. CPHAビットの機能
CPHA | 前方エッジ | 後方エッジ |
---|---|---|
0 | サンプリング | シフト・レジスタのセットアップ |
1 | シフト・レジスタのセットアップ | サンプリング |
この二つのビットにより、マスターとして設定されているデバイスのSCKクロック分周比を設定します。SPR1、SPR0はスレーブ・モードの動作には影響ありません。SCKクロックと発振器クロック周波数foscとの関係を、下記の表に記します。
Table 18-5. SCKクロックと発振器周波数との関係
SPI2X | SPR1 | SPR0 | SCKクロック周波数 |
---|---|---|---|
0 | 0 | 0 | fosc/4 |
0 | 0 | 1 | fosc/16 |
0 | 1 | 0 | fosc/64 |
0 | 1 | 1 | fosc/128 |
1 | 0 | 0 | fosc/2 |
1 | 0 | 1 | fosc/8 |
1 | 1 | 0 | fosc/32 |
1 | 1 | 1 | fosc/64 |
ビット | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
0x2D (0x4D) | SPIF | WCOL | - | - | - | - | - | SPI2X | SPSR |
Read/Write | R | R | R | R | R | R | R | R/W | |
初期値 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
シリアル転送が完了すると、SPIFフラグがセットされます。SPCRレジスタのSPIEビットがセットされていて、グローバル割込みフラグが有効になっていると、割込みが発生します。SPIマスター・モードで、/SS端子が入力に設定されていて、Lowになったときも、SPIFフラグがセットされます。SPIFフラグは、対応する割込みベクトルが処理されるとハードウェアによりクリアされます。別の方法として、まず、SPIFビットがセットされた状態のSPIステータスレジスタを読み込み、その後SPIデータレジスタ(SPDR)にアクセスすることで、SPIFフラグをクリアすることができます。
データ転送中にSPIデータレジスタ(SPDR)に書き込みがあると、WCOLビットがセットされます。まず、WCOLビットがセットされた状態のSPIステータスレジスタを読み込み、その後SPIデータレジスタにアクセスすることで、WCOLビット(および、SPIFビット)をクリアすることができます。
このビットはATmega48/88/168では予約ビットとなっており、読み取り時には常にゼロとなります。
このビットに1を書き込むと、SPIマスター・モードにおいてSPIの通信速度(SCKクロック周波数)が2倍になります(Table18-5を参照)。つまり設定可能なSCKクロックの最小周期は2CPUクロックになります。SPIがスレーブ・モードに設定されている場合、SPIはfosc/4以下の周波数でのみ動作することが保証されます。
ATmega48/88/168のSPIインターフェースは、プログラム・メモリおよびEEPROMのダウンロード、アップロードにも利用されています。「シリアル・プログラミング」(p.297)を参照してください。
ビット | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
0x2E (0x4E) | MSB | LSB | SPDR | ||||||
Read/Write | R/W | R/W | R/W | R/W | R/W | R/W | R/W | R/W | |
初期値 | X | X | X | X | X | X | X | X | 不定 |
SPIデータ・レジスタは汎用レジスタ・ファイルとSPIシフト・レジスタ間でデータのやりとりをするための読み書き可能なレジスタです。このレジスタに書き込みをすることで、データ転送が開始されます。このレジスタを読み取ることにより、シフト・レジスタの受信バッファを読み取ります。