Go Down

Topic: Communication between 3 or more Arduinos with SPI (Read 1 time) previous topic - next topic

Muchael

Oct 29, 2012, 08:55 pm Last Edit: Oct 30, 2012, 03:08 pm by Muchael Reason: 1
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:

Code: [Select]
#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:

Code: [Select]
#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?

Nick Gammon

Quote
when I put another arduino


What do you mean by that? How have you wired it all up?
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

Muchael

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.

Graynomad

#3
Oct 30, 2012, 04:15 pm Last Edit: Oct 30, 2012, 04:25 pm by Graynomad Reason: 1
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
Rob Gray aka the GRAYnomad www.robgray.com

Muchael

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)

Nick Gammon

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

Code: [Select]

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


@OP: http://www.gammon.com.au/spi
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

Nick Gammon

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:

Code: [Select]

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?
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

Muchael

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

Code: [Select]
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.

Nick Gammon

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

Is it working now?
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

Muchael

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

Graynomad

Quote
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
Rob Gray aka the GRAYnomad www.robgray.com

Nick Gammon

It's an Easter Egg for those that browse the code. ;)
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

Graynomad

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

______
Rob
Rob Gray aka the GRAYnomad www.robgray.com

Go Up