PIC32でSPIのスレーブモード受信

Receive a SPI signal by PIC32 slave mode
 
PIC32ではMSTEN=0をセットし、スレーブモードを有効にしてSPI通信を行うと、マスター側から受け取ったクロックのタイミングをハードウェアで認識してデータに変換してくれます。

スレーブモード固有の設定は入力タイミングに関連する指定が主のものとなります。SSENを1にするとSSxピンが閉じる(立ち下がる)を感知して、続いて送られてくるクロック信号とビット列の取得を開始します。SSEN=1に加えてFRMEN=1にすると、フレーム化SPI信号(クロック信号は常に発生していて、データの受信前に一瞬だけSSxピンのスイッチが切り替わる)を識別できます。ただ、私の知る限り、フレーム化SPIを送信するICはほとんど見かけません。

それではサンプルプログラムの紹介です。ここではArduinoで生成したSPI信号をPIC32で解析させます。
まずはマスター側であるArduinoのスケッチから。こちらではSSピンを手動でオフにしてから「hello」というASCIIコードを500msごとにSPI命令で送信しています。
spisend.ino
#include <SPI.h>

#define SS 10

void setup() {
    pinMode(SS, OUTPUT);
    digitalWrite(SS, HIGH);

Serial.begin(9600);
    SPI.begin();
    delay(500);
}

void loop() {
    digitalWrite(SS, LOW);
    SPI.transfer('h');
    SPI.transfer('e');
    SPI.transfer('l');
    SPI.transfer('l');
    SPI.transfer('o');
    digitalWrite(SS, HIGH);

    delay(500);
}
つづいてPIC32でのプログラムコードです。SPI2の信号を各ピンに割り当てて(値とピンの関係についてはSPI送信の記事をご覧ください)、割り込み処理内のループで連続したビットを一度に取得しています。
spirecv.c
#include <p32xxxx.h>
#include <sys/attribs.h>

// 外部の8MHz水晶発振器から40MHzのクロックを生成するための設定
#pragma config FNOSC = PRIPLL // 発信源 = 主外部発振器
#pragma config POSCMOD = XT // 主発振の方法 = 外部高精度発振器を使う
#pragma config FPLLIDIV = DIV_2 // PLL入力分数 = x1/2
#pragma config FPLLMUL = MUL_20 // PLL逓倍比 = x20
#pragma config FPLLODIV = DIV_2 // PLL出力分数 = x1/2
#pragma config FPBDIV = DIV_2 //周辺モジュールクロック倍数 : x1/2

#pragma config ICESEL = ICS_PGx3
#pragma config DEBUG  = ON

void __ISR(_SPI2_VECTOR, IPL4AUTO) OnSpi2(void)
{
    int i, n[5];
     IFS1bits.SPI2RXIF = 0;     // 割り込みフラグのクリア
   
    for(i = 0; i < 5; i++){
        SPI2BUF = 0;
        while(!SPI2STATbits.SPIRBF);  // 受信バッファが使用可能になるのを待つ
        n[i] = SPI2BUF;
    }
}

int main(void)
{
    int i;
    ANSELB = 0x00;          // ポートBをすべてデジタルモードにする  
    TRISB = 0;              // ポートBをすべて出力にする
      
    SPI2CONbits.ON = 0;     // 設定のためSPI1を無効に
    
    SPI2CONbits.SSEN = 1;   // SSピンを有効にする
    SPI2CONbits.MSTEN = 0;  // スレーブモード
    SPI2CONbits.CKP = 0;    // ArduinoにおけるMode0
    SPI2CONbits.CKE = 1;    // ArduinoにおけるMode0
    
    SDI2Rbits.SDI2R = 0b0100; // B2にSDI2を割り当てる
    RPB1Rbits.RPB1R = 0b0100; // B1にSDO2を割り当てる
    SS2Rbits.SS2R = 0b0010;   // B0にSS2を割り当てる
    
    IPC9bits.SPI2IP = 4;      // SPI2割り込み優先度
    IPC9bits.SPI2IS = 3;      // SPI2副優先度
    
    IEC1bits.SPI2RXIE = 1;    // SPI2割り込みを有効にする
    IFS1bits.SPI2RXIF = 0;    // 割り込みフラグのクリア
    i = SPI2BUF;              // ダミーデータに格納することでバッファをクリア
    
    INTCONbits.MVEC = 1;      // マルチベクタ割り込みを有効にする
       
    __builtin_enable_interrupts();  // マイコンにおける割り込みの有効
    
    SPI2CONbits.ON = 1;       // SPI2を稼働

    while(1) ;
}
ここではデバッガでの確認でお茶を濁していますが、デバッガ情報の書き込み内容によっては、PIC内に余計な情報が挟まるためか、いつまでたっても正しい値を表示してくれないことがあります。そのときはクリーンビルドを試してみてください。
2018/09/29