Can't get result from slave after calling the spi.transfer16()

Hi,

i have set up of 2 arduino's uno which communicating by SPI.
The master code :

// Written by Nick Gammon
// February 2011


#include <SPI.h>
unsigned short controlReg = 10000000000000;
uint16_t masterReceive;
int bitIndexToSet=0;

void setup (void)
{
  Serial.begin(115200); //Starts Serial Communication at Baud Rate 115200
  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_DIV32);  
  
}  // end of setup

void loop (void)
{

  // enable Slave Select
  digitalWrite(SS, LOW);    // SS is pin 10
 
   bitSet(controlReg,bitIndexToSet);  
  
   masterReceive = SPI.transfer16 (controlReg);

   bitClear(controlReg,bitIndexToSet);

    bitIndexToSet++;

    if (bitIndexToSet==15)
    {
      bitIndexToSet=0;
    }
  Serial.println(masterReceive ,BIN);

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

}  // end of loop

The Slave Code:

// Written by Nick Gammon
// February 2011


#include <SPI.h>
#include <SoftwareSerial.h>


  #define SCK_PIN 13  //CLK is 13
  #define MISO_PIN 12 //MSIO is  12
  #define MOSI_PIN 11 //MOSI is 11
  #define SS_PIN 10   //SS is 10


unsigned short controlReg = 0;
volatile boolean process_it;
uint16_t regBuffer; 
int channel;
uint16_t sendToMaster = 111111110000000;
byte higherByte = 0;
byte lowerByte = 0;
byte myBuffer[2]={0};
int i=0;
long interuptCounter = 0;

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

  // turn on SPI in slave mode
  SPCR = (1<<SPIE)|(1<<SPE)|(0<<DORD)|(0<<MSTR)|(0<<CPOL)|(0<<CPHA)|(0<<SPR1)|(1<<SPR0);

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

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

}  // end of setup


// SPI interrupt routine
ISR (SPI_STC_vect)
{
  myBuffer[i]= SPDR;
  i++;
  interuptCounter++;
  SPDR = sendToMaster;
  
      
}   
//end of interrupt routine SPI_STC_vect

// main loop - wait for flag set in interrupt routine
void loop (void)
{
  if (i==2)
  {
    Serial.println((int)myBuffer[0]<<8 & 0xFF00|(int)myBuffer[1], BIN);
    i=0;
  }
    
}  // end of loop

The master send 16 bits to the slave by the spi.transfer16() function.
The 16 bits change every interrupt:

10000000000000001
10000000000000010
10000000000000100
10000000000001000
10000000000010000
10000000000100000
10000000001000000 ect...

The communication from master --> slave works fine ,and i do get the right data on the slave side.

After receiving the 16 bits from the master i am trying to send 16 bits (constant 16 bit:1111111100000000) back to the master from the slave.
But unfortunately i do not get this 16 bits on the master side.

The result i get on the master is like this:
1000000010000001
1000000010000010
1000000010000100
1000000010001000
1000000010010000
1000000010100000
1000000011000000
1000000010000000
1000000010000001

I am sending the data from slave to master by setting the SPDR value.

What is wrong?
What do i have to do on the slave side in order to send back to the master 16 bits?
What do i have to do on the master side in order to get the 16 bit from the slave?

What is wrong?

There is probably an error in the code you're hiding from us.

What do i have to do on the slave side in order to send back to the master 16 bits?

You have to provide two bytes in the right order to the SPI hardware.

What do i have to do on the master side in order to get the 16 bit from the slave?

You have to read two bytes from the SPI hardware. This can be done by the SPI.transfer16() method but with the usual slave side code this doesn't work.

// SPI interrupt routine
ISR (SPI_STC_vect)
{
  myBuffer[i]= SPDR;
  i++;
  interuptCounter++;
  SPDR = sendToMaster;
  
      
}

You should move the line that sets the SPDR register as early as possible to have the value ready for sending to the master as fast as possible.

i and interruptCounter are not declared volatile, the compiler may optimize any code away if it thinks it may help (as the code may not be relevant).

