Hi,
I have written the codes below. to use SPI between 2 arduino UNOs as a first trial based on Nick Gammon’s tutorial.
I send commands ‘i’ and ‘o’ to the master over serial. Slave receives commands over SPI. ‘i’ turns ON and LED. ‘o’ turns the LED OFF.
I’ve set up this protocol for the SPI communitcation:
The code does what just that but it really bothers me that it seems that you need to have that “delayMicroseconds (20)” inbetween transfers else things just don’t work properly and stop responding!
the SPDR register should be already updated by the time SPI.transfer is complete. so why do we need to wait 20us before actually reading the data.
And to make things more fun, if I use Serial.print to try and debug, it work fine! :o
Any ideas why, anyone?
MASTER:
#include <SPI.h>
volatile char req[9];
volatile uint8_t a, i = 0;
byte transferAndWait (byte what)
{
byte x = SPI.transfer (what);
delayMicroseconds (20); //wait for slave to process and reply
return x;
}
void setup (void)
{
Serial.begin (9600);
digitalWrite(SS, HIGH); // ensure SS stays high for now
SPI.begin ();
SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));
Serial.println ("READY");
}
void loop (void)
{
uint8_t j;
if (Serial.available()) {
req[i] = Serial.read();
++i;
}
if (req[i - 1] == ';') {
if (req[0] == 'o') { //turn LED OFF
// enable Slave Select
digitalWrite(SS, LOW);
a = transferAndWait(0); //start SPI COMMS
//Serial.println (String(a,HEX));
a = transferAndWait('o'); //send command
//Serial.println (String(a,HEX));
a = transferAndWait(0); //end SPI COMMS
if (a == 'O') {
Serial.print("LED OFF!");
Serial.println (char(a));
}
else {
Serial.print("Failed! ");
Serial.println (String(a, HEX));
}
// disable Slave Select
digitalWrite(SS, HIGH);
}
else if (req[0] == 'i') { //turn LED ON
// enable Slave Select
digitalWrite(SS, LOW);
a = transferAndWait(0); //start SPI COMMS
//Serial.println (String(a,HEX));
a = transferAndWait('i'); //send command
//Serial.println (String(a,HEX));
a = transferAndWait(0); //end SPI COMMS
if (a == 'I') {
Serial.print("LED ON!");
Serial.println (char(a));
}
else {
Serial.print("Failed! ");
Serial.println (String(a, HEX));
}
// disable Slave Select
digitalWrite(SS, HIGH);
}
i = 0;
}
}
SLAVE:
#define SPI_TIMEOUT 25
#include <SPI.h>
volatile uint8_t start = 0, command = 0;
// SPI interrupt routine
ISR (SPI_STC_vect)
{
byte spi = SPDR;
if (spi == 0 && start == 0) { //start of SPI comms
if (command != 0xA3) {
start = 1;
SPDR = 0xA4; //acknowledge start of comms
}
else {
command = 0;
SPDR = 0;
}
}
else if (start > 0) {
if (start == 1) {
start = 2;
command = spi;
}
if (command == 'o') {
digitalWrite(2, LOW);
command = 0xA3; //end of command
start = 0; //end of comms
SPDR = 'O';
}
else if (command == 'i') {
digitalWrite(2, HIGH);
command = 0xA3; //end of command
start = 0; //end of comms
SPDR = 'I';
}
else { //reset spi comms
start = 0;
command = 0;
}
}
timeout = micros();
}
void setup (void)
{
pinMode(2, OUTPUT); //LED output
digitalWrite(2, LOW);
// have to send on master in, *slave out*
pinMode(MISO, OUTPUT);
// turn on SPI in slave mode
SPCR |= _BV(SPE);
// turn on interrupts
SPCR |= _BV(SPIE);
SPDR = 0; //initialise SPI register
} // end of setup
void loop (void)
{
//re-initialise SPI variables on timeout
if (SPDR != 0 && (micros() - timeout) > SPI_TIMEOUT) {
start = 0;
command = 0;
SPDR = 0;
}
}