SPI Slave emulation - how to use SPDR properly

I am trying to understand how to send SPI data back to the master. I used the SPI examples from Circuit Digest. I am connecting 2 Arduino's together. The Master is sending SPI.tranfer16(). In the scope image below the Master sent 0x3E00. MOSI-Yellow MISO-Green

What I would like to do is detect a message from byte 1 and then send responses in bytes 3, 4, 5, 6,... depending on the value in byte 1.

When I read the first non-zero value it already responds with 0xFF.
The second byte always echos whatever is in the first?
And the rest are always 0?

My understanding was the SPDR buffer would send when the master is clocking data during the ISR. Is the ISR triggered by the CS so it only enters 1 time?

Thanks for reading :slight_smile:

//SPI SLAVE (ARDUINO)
//SPI COMMUNICATION BETWEEN TWO ARDUINO 
//CIRCUIT DIGEST
//Pramoth.T

#include<SPI.h>
volatile boolean received;
volatile byte Slavereceived;
volatile byte Slavetx;

void setup()
{
  Serial.begin(115200);
  pinMode(MISO,OUTPUT);                   //Sets MISO as OUTPUT (Have to Send data to Master IN 
  SPCR |= _BV(SPE);                       //Turn on SPI in Slave Mode
  received = false;
  SPI.attachInterrupt();                  //Interuupt ON is set for SPI commnucation
}

ISR (SPI_STC_vect)                        //Inerrrput routine function 
{
  Slavereceived = SPDR;                   // Value received from master if store in variable slavereceived
  received = true;                        //Sets received as True 
}

void loop()
{ if(received)                              
   {
      if (Slavereceived != 0) 
      {
        Serial.println("not zero");
        Slavetx = (0xAA);
      }
      else
      {
        Slavetx = (0xFF);
      }
       SPDR = Slavetx;
  
   }
}

oscope.JPG

oscope.JPG

Check Nick Gammon's write up on SPI Master & Slave here

I re-wrote the code and it's working as expected now.

I re-wrote the master side deleting the SPI.transfer16's and only used the SPI.transfer just to keep everything like Gammon's example.

Next, I moved more of my code into the interrupt subroutine ISR (SPI_STC_vect) which Gammon says not to do, but because I needed send the outgoing data according to # of messages from a particular received value. I wasn't sure if storing a count variable outside the ISR was a good idea?

But the biggest change was his transferAndWait function on the Master side. He adds a delay after the SPI.transfer. Everything works in my code great if the delay is 4ms. 3ms or less and the returned data on the scope doesn't match what it should be.

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

Here's my slave side

#include<SPI.h>
volatile byte Slavereceived;
volatile int bytecounter = 0;
volatile int msgcounter = -1;
volatile byte array_X[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};

void setup()
{
  Serial.begin(115200);
  pinMode(MISO,OUTPUT);                   //Sets MISO as OUTPUT (Have to Send data to Master IN 
  SPCR |= _BV(SPE);                       //Turn on SPI in Slave Mode
  SPI.attachInterrupt();                  //Interuupt ON is set for SPI commnucation
}

ISR (SPI_STC_vect)                        //Inerrrput routine function 
{
  Slavereceived = SPDR;                   // Value received from master if store in variable slavereceived

  if (Slavereceived == (0xEE))
  {   
    bytecounter = 1;
    msgcounter++;
    if (msgcounter == 6)
    {
      msgcounter = 0;
    }
  }
  else
  {
  bytecounter++;  
  }
  
  if (bytecounter == 5)
  {
  SPDR = array_X[msgcounter];
  }
  else
  {
  SPDR = 0;
  }
  
}


void loop()
{ 
}

oscope2.JPG

oscope2.JPG

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.