0

Brief - I am using two arduino Uno's. One acts as a master and the other as slave using Arduino IDE. Below is the Master Code:

// Taken from Nick Gammon's Forum//

#include "SPI.h"
#include"pin_arduino.h"
int ss = 10;
void setup()
  {
    pinMode(ss,OUTPUT);
    Serial.begin(9600);
    Serial.println();
    digitalWrite(ss,HIGH);
    SPI.begin();
    SPI.setClockDivider(SPI_CLOCK_DIV8);
   }
byte transferAndWait(const byte what)
 {
   byte a = SPI.transfer(what);
   delayMicroseconds(20);
   return a;
 }
void loop()
 {
   byte a,b,c;
   digitalWrite(ss,LOW);
   transferAndWait('a');
a = transferAndWait(17);
b =  transferAndWait(33);
c = transferAndWait(0);
digitalWrite(ss,HIGH);
Serial.println(a,DEC);
Serial.println(b,DEC);
Serial.println(c,DEC);
delay(1000);
 }

Before I go into the details of the results I obtained and the problem, below is the Slave code:

//Taken from Nick Gammon's Forum//

#include "SPI.h"
#include "pins_arduino.h"
int slave = 10;
int miso = 11;
byte c = 0;
void setup()
  {
    pinMode(miso,OUTPUT);
    pinMode(slave,INPUT);
    Serial.begin(9600);
    SPR|= BV_(SPE);
    SPR|= BV_(SPIE);
 }
ISR(SPI_STC_vect)
 {
   c = SPDR;
  switch(c)
    {
      case 0:
      SPDR = 0;
      break;

     case 'a':
     SPDR = c + 15;
     break;
   }
  }
  void loop(void)
   {
     if(digitalRead(slave)==HIGH)
     c = 0;
   }

My Results : After dumping the master and slave codes into their respective arduino uno's, then when I open the serial monitor of the master code, It displays the number 17, 33, 0 and the same goes with the slave, meaning that the data is being sent to the slave and received back successfully, and hence I presume the SPI bus is working properly!. But why isn't the add operation happening?

Problem: Now the problem is, when the command 'a' is sent from the master to the slave, the slave has to interpret this 'a' command as Addition command and perform the addition of a number 15 to the incoming byte from the master as shown in the slave code, and return the results to the master, which should display the addition results in the masters serial monitor. I am having problem performing this task and looking forward to suggestions on how to test or where I am doing wrong or make changes to the code or methods in order to get this working. I am expecting answers relevant to the below codes and method.

1

Since I wrote that example, I'll try to answer this. First I tested with the code from my page about SPI.


SPI Master

This is the master:

#include <SPI.h>

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

  digitalWrite(SS, HIGH);  // ensure SS stays high for now

  // Put SCK, MOSI, SS pins into output mode
  // also put SCK, MOSI into LOW state, and SS into HIGH state.
  // Then put SPI hardware into Master mode and turn SPI on
  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(SS, LOW);    

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

  // disable Slave Select
  digitalWrite(SS, 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(SS, LOW);   

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

  // disable Slave Select
  digitalWrite(SS, 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 
}  // end of loop

SPI Slave

And this is the slave:

// what to do with incoming data
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;
}  // end of loop

Test results

Testing gave the expected results:

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

So, what is different in your code?

Your slave ISR:

ISR(SPI_STC_vect)
 {
   c = SPDR;
  switch(c)
    {
      case 0:
      SPDR = 0;
      break;

     case 'a':
     SPDR = c + 15;
     break;
   }
  }

This isn't quite the same, is it? In my code you get the command in one session (one interrupt) and what to use it for in another one.

Hence I had this:

  byte c = SPDR;

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

Sending a "command" of zero clears the current command. So the sequence being sent is like this:

0    <-- start a new command
command  (ie. 'a' or 's')
22   <-- what to add to
33   <-- what to add to
44
55

Perhaps confusingly, I didn't send in that order, because I knew that the command would be zero initially(1), so I actually sent:

command  (ie. 'a' or 's')
22   <-- what to add to
33   <-- what to add to
44
55
0    <-- start a new command

There would be other ways of achieving this, but the fact is you changed the way the slave interpreted the incoming data.


  1. I knew it would be zero because the slave sets the command to zero in the main loop if SS is not asserted.
0
ISR(SPI_STC_vect);  <-- Reason 1.
 {
   byte c = SPDR;
  switch(command)   <-- Reason 2.
    {                      |
      case 0:              |
      command = c;  <------┘ 
      SPDR = 0;
      break;

     case 'a':
     SPDR = c + 15;
     break;
   }
  void loop(void)   <--- Reason 3.
   {
     if(digitalRead(slave)==HIGH)
     command = 0;
   }

The slave code is not going to work, for various reasons.

Reason 1: This is a declaration of a function. Not an implementation. The ";" is badly misplaced here.

Reason 2: You're switching on a value "command" but it's only changed after executing the case/command?

Reason 3: The loop function is still part of the previous function? The "{" below the ISR(SPI... isn't closed right. (With another "}")

  • The reason 1 and 3 were a typos, sorry about that! – PsychedGuy Mar 27 '15 at 14:16
  • Oh. Thank you for pointing out reason 2. Didn't notice that. I will shift this statement outside the case and check. – PsychedGuy Mar 27 '15 at 14:20
  • I edited the slave code as shown above. But my slave code is still not executing the " SPDR = c + 15" statement for case 'a'. Its repeatedly displaying 97,97,97.... on the serial monitor. Its just a simple add operation and I cant figure whats the mistake in the code, my master code seems to look fine. Pl help me debug. – PsychedGuy Mar 27 '15 at 14:34
  • Try to go back to the basics, verify that works and build on from there. So first, make one arduino send stuff and let the other one print it as is. No handling, just serial out it. From there you can build on. I believe SPDR is only 1 byte, so sending three bytes after eachother is quite weird? Because you check on the 'a' and then send it back +15... if another byte comes in, it will not be handled by the case switch.. – Paul Mar 29 '15 at 15:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.