I am trying the to send the constant 2 byte :111111110000000

No, you are not. SPDR is a 8 bit register, setting it to a 16 bit integer will use only the lower 8 bit (every time). You set the sendToMaster variable to 0xFD80, so the lower byte is sent 0x80.

As you variables are not declared correctly your interrupt may be compiled to something that does not exactly what you expect it to do.

@OP

Try the following sketches:

MEGA-Master-SPI Codes:

#include <SPI.h>
int i = 0;
byte myData[] = {0x12, 0x34};

union
{
  int x;
  byte rxData[2];
} data;

void setup()
{
  Serial.begin(115200);
  SPI.begin ();
  SPI.setClockDivider(SPI_CLOCK_DIV128); //125 kHz ; difficult at 4 MHz speed
  digitalWrite(SS, LOW);
  delay(100);
}

void loop()
{
  SPI.transfer(myData, sizeof(myData));
  data.rxData[0] = myData[1];  //SPI is simultaneous send and receive 1-byte offset
  data.rxData[1] = myData[0];

  Serial.print("Received data from Slave: ");
  Serial.println(data.x, BIN);
  Serial.println("=========================================================");

  delay(2000);
}

NANO-Slave-SPI Codes:

#include <SPI.h>  //needed just for the symbols: MISO, SS
volatile uint16_t sensorId;
int sendToMaster = 0b111111110000000; //7F80
volatile bool flag1 = false;
byte myData[] =
{
  lowByte(sendToMaster), highByte(sendToMaster)
};
int i = 0;

void setup()
{
  Serial.begin(115200);
  pinMode(MISO, OUTPUT);
  pinMode(SS, INPUT_PULLUP);
  SPCR |= _BV(SPE);
  bitClear(SPCR, 4);  //SPI slave
  SPCR |= _BV(SPIE);
}

void loop()
{
  if (flag1 == false)
  {
    ;
  }
  else
  {
    SPDR = myData[i];//highByte(distancePrimaryCM);
    flag1 = false;
    i++;
    if ( i == 2)
    {
      i = 0;
    }
  }
}

ISR(SPI_STC_vect)
{
  flag1 = true;
}

Screenshot of MEGA:
sm-spi8.png

sm-spi8.png

pylon:

// SPI interrupt routine

ISR (SPI_STC_vect)
{
 myBuffer[i]= SPDR;
 i++;
 interuptCounter++;
 SPDR = sendToMaster;
 
     
}




You should move the line that sets the SPDR register as early as possible to have the value ready for sending to the master as fast as possible.

i and interruptCounter are not declared volatile, the compiler may optimize any code away if it thinks it may help (as the code may not be relevant).

No, you are not. SPDR is a 8 bit register, setting it to a 16 bit integer will use only the lower 8 bit (every time). You set the sendToMaster variable to 0xFD80, so the lower byte is sent 0x80.

As you variables are not declared correctly your interrupt may be compiled to something that does not exactly what you expect it to do.

Thanks Phylon,
But how do i need to transmit correctly 16 bit from master to slave and how do i need to receive it on the master side?

GolamMostafa:
@OP

Try the following sketches:

MEGA-Master-SPI Codes:

#include <SPI.h>

int i = 0;
byte myData[] = {0x12, 0x34};

union
{
  int x;
  byte rxData[2];
} data;

void setup()
{
  Serial.begin(115200);
  SPI.begin ();
  SPI.setClockDivider(SPI_CLOCK_DIV128); //125 kHz ; difficult at 4 MHz speed
  digitalWrite(SS, LOW);
  delay(100);
}

void loop()
{
  SPI.transfer(myData, sizeof(myData));
  data.rxData[0] = myData[1];  //SPI is simultaneous send and receive 1-byte offset
  data.rxData[1] = myData[0];

Serial.print("Received data from Slave: ");
  Serial.println(data.x, BIN);
  Serial.println("=========================================================");

delay(2000);
}




**NANO-Slave-SPI Codes:**


