PSoC 4 Pioneer KitをSPIのスレーブとして動作させて、SPI LCDのNokia 5110も同じSPIバスを使って動作させてみた。
<追記:2017.08.30>
ArduinoはSPI Slaveにすることができないので、Arduinoのスケッチの中でAVRのレジスタを使って実験しました。
「
Arduino UnoをSPI Slaveとして使う。」
</追記>
※実際の配線では「Arduino Uno」と「Nokia 5110」間のMISOはつながっていません。
SPIはスレーブの切り替えに
SS(Slave Select。CS/Chip Select)を使う。信号線はMaster
→Slaveの
MOSIとMaster
←Slaveの
MISOの2本だがスレーブの数だけ
SSが必要になる。
<追記:2016.06.03>
書き忘れてましたが、SPI通信には信号線以外にクロック線の
SCKが必要です(^q^;
</追記>
ブレッドボード図
動作としては、
1) MasterのArduinoが、繋がれているPOTの値を読み取り、SPIでSlaveのPSoC4に送信する。
2) SlaveのPSoC4はArduinoから送られてきたデータを受け取り、繋がれているロータリー・エンコーダーの値を読み取り、MasterのArduinoに送信する。
3) SlaveのPSoC4はArduinoから送られてきたデータの値(RX)と、Arduinoに送ったデータ(TX)をキャラクタLCD(パラレル接続)に表示する。
4) MasterのArduinoは1)で自分が送ったデータ(TX)と、SlaveのPSoC4から送られてきたデータ(RX)をSPI接続のLCDのNokia 5110に表示する。
したがって、POTを回しても、ロータリー・エンコーダーを回してもArduinoのLCDにもPSoC4のLCDにも同じデータが表示される。
Master側のArduinoのスケッチ
// PSoC 4 SPI Slave用のMasterプログラム
//
// POTでTXデータを設定、NOKIA 5110でTX,RXデータを表示
//
// PSoC 4 Slave
// SCK 13
// MISO 12
// MOSI 11
// CS 9
//
// LCD5110
// SCK - Pin 13
// MOSI - Pin 11
// DC - Pin 2
// RST - Pin 3
// CS - Pin 10
//
// POT A0
//
// 2016.05.09
#include <stdio.h>
#include <SPI.h>
#include <LCD5110_Graph.h>
#define PIN_PSOC_SS 9
#define PIN_POT A0
#define TX_PACKET_SIZE 3
#define RX_PACKET_SIZE 3
LCD5110 myGLCD(13,11,2,3,10); // SCK, MOSI, DC, RST, CS
extern uint8_t SmallFont[];
byte txBuffer[TX_PACKET_SIZE];
byte rxBuffer[RX_PACKET_SIZE];
char strBuffer[17];
void setup()
{
myGLCD.InitLCD();
myGLCD.setFont(SmallFont);
myGLCD.clrScr();
myGLCD.print("SPI Master", 0, 0);
myGLCD.update();
pinMode(PIN_PSOC_SS, OUTPUT);
}
void loop()
{
int txData;
int rxData;
txData = analogRead(PIN_POT);
rxData = sendRecieveData(txData);
displayData(txData, rxData);
delay(100);
}
int sendRecieveData(int txData) {
static byte cnt;
txBuffer[0] = cnt++;
txBuffer[1] = txData >> 8;
txBuffer[2] = txData & 0xff;
SPI.begin();
SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
digitalWrite(PIN_PSOC_SS, LOW);
rxBuffer[0] = SPI.transfer(txBuffer[0]);
rxBuffer[1] = SPI.transfer(txBuffer[1]);
rxBuffer[2] = SPI.transfer(txBuffer[2]);
digitalWrite(PIN_PSOC_SS, HIGH);
SPI.endTransaction();
SPI.end();
return ((int)rxBuffer[1] << 8) | (rxBuffer[2]);
}
void displayData(int txData, int rxData) {
myGLCD.clrScr();
myGLCD.print("SPI Master", 0, 0);
sprintf(strBuffer, "TXDATA: %d", txData);
myGLCD.print(strBuffer, 0, 10);
sprintf(strBuffer, "TX:%03d %03d %03d", txBuffer[0], txBuffer[1], txBuffer[2]);
myGLCD.print(strBuffer, 0, 20);
sprintf(strBuffer, "RX:%03d %03d %03d", rxBuffer[0], rxBuffer[1], rxBuffer[2]);
myGLCD.print(strBuffer, 0, 30);
sprintf(strBuffer, "RXDATA: %d", rxData);
myGLCD.print(strBuffer, 0, 40);
myGLCD.update();
}
Nokia 5110の表示には「Nokia5110_Graph」ライブラリを使っている。(参考「
ロジックICでSPIの5V->3.3Vレベルシフト Nokia LCD5110を動かす」)。
PSoC4とのSPI通信にはArduinoの「SPI」ライブラリを使った。「NOKIA5110_Graph」はArduinoのSPIライブラリを使用していない(ATMega328pのハードウェアSPIも使っていない)ので、PSoC4との通信の前後でSPIオブジェクトをbegin()、end()させている。こうしないとNokia 5110との通信がうまくいかない。
送受信データは、どちらも3byteにしていて、Masterが生成したカウンターの値(1byte)+POT/RotaryEncoderの16bitの読み取り値(2byte)。
Slave側のPSoC4のプロジェクト
TopDesign
SPISはSCBのSPIコンポーネントでスレーブに設定している。UARTはデバッグ用に使った。PIN_REというPINコンポーネントはロータリー・エンコーダーの読み取り用。
Github:
https://github.com/ryood/PSoC4_SPI_Slave_Test
Master側 (Arduino)
https://github.com/ryood/PSoC4_SPI_Slave_Test/tree/master/Arduino(Master)/SPI_Master_PSOC4_Slave_w_UI
Slave側 (PSoC4)
https://github.com/ryood/PSoC4_SPI_Slave_Test/tree/master/PSoC(Slave)/PSoC4_SPI_Slave_Test
メモ:
SPIは全二重なので送信だけ、受信だけという使い方にするには少し工夫が必要。普通のシリアル通信のようにプログラムを書くと
電話でお互いが勝手に喋っべいるみたいな状態(自分の声でかき消されて相手が何を言っているか聞き取れない?)になってしまってハマってしまった。
SlaveからMasterに送信するには、Master側からSlaveに「どうぞ」と声をかけてからSlaveが送信するとか、Master側から制御するR/Wの信号線を追加するとかしないとダメかもしれない。