Communication between 3 or more Arduinos with SPI

Hi,
I need to communicate more than 2 Arduinos with SPI.
I connected them this way:

I wrote the following code for receive double on master:

#include <SPI.h>

const int SS1 = 8;
const int SS2 = 9;
double valor;
byte* pvalor;
byte slave = 0;

void setup() {
  // set the SS1 as an output:
  pinMode (SS1, OUTPUT);
  pinMode (SS2, OUTPUT);
  // Begin sending data to Slave 1
  digitalWrite(SS1,LOW);
  digitalWrite(SS2,HIGH);
  // initialize SPI:
  SPI.begin(); 
  Serial.begin (57600);   // debugging
  
  pvalor = (byte *) &valor;
}

void loop() {
  
  SPI.transfer(0x0F);
  for (int i = 0; i < 4; i++) {
    pvalor[i] = SPI.transfer(i);
    delay(100);
  }
  delay(500);
  Serial.println(valor);
  
  i++;
  
  if ((i % 10) == 0) {
    slave = (slave + 1) % 2;
    switch (slave) {
      case 0:
        digitalWrite(SS2,HIGH); 
        delay(1000);
        digitalWrite(SS1,LOW);
        break;
      case 1:
        digitalWrite(SS1,HIGH); 
        delay(1000);
        digitalWrite(SS2,LOW);
        break;
    }
  }
}

and for slaves:

#include <SPI.h>
// Definition of interrupt names
#include < avr/io.h >
#include < avr/interrupt.h >

int sensePin = 2;
double valor = 5000;
byte* pvalor;
boolean interrupt = false;
int led = 9;

void setup (void)
{
  Serial.begin (57600);   // debugging

  // read from the sense pin
  pinMode(sensePin, INPUT);
  // have to send on master in, *slave out*
  pinMode(MISO, OUTPUT);
  pinMode(led, OUTPUT);
  digitalWrite(led, LOW);

  pvalor = (byte *) &valor;

}  // end of setup

// SPI interrupt routine
ISR (SPI_STC_vect)
{
  byte c = SPDR;  // grab byte from SPI Data Register
  Serial.print(c);
  Serial.print(" ");
  switch (c) {
    case 0x0F:
      valor = valor + 1.12;
      SPDR = pvalor[0];
      break;
    case 0:
      SPDR = pvalor[1];
      break;
    case 1:
      SPDR = pvalor[2];
      break;  
    case 2:
      SPDR = pvalor[3];
      break;      
  }
}  // end of interrupt routine SPI_STC_vect

void loop (void)
{
  int valor = digitalRead(sensePin);
  if ((valor == HIGH) && (interrupt == true)) {
    digitalWrite(led, LOW);
    
    SPI.detachInterrupt();
    SPI.end();
    interrupt = false;
  } else if ((valor == LOW) && (interrupt == false)) {
    digitalWrite(led, HIGH);
    
    // turn on SPI in slave mode
    SPCR |= _BV(SPE);
    // now turn on interrupts
    SPI.attachInterrupt();
    interrupt = true;
  }
  delay(100);
}  // end of loop

This works fine for communicating 2 arduinos but, when I connect another arduino the master only receive zeros. Anyone know what can be happening?

when I put another arduino

What do you mean by that? How have you wired it all up?

Nick, I mean when a connect another Arduino to the bus, now there is a image of how I wired it on the first post.

You don't have the slave's SS pins (pin 10) connected. You do have two wires going to pins 2 for some reason but that won't do anything for SPI.

Read up on SPI's use of the SS pin when the chip is a slave.

BTW you can't just hang a LED form a pin straight to GND, you MUST have a current-limiting resistor.

Also I can't really follow your master code but you seem to do X SPI.transfer()s and then dick with SS1 and SS2 after the transfers?? You have to drop SSx, do the transfers then raise SSx.

Is SPI.attachInterrupt(); valid code? It does compile but I can't see any documentation for it. And if it is valid surely it needs a reference to a function as the parameter.


Rob