#include <SPI.h>  //needed just for the symbols: MISO, SS
volatile uint16_t sensorId;
int sendToMaster = 0b111111110000000; //7F80
volatile bool flag1 = false;
byte myData[] =
{
  lowByte(sendToMaster), highByte(sendToMaster)
};
int i = 0;

void setup()
{
  Serial.begin(115200);
  pinMode(MISO, OUTPUT);
  pinMode(SS, INPUT_PULLUP);
  SPCR |= _BV(SPE);
  bitClear(SPCR, 4);  //SPI slave
  SPCR |= _BV(SPIE);
}

void loop()
{
  if (flag1 == false)
  {
    ;
  }
  else
  {
    SPDR = myData[i];//highByte(distancePrimaryCM);
    flag1 = false;
    i++;
    if ( i == 2)
    {
      i = 0;
    }
  }
}

ISR(SPI_STC_vect)
{
  flag1 = true;
}




**Screenshot of MEGA:**
![sm-spi8.png|517x381](upload://iMd4RIymk8S81JAQdsIbpyng3NG.png)

Your solution didn't work for me because i use the spi.transfer16() on the master code.
As you can see, on the subject of my topic, the problem is only when i use the spi.transfer16().
when i use the spi.transfer() it works fine, but i need to use the spi.transfer16().

Thanks GolamMostafa, but your solution you offered is good only for spi.transfer() and doesn't work with spi.transfer16() (which i use).

If you change your code from spi.transfer() to spi.transfer16()
you get on the master "1001000110100" and dont get the "1111111100000000"

How can i get the "111111110000000" on the master side while using the spi.transfer16() ?

Tomerf111:
How can i get the "111111110000000" on the master side while using the spi.transfer16() ?

MasterMEGA SPI Codes:

#include <SPI.h>
unsigned short controlReg = 00000000000000;
int masterReceive;

void setup (void)
{
  Serial.begin(115200);
  digitalWrite(SS, HIGH);  // ensure SS stays high for now
  SPI.begin ();
  delay(100);
  digitalWrite(SS, LOW);    // SS is pin 10
  SPI.setClockDivider(SPI_CLOCK_DIV128);  //125 kbits/sec
}

void loop()
{
  masterReceive = SPI.transfer16(controlReg);
  Serial.println(masterReceive, BIN);
  delay(1000);      //test interval
}

SlaveNAO SPI Codes:

#include <SPI.h>  //needed just for the symbols: MISO, SS
int sendToMaster = 0b111111110000000; //7F80
volatile bool flag1 = false;

byte myData[] =
{
  lowByte(sendToMaster), highByte(sendToMaster)
};
int i = 0;

void setup()
{
  Serial.begin(115200);
  pinMode(MISO, OUTPUT);
  pinMode(SS, INPUT_PULLUP);
  SPCR |= _BV(SPE);
  SPCR |= _BV(SPIE);
}

void loop()
{
  if (flag1 == false)
  {
    ;
  }
  else
  {
    SPDR = myData[i];
    flag1 = false;
    i++;
    if ( i == 2)
    {
      i = 0;
    }
  }
}

ISR(SPI_STC_vect)
{
  flag1 = true;
}

Screenshot at Master Side
smspi13.png

smspi13.png

Thanks alot GolamMostafa, now it works!

But, i have something strange.

I added only this single line to your code (on the slave loop code):

void loop()
{
if (flag1 == false)
{
;
}
else
{
SPDR = myData*;*
** Serial.println(SPDR);**

  • flag1 = false;*
  • i++;*
  • if ( i == 2)*
  • {*
  • i = 0;*
  • }*
  • }*
    }
    and then the masterReceive (on the master side) is affected.
    Why is that???

You just can't put/add codes anywhere whatever you like and expecting that the system should work. You can do it for experiments purpose, and in that case you need to find out the reasons why we can't do like this. Please, study the attached write-up and start to learn SPI Communication from the very beginning.

Section-7(SPI)doc.doc (432 KB)