SPI multislave interference problem

Hello guys,

I have connected Arduino Mega (master) to two Arduino Unos (slave) using SPI.
First Uno is connected to temperature sensors. Second Uno is connected to accelerometer.
When I connected only one slave, I get the reading that I want. However, when I connected both slave, the result is changed.

I tried to use simple code as below to check if error still occur:

Master:

#include <SPI.h>

  void setup (void)
    {
    Serial.begin (115200);
    Serial.println ();

    digitalWrite(46, HIGH);  // ensure SS stays high for now
    SPI.begin ();

    // Slow down the master a bit
    SPI.setClockDivider(SPI_CLOCK_DIV8);
    }  // end of setup

  byte transferAndWait (const byte what)
    {
    byte a = SPI.transfer (what);
    delayMicroseconds (20);
    return a;
    } // end of transferAndWait

  void loop (void)
    {

    byte a, b, c, d;

    // enable Slave Select
    digitalWrite(46, LOW);

    transferAndWait ('a');  // add command
    transferAndWait (10);
    a = transferAndWait (17);
    b = transferAndWait (33);
    c = transferAndWait (42);
    d = transferAndWait (0);

    // disable Slave Select
    digitalWrite(46, HIGH);

    Serial.println ("Adding results:");
    Serial.println (a, DEC);
    Serial.println (b, DEC);
    Serial.println (c, DEC);
    Serial.println (d, DEC);

    // enable Slave Select
    digitalWrite(46, LOW);

    transferAndWait ('s');  // subtract command
    transferAndWait (10);
    a = transferAndWait (17);
    b = transferAndWait (33);
    c = transferAndWait (42);
    d = transferAndWait (0);

    // disable Slave Select
    digitalWrite(46, HIGH);

    Serial.println ("Subtracting results:");
    Serial.println (a, DEC);
    Serial.println (b, DEC);
    Serial.println (c, DEC);
    Serial.println (d, DEC);

    delay (1000);  // 1 second delay
    }

Slave:

volatile byte command = 0;

void setup (void)
  {

  // 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);

  }  // end of setup


// SPI interrupt routine
ISR (SPI_STC_vect)
  {
  byte c = SPDR;

  switch (command)
    {
    // no command? then this is the command
    case 0:
      command = c;
      SPDR = 0;
      break;

    // add to incoming byte, return result
    case 'a':
      SPDR = c + 15;  // add 15
      break;

    // subtract from incoming byte, return result
    case 's':
      SPDR = c - 8;  // subtract 8
      break;

    } // end of switch

  }  // end of interrupt service routine (ISR) SPI_STC_vect

void loop (void)
  {

  // if SPI not active, clear current command
  if (digitalRead (SS) == HIGH)
    command = 0;
  }

When I only connect to one slave, the result as follow:

Adding results:
25
32
48
57
Subtracting results:
2
9
25
34
Adding results:
25
32
48
57
Subtracting results:
2
9
25
34

But when I connect wire from second slave, the result changed to this:

Adding results:
25
32
48
57
Subtracting results:
2
9
25
34
Adding results:
10
17
33
42
Subtracting results:
2
9
25
34

You can see that interference happened as I get the input again for some case.

This is how I connect the board

Uno 1 pin Mega pin
13 52
12 50
11 51
10 46
Uno 2 pin Mega pin
13 52
12 50
11 51
10 48

Please guide me to solve this problem.
Thank you.

When master connects to multiple SPI slaves, each must have its own SS Pin controlled by the master.
On the master, there must be a separate SS Output Pin per slave, max. one of them being LOW (active) at a time.

michael_x:
When master connects to multiple SPI slaves, each must have its own SS Pin controlled by the master.
On the master, there must be a separate SS Output Pin per slave, max. one of them being LOW (active) at a time.

Yes, I have set pin 46 as SS pin for slave 1 and pin 48 for slave 2

I also set both pin as HIGH before I start the SPI communication.

pinMode(48, OUTPUT);
digitalWrite(48, HIGH);
pinMode(46, OUTPUT);
digitalWrite(46, HIGH);

but still cannot get correct result.

In the code you posted, you only change the state of pin 46.

I changed the code to this:

#include <SPI.h>

  void setup (void)
    {
    Serial.begin (115200);
    Serial.println ();

    // ensure all SS stays high for now
    pinMode(48, OUTPUT);
    digitalWrite(48, HIGH);
    pinMode(46, OUTPUT);
    digitalWrite(46, HIGH);

    SPI.begin ();

    // Slow down the master a bit
    SPI.setClockDivider(SPI_CLOCK_DIV8);
    }  // end of setup

  byte transferAndWait (const byte what)
    {
    byte a = SPI.transfer (what);
    delayMicroseconds (20);
    return a;
    } // end of transferAndWait

  void loop (void)
    {

    byte a, b, c, d;

    // enable Slave Select
    digitalWrite(46, LOW);

    transferAndWait ('a');  // add command
    transferAndWait (10);
    a = transferAndWait (17);
    b = transferAndWait (33);
    c = transferAndWait (42);
    d = transferAndWait (0);

    // disable Slave Select
    digitalWrite(46, HIGH);

    Serial.println ("Adding results:");
    Serial.println (a, DEC);
    Serial.println (b, DEC);
    Serial.println (c, DEC);
    Serial.println (d, DEC);

    // enable Slave Select
    digitalWrite(46, LOW);

    transferAndWait ('s');  // subtract command
    transferAndWait (10);
    a = transferAndWait (17);
    b = transferAndWait (33);
    c = transferAndWait (42);
    d = transferAndWait (0);

    // disable Slave Select
    digitalWrite(46, HIGH);

    Serial.println ("Subtracting results:");
    Serial.println (a, DEC);
    Serial.println (b, DEC);
    Serial.println (c, DEC);
    Serial.println (d, DEC);

    delay (1000);  // 1 second delay
    }

but still have same problem.

In loop() you are not addressing altering pin 48.

I'm not altering it because I only communicate with slave 1 (46).
I guess by set pin 48 as HIGH in setup(), it will remain HIGH in loop. So master will "ignore" slave 2.

Is it just the longer wires you're adding when you connect the second one? Can you connect the wires without the UNO at the other end?

Long wires give you problems, initially because of the capacative coupling. The clock and the data wires running side-by-side make a capacitor, which means the clock tends to drag the data line up to the same voltage. One mitigation for this, if using ribbon cable, is to put a ground or power wire between clock and data.

Then you get reflections off the ends of the wires if they're not terminated with the proper impedance. The whole theory is called "transmission line theory" and it gets pretty complex. That's why you see 75ohm connectors used on 75ohm cable even though a connector doesn't really have a resistance.

Pin 53 is hardware slave select on the Mega. I would try 53 and some other pin for your slave select. The hardware slave select has to be an output.

Also what MorganS said. How long are these connecting wires?

MorganS:
Is it just the longer wires you're adding when you connect the second one?

No, both are 10 cm. I use single male to male jumper wire, not ribbon wire.

MorganS:
Can you connect the wires without the UNO at the other end?

I'm sorry, I don't understand what you mean.

I plan to use pin 53 for SD Card breakout board. That is why I set different pins for Unos

Ok 10cm has never caused a problem on SPI in my experience. (I2C can have problems at that length.)

It certainly seems odd that just plugging in the second device causes the first to fail. Make sure all those pins are declared as inputs on the second device. SPI.begin() should do this for you, don't put in separate lines of code.