Thanks Graynomad, the problem was with the SS pin.
And the SPI.attachInterrupt(); is a valid code. I didn't pass the function as parameter because I'm registering the interrupt this way: ISR (SPI_STC_vect)

SPI.attachInterrupt just does this, so that part look OK.

void SPIClass::attachInterrupt() {
  SPCR |= _BV(SPIE);
}

@OP: http://www.gammon.com.au/spi

Apart from no resistors for the LEDs, you have to have the SS line on the slaves to be pin 10, which is what the hardware expects, as Graynomad said.

Also, as he said:

void loop() {
  
  SPI.transfer(0x0F);
  for (int i = 0; i < 4; i++) {
    pvalor[i] = SPI.transfer(i);
    delay(100);
  }

Bring the SS line (for one of the slaves) low, transfer data, bring it high again, then do the same for the other slave, as required. Don't have both low at once.

What's the delay for? Do you like code that runs slowly?

The code that I'm using now is like this:

void receiveDouble() {
  digitalWrite(slave,LOW);
  SPI.transfer(0x0F);
  for (int i = 0; i < 4; i++) {
    pvalor[i] = SPI.transfer(i);
    delay(10);
  }
  digitalWrite(slave,HIGH); 
}

And I put the delay because without it the master don't get the right value from slave.

Oh, OK, yes I forgot about that. My web page mentions needing a delay. Heh.

Is it working now?

Yes, now it's working :slight_smile:
Thanks Nick, I was trying to find some resource about Arduino SPI Slave and the one that you wrote is just what I need.

SPI.attachInterrupt(); is a valid code

Fair enough, I couldn't find any documentation. BTW I still can't, where is this documented?

Another typical example of Arduino bad naming practice. How can something call "attach" simply set a bit and not load a function pointer like the function of the same name does elsewhere. This should be enableInterrupt() or something.


Rob

It's an Easter Egg for those that browse the code. :wink:

He he, like I said, typical Arduino (non)documentation and bad naming practices.


Rob

Hi,
I am facing a similar problem. I am using arduino due for SPI communication between 3 Arduinos.
I am not able to use any other pin except for pin No 10 as a SS pin. When i use any other pin i am not able to transfer data. Please let me know what i should do.

I have a question regarding SPI Sniffing:

Data logger SPI – Ethernet data

Objective:

The objective of this project is to develop an embedded systems device, namely Datalogger. The user should choose what He/She wants to record through a GUI (Graphical User Interface). For GUI design you could use Python Tkinter or something of your choice.

Note: The thing is, you will be needing 4 Arduinos. Two Arduinos will communicate with each other using SPI. Third Arduino will act as a sniffer and collect the data that is communicated between Arduino 1 and Arduino 2 without interrupting their communication. Then the third Arduino will send this data to the fourth Arduino which is connected to the ethernet port of the Laptop. Then display the data on the GUI in PC/Laptop in a user-readable form. Also, display the data in the LCD display module. The Third Arduino will act as a sniffer.

BharghavNukala:
I have a question regarding SPI Sniffing:

Data logger SPI – Ethernet data

Objective:

The objective of this project is to develop an embedded systems device, namely Datalogger. The user should choose what He/She wants to record through a GUI (Graphical User Interface). For GUI design you could use Python Tkinter or something of your choice.

Note: The thing is, you will be needing 4 Arduinos. Two Arduinos will communicate with each other using SPI. Third Arduino will act as a sniffer and collect the data that is communicated between Arduino 1 and Arduino 2 without interrupting their communication. Then the third Arduino will send this data to the fourth Arduino which is connected to the ethernet port of the Laptop. Then display the data on the GUI in PC/Laptop in a user-readable form. Also, display the data in the LCD display module. The Third Arduino will act as a sniffer.

Waht is your question ?

Are you asking someone to write the code for your 'project' ?

Two Arduinos will communicate with each other using SPI. Third Arduino will act as a sniffer and collect the data that is communicated between Arduino 1 and Arduino 2 without interrupting their communication.

*********My question is how can third arduino be used as sniffer? or do we need to use any other module/component for sniffing the data from arduino without interrupting their communication ********