Arduino to arduino communication using SPI

Hello there!

I am Yogesh. I am trying to communicate the integer data from one arduino to another arduino using SPI communication protocol. The receiver arduino is not giving any output.
Please help me find the solution.

Code for sender arduino-

#include <SPI.h>

void setup (void) {
   Serial.begin(115200); //set baud rate to 115200 for usart
   digitalWrite(SS, HIGH); // disable Slave Select
   SPI.begin ();
   SPI.setClockDivider(SPI_CLOCK_DIV8);//divide the clock by 8
}

void loop (void) {
  
   digitalWrite(SS, LOW); // enable Slave Select
   // send test string
   for (int p ; p<30; p++) {
      SPI.transfer (p);
      Serial.print(p);
    
   }
   digitalWrite(SS, HIGH); // disable Slave Select
   delay(2000);
}

code for receiver arduino-

#include <SPI.h>
char buff [50];
volatile byte indx;
volatile boolean process;

void setup (void) {
   Serial.begin (115200);
   pinMode(MISO, OUTPUT); // have to send on master in so it set as output
   SPCR |= _BV(SPE); // turn on SPI in slave mode
   indx = 0; // buffer empty
   process = false;
   SPI.attachInterrupt(); // turn on interrupt
}
ISR (SPI_STC_vect) // SPI interrupt routine
{ 
   byte c = SPDR; // read byte from SPI Data Register
   if (indx < sizeof buff) {
      buff [indx++] = c; // save data in the next index in the array buff
      if (c == '\r') //check for the end of the word
      process = true;
   }
}

void loop (void) {
   if (process) {
      process = false; //reset the process
      Serial.println (buff); //print the array on serial monitor
      indx= 0; //reset button to zero
   }
}

Welcome to the forum

Where is SS declared and which pin does it use ?

I have used default pin i.e. digital pin 10 for ss.

I show you simple example where 1-byte data exchange takes place between Master and Slave. You may follow this example and adjust your sketches. In addition to that you may find worth reading/practicing the examples of the attached file for multi-byte exchange.
Ch-8SPILec.pdf (352.5 KB)

Master Sketch

#include <SPI.h>

void setup ()
{
  Serial.begin(115200); //set baud rate to 115200 for usart
  SPI.begin ();
  SPI.setClockDivider(SPI_CLOCK_DIV8);//divide the clock by 8
  digitalWrite(SS, LOW); // disable Slave Select
  byte y1 = SPI.transfer (0x00);//00 (any value) goes to bring-in old data from Slave's SPDR
}

void loop ()
{
  byte y = SPI.transfer (0x35); //35 goes to Slave; comes 12
  Serial.println(y, HEX);
  delay(2000);
}

Slave Sketch

#include <SPI.h>
volatile bool flag = false;
volatile byte y1;

void setup () 
{
   Serial.begin (115200);
   pinMode(MISO, OUTPUT); // have to send on master in so it set as output
   SPCR |= _BV(SPE); // turn on SPI in slave mode
   pinMode(SS, INPUT_PULLUP);
   SPI.attachInterrupt(); // turn on interrupt
}

void loop()
{
  if(flag == true)
  {
    Serial.println(y1, HEX);  //show show 35
    flag = false; 
  }
}

ISR (SPI_STC_vect) // SPI interrupt routine
{ 
   y1 = SPDR; // read byte from SPI Data Register
   SPDR = 0x12;  //Slave sends 12 to MAster
   flag = true;
}

There is no need for exclusive declaration of SS signal/name. When SPI.h file is included and SPI.begin() is executed at the Master side, then the symbolic name SS automatically refers to DPin-10 (SS/ signal of Arduino) and it assumes HIGH state.

At the Slave side, it is needed --
to include the SPI.h file
not to execute: SPI.begin();
to execute: pinMode(MISO, OUTPUT);
to execute: pinMode(SS, INPUT_PULLUP);
to execute: bitSet(SPCR, SPE); //enable SPI Port //edit
to execute: SPI.attachInterrupt(); //SPI's interrupt logic is enabled

(post deleted by author)

Now Turn on SPI in Slave Mode by using SPI Control Register

Yes! At Slave side, we need to enable the SPE-bit of the SPCR Register. I have edited my post #5 to include it.

It works very well.
Thank you very much for the help.

1 Like

Is it possible to transmit two different data streams and recall it whenever necessary.
For example, I want to transmit velocity and distance travelled both "simultaneously" and "countinuosly" from one arduino to another arduino. also, after getting these, I want to perform some other applications on that data. and again read the velocity and distance from transmitting arduino and perform that operation , so on...
Thanks in advance.

SPI is a full-duplex byte-oriented system which means --
Within the same 8 SCK pulses, 8-bit data goes from Master to Slave and within that time frame 8-bit data come from Slave to Master.

It is the responsibility of the programmer to adjust the data transfer rate and the necessary delay (usually determined by experiments) offered at the Master side to allow Slave for managing its data structure once a data byte arrives.

Apart from the above, there are no more restrictions for exchanging any kind of data types between Master and Slave using the SPI port.

Would appreciate to see a typical example of your data item that you want to exchange.

Thank you very much for the response.

I am a Mechanical engineer and have very less knowledge about coding. I really appreciate you helping me out with this problem.

I am not able to write the code but below is the basic idea of the operation I am planning to perform. Its to implement adative cruise control system.

Sender arduino:
It should send current speed (v1) of the vehicle and and distance(d1) travelled from the start of car(program).
(Basically want to tranfer two variables)

Receiver arduino:
It should receive data v1 and d1 from the sender arduino.
It will calculate relative velocity(v2) from the data got through sensors.(programming for this is already done).
print relative velocity (v2-v1)
print relative distance (d2-d1)
suggest the acceleration or deacceleartion ( another variable) (coding is already done)
repeat this in a loop.

I would really appreciate any help.

You have not told your problem for which you seek assistance.

Code for sender arduino

#include <SPI.h>
#include<NewPing.h>
NewPing sonar (5,6,200);
NewPing sonar2 (2,3,200);

void setup ()
{
  Serial.begin(115200); //set baud rate to 115200 for usart
  SPI.begin ();
  SPI.setClockDivider(SPI_CLOCK_DIV8);//divide the clock by 8
  digitalWrite(SS, LOW); // disable Slave Select
 // byte y1 = SPI.transfer (0x00);//00 (any value) goes to bring-in old data from Slave's SPDR
}

void loop ()
{
int d1=sonar.ping_cm();
int v1=sonar2.ping_cm();

  byte a = SPI.transfer (v1);Serial.println (v1);delay(100);
  byte a = SPI.transfer (d1);Serial.println (d1);delay(100);

}

I am not able to receive the v1 and d1 value from the sender arduino. can you suggest modifications in below code.

Code for receiver arduino

void setup() {
   // Pin mode for Input: d_error
    pinMode(0 , INPUT);
    // Pin mode for Input: v_rel
    pinMode(1 , INPUT);
    pinMode(2 , OUTPUT);
 }

void loop() {
 int v2= analogRead(0);
 int d2=analogRead(1);

int v_rel=(v2-v1);
int d_rel= (d2-d1);
 
  //Afetr getting v1 and d1 from sender arduino
  if (v_rel>10&& d_rel=>10)
  {
    analogWrite(2,255);
   }
 if (v_rel<10&& d_rel<10)
  {
    analogWrite(2,50);
   }
}

For data exchange between two Arduinos, there are other options -- I2C and UART/SUART. Why do you prefer to use SPI?

Can you tell me the values of d1 and v1 at the Master side?

Assume that:
d1 = 2345;
v1 = 1378;

Now follow examples of my attached file of post #3 and create sketches for both Master and Slave.

I have tried both the suggested options. mostly worked on i2c communication. but while using i2c, all the values are sent to the receiver at once. Also, those values are not synchronised. the delay given in the sender code is not having any effect on receiver input. i am getting both the values at once.
for your reference, here is simple code I have used

for sender arduino

//i2c sender mega

#include <Wire.h>

void setup() {
  Wire.begin(8);                // join i2c bus with address #8
  Wire.onRequest(requestEvent); // register event
}


void loop() {
  // put your main code here, to run repeatedly:
 delay(100);
}

void requestEvent() {

  Wire.write("any value for d1");
 delay(2000);
  Wire.write("any value for v1");

}

for receiver

//i2c receiver uno

#include <Wire.h>

void setup() {
  Wire.begin();        // join i2c bus (address optional for master)
  Serial.begin(9600);  // start serial for output
}

void loop() {
  Wire.requestFrom(8, 12);    // request 12 bytes from peripheral device #8
delay(500);
  while (Wire.available()) { // peripheral may send less than requested
    int c = Wire.read(); // receive a byte as character
    Serial.println(c);         // print the character
  } 
}

I have found very less resoures on UART/SUART.

v1 and d1 values are continuosly changing .

The programming and operation of I2C bus is simpler than that of SPI Port. Just give me numerical two values that you want to send from I2C-Master to 2C-Slave using I2C Bus. Please, be specific as to MEGA is I2C-Master and UNO is I2C-Slave.

You can read the materials of the attached files on UART architecture and programming.
Ch-6UARTLec.pdf (451.8 KB)
Expt-6(UART).pdf (429.5 KB)

You can transfer as much data as you want. The data is sent byte by byte, so it is infinite, this is the same for serial port type UART, type SPI, type I2C, type OneWire, among others that operate in a serialized way, such as the SATA port of mass storage and the USB port.

But it is interesting to operate with frames, being generally used a header, control data, effective data, error control, terminator. Control bytes, headers and terminators are especially important when the system operates in a noisy environment, either due to noise generated in the device itself, or from an external source.

Here is an example widely used in systems with Xbee boards:
https://www.digi.com/resources/documentation/Digidocs/90002002/Content/Tasks/t_calculate_checksum.htm

Note: networking - Difference between PACKETS and FRAMES - Stack Overflow

Have fun!

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