新しいPICに搭載のSPIモジュール

最近はMSSP(Master Synchronous Serial Port)から、より機能性が増えた新しいSPIモジュールが搭載されてたチップが増えてきている。
そのため新しいSPIモジュールではアプリケーション側手順も違ってます。
どちらが搭載されているかはデータシートを見ないと、パラメトリック検索では分からないです。
PPS（Peripheral Pin Select）が搭載されている事で可能になった部分も大きいので、PPSが無いものは従来のMSSPの可能性が大きいです。
（全てのチップを調べたわけではないのでデータシートを確認してください）


## MSSP（もっと古いPICではSSP）の動作概要

・SPIかI2Cを切り替えて使い、I/Oピンが共通である。(SDI/SDA , SCK/SCLとなっている)
・シフトレジスタが1つでループになっている　SDI→[SSPSR]→SDO
・バッファ(SSPBUF)に書き込むと転送開始され、完了と同時にSSPSRからSSPBUFに読まれる
・完了するとSSPIF（Interrupt flag）がセットされる（SSPIFをリセットして転送完了）

## SPIモジュールの動作概要（HOST動作）
・SPIモジュールはI2Cと独立しており、どちらもPPSでI/Oピンを選択できる
・シフトレジスタが独立しておりループになっていない　SDI→[RX Shift Register] / [TX Shift Register]→SDO
・バッファは送信、受信とも2段のFIFOになっており、送信FIFO、受信FIFO、または両方のFIFOを使用するかセレクトできる
・転送は8ビット以外にも設定出来るため、可変長ビットの転送も可能（7ビットや14ビットなど）
・送信ではTXRをセットし、転送するデータサイズを設定して、FIFOへ書き込むと転送が開始される
・受信ではRXRをセットし、転送するデータサイズを設定すると転送が開始される
・送受信ではTXRとRXRをセットし、転送するデータサイズを設定して、FIFOへ書き込むと転送が開始される
・転送状況のステータスは SPIxTXIF, SPIxRXIF ,SRMTIFのなどのフラグで構成されている

## 各種フラグについて

・SPI Transmit (SPIxTXIF)
送信FIFOが空きがあるとセットされるので、フルになるとリセット状態になる（Read Onlyでリセットは不要）
連続して書き込む場合はこのフラグを確認し、空いていたらで連続して書き込める

・SPI Receive (SPIxRXIF)
受信FIFOにデータがあるとセットされるので、データがない間だけリセット状態（Read Onlyでリセットは不要）
セットされるとデータの受信が完了している事を示すため、このフラグがセットされていたら読み込みをする

・Shift Register Empty (SRMTIF)
転送が完了するとセットされる、転送が始まるとリセットされるがソフトウェア側でリセットが必要。
転送の終わり（FIFOがゼロかつシフトレジスタが空）の場合にセットされる。

・TXWE (Transmit Buffer Write Error)
送信FIFOがフルの状態でFIFO（SPIxTXB）へ書き込むと、FIFOへデータの書き込みされずにこのフラグがセットされるクリアはソフトウェアで行う必要がある。

・TXBE (Transmit Buffer Empty)
送信FIFOが空の状態でセットされる(Read Only)

・RXRE (Receive Buffer Read Error)
受信FIFOが空の状態でFIFO（SPIxRXB）を読み込むと、ゼロのデータが読み込まれ、このフラグがセットされる。クリアはソフトウェアで行う必要がある。

・RXBF (Receive Buffer Full)
受信FIFOがフルでセットされる。(Read Only)
***
### ○送受信の動作（FullDuplex)
```C:FullDuplex
SPIxCON2bits.TXR = 1; // Transmit Data-Required Control
SPIxCON2bits.RXR = 1; // Receive FIFO Space-Required Control
SPIxTCNT = 1; // Set to SPI Transfer Counter Register
SPIxTXB = Data; // Load data into SPI Transmit Buffer
while (PIRnbits.SPIxRXIF == 0); // Check for any SPIx Receive Interrupts; 0 is FIFO Empty; flag is read-only.
return SPIxRXB; // Read Data from SPI Receive Buffer Register;

```

### ○送信の動作（Transmit Only)
```C:Transmit
SPIxCON2bits.TXR = 1; // Transmit Data-Required Control
SPIxCON2bits.RXR = 0; // Receive FIFO Space-Required Control
SPIxTCNT = 2; // Set to SPI Transfer Counter Register 2 Byte
SPIxTXB = Data1; // Load data into SPI Transmit Buffer

// 連続して書き込む場合などでバッファをチェックする場合
while (PIRnbits.SPIxTXIF== 0); // Check for any SPI Transmit Interrupts; 0 is FIFO Full; flag is read-only.
SPIxTXB = Data2; // Load data into SPI Transmit Buffer

// 転送ブロックの終了待ちをする場合
while(SPIxINTFbits.SRMTIF==0); // 1 = The data transfer is complete (Shift Register Empty Interrupt Flag)
SPI1INTFbits.SRMTIF = 0; // must be cleared in software.

```

送信専用モードではSPIxTCNTを設定しなくても転送可能でSPIxTXBへ書き込んだ時点からクロックがスタート。
書き込みと同時にSPIxTCNT=0はディクリメントされて最大値になる。
そのため、SPIxTXIFをチェックしながら送信が終わるまでデータを書き続けることで連続送信が出来る。
（ただし全ての転送が終わる（SRMTIF）がセットさせる前にデータをSPIxTXB へセットする必要ががある。）
FIFOが空になるとクロックが停止し転送が終了する。


### ○受信の動作（Recieve Only)

```C:Recieve
SPIxCON2bits.TXR = 0; // Transmit Data-Required Control
SPIxCON2bits.RXR = 1; // Receive FIFO Space-Required Control
SPIxTCNT = 1; // Set to SPI Transfer Counter Register
//SPIxTXB = Data; // Load data into SPI Transmit Buffer
while (PIRnbits.SPIxRXIF == 0); // Check for any SPIx Receive Interrupts; 0 is FIFO Empty; flag is read-only.
return SPIxRXB; // Read Data from SPI Receive Buffer Register;

```
　受信をする場合、FIFOがフルになると、クロックが一時停止する。SPIxRXBを読み込み、FIFOが空くと転送継続される。
　受信専用モードではSPIxTCNT に書き込んだ時点でクロックが開始される。
　データをSPIxTXBに書き込むと転送はされるがFIFOの占有率は変化しない。(FIFOの最初のデータが繰り返し出力される)
　送信FIFOにデータが無い場合は最後に受信したデータが送信される。（ループ動作）

### ○転送OFFの動作（Transfer-Off)
```C:Transfer-Off
SPIxCON2bits.TXR = 0; // Transmit Data-Required Control
SPIxCON2bits.RXR = 0; // Receive FIFO Space-Required Control
SPIxTCNT = 1; // Set to SPI Transfer Counter Register
SPIxTXB = Data; // Load data into SPI Transmit Buffer

```
転送はされないが（クロックは停止）、送信FIFOに書き込まれ、RXR がセットされると送信される。
送信データを最初にセットすることが可能。