SPI byte echo

Hello, I'm trying to get 2 arduinos talking over SPI. I want the master to send something (anything really, doesn't matter what it is) to the slave, and then have the slave echo that same byte straight back to the master. Can anybody give me a super simple, bare bones example of this? Heres what I have at the moment, which doesn't work (also from 2 seperate sketches I downloaded so probably messy...)

MASTER:
#include <SPI.h>

void setup (void)
{

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);
Serial.begin(115200);

} // end of setup

void loop (void)
{

int c = 0x0FF;
// enable Slave Select
digitalWrite(SS, LOW); // SS is pin 10

// send test string
SPI.transfer (c);

Serial.println("Sent");

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

delay (1000); // 1 seconds delay
} //

SLAVE:

#include <SPI.h>

char buf [100];
volatile byte pos;
volatile boolean process_it;

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

// have to send on master in, slave out
pinMode(MISO, OUTPUT);

// turn on SPI in slave mode
SPCR |= _BV(SPE);

// get ready for an interrupt
pos = 0; // buffer empty
process_it = false;

// now turn on interrupts
SPI.attachInterrupt();

} // end of setup

// SPI interrupt routine
ISR (SPI_STC_vect)
{
byte c = SPDR; // grab byte from SPI Data Register

// add to buffer if room
if (pos < sizeof buf)
{
buf [pos++] = c;

// example: newline means time to process buffer

} // end of room available
} // end of interrupt routine SPI_STC_vect

// main loop - wait for flag set in interrupt routine
void loop (void)
{

Serial.println (buf);
pos = 0;

} // end of flag set

Please // use the code (#) button to put code snippets in code tags like this

The slave interrupt handler has to set SPDR to the just-received value, then this will be
sent back on the next SPI transfer.

// SPI interrupt routine
ISR (SPI_STC_vect)
{
  byte c = SPDR;  // grab byte from SPI Data Register
  SPDR = c ;
}

Writing SPDR puts a byte into the outgoing register, which is separate from the incoming register (which is actually double-buffered)

In the slave's setup() function set SPDR to the initial byte to send upon the first transfer...

I've got this working some time ago but without using the SPI library - presumably the same interrupt handling is compatible with
the SPI library. You've fortunately used a clock rate that's 1/4 of system clock or slower (a requirement for slave to operate correctly).

  1. writing a spi slave is no simple matter;
  2. you will need a way for the slave to understand when it is time to send data (aka a protocol).

dhenry:

  1. writing a spi slave is no simple matter;
  2. you will need a way for the slave to understand when it is time to send data (aka a protocol).
  1. Well here's a (very simple) proof-of-concept SPI slave I wrote, and
  2. the slave never has to understand when it is time to send data, because the master always makes that decision for it.
    It does have to decide what to send next time and stick it in SPDR.

A simple SPI slave looks at a command byte and queues up some response bytes or just does something... The
same as for serial in essence.

const int pinSCLK = 13 ;
const int pinMISO = 12 ;
const int pinMOSI = 11 ;
const int pinSS = 10 ;

#include <avr/io.h>
#include <avr/interrupt.h>


byte message [8] ;
byte resp [8] ;
byte N = 0 ;

ISR (SPI_STC_vect)
{
  byte to = 0 ;
  while (to < 50 && !(SPSR & (1 << SPIF)))
  {
    to ++ ;
  }
  to = SPDR ;
  if (to == 0xE5 && N == 0)
  {
    N = 1 ;
    SPDR = 0x55 ;
  }
  else if (to == 0x6B && N == 1)
  {
    N = 2 ;
    SPDR = resp [0] ;
  }
  else if (N >= 2)
  {
    message [N-2] = to ;
    if (N < 9)
    {
      SPDR = resp [N-1] ;
      N++ ;
    }
    else
    {
      SPDR = 0xAA ;
      N = 0 ;
    }
  }
}

void setup ()
{
  pinMode (pinSS, INPUT) ;
  
  // SPCR = 11000011
  //interrupt disabled,spi enabled,msb 1st,master,clk low when idle,
  //sample on leading edge of clk,system clock/16 rate
  
  SPCR = (1<<SPIE) | (1<<SPE) | (0<<MSTR) | 0x1 ;
  int junk = SPSR ;
  SPDR = 0xAA ; // first response
  pinMode (pinMISO, OUTPUT) ;
  
  Serial.begin (57600) ;
}

void barchart (byte size, byte percent)
{
  Serial.print ((char) 0xFE) ;
  Serial.print ('b') ;
  Serial.print ((char) size) ;
  Serial.print ((char) percent) ;
}
 
void loop ()
{
  delay (200) ;
  byte foo [8] ;
  foo[0] = message[0] ;
  foo[1] = message[1] ;
  foo[2] = message[2] ;
  foo[3] = message[3] ;
  foo[4] = message[4] ;
  foo[5] = message[5] ;
  foo[6] = message[6] ;
  foo[7] = message[7] ;
  for (byte i = 0 ; i < 6 ; i++)
  {
    barchart (i < 4 ? 3 : 2, foo[i] >> 1) ;
    resp [i] = analogRead (i) >> 2 ;
  }
  for (byte i = 0 ; i < 6 ; i++)
    barchart (i < 4 ? 3 : 2, resp[i] >> 1) ;
  Serial.println () ;
  delay (200) ;
}