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