A Microcontroller uses many different protocols to communicate with various sensors and peripherals. There are many protocols for wireless and wired communication, and the most commonly used communication technique is Serial Communication. Serial communication is the process of sending data one bit at a time, sequentially, over a communication channel or bus. There are many types of serial communication like UART, CAN, USB, I2C and SPI communication.

In this tutorial we learn about SPI protocol and how to use it in Arduino. We will use SPI Protocol for communication between two Arduinos. Here one Arduino will act as Master and another one will act as Slave, two LEDs and push buttons will be connected to both the arduinos. To demonstrate SPI communication, we will control master side LED by the push button at slave side and vice versa using the SPI Serial communication protocol.

What is SPI?

SPI (Serial Peripheral Interface) is a serial communication protocol. SPI interface was found by Motorola in 1970. SPI has a full duplex connection, which means that the data is sent and received simultaneously. That is a master can send data to slave and a slave can send data to master simultaneously. SPI is synchronous serial communication means the clock is required for communication purpose.

Working of SPI

A SPI has a master/Slave communication by using four lines. A SPI can have only one master and can have multiple slaves. A master is usually a microcontroller and the slaves can be a microcontroller, sensors, ADC, DAC, LCD etc.

Below is the block diagram representation of SPI Master with Single Slave.

SPI has following four lines MISO, MOSI, SS, and CLK

MISO (Master in Slave Out) - The Slave line for sending data to the master.

MOSI (Master Out Slave In) - The Master line for sending data to the peripherals.

SS (Slave Select) –Master can use this pin to enable and disable specific devices.

SPI Master with Multiple Slaves

To start communication between master and slave we need to set the required device's Slave Select (SS) pin to LOW, so that it can communicate with the master. When it's high, it ignores the master. This allows you to have multiple SPI devices sharing the same MISO, MOSI, and CLK lines of master. As you can see in the above image there are four slaves in which the SCLK, MISO, MOSI are common connected to master and the SS of each slave is connected separately to individual SS pins (SS1, SS2, SS3) of master. By setting the required SS pin LOW a master can communicate with that slave.

SPI Pins in Arduino UNO

The image below shows the SPI pins present Arduino UNO (in red box).

SPI Line

Pin in Arduino

MOSI

11 or ICSP-4

MISO

12 or ICSP-1

SCK

13 or ICSP-3

SS

10

Using SPI in Arduino

Before start programming for SPI communication between two Arduinos. We need to learn about the SPI library used in Arduino IDE.

The library <SPI.h> is included in the program for using the following functions for SPI communication.

1. SPI.begin()

USE: To Initialize the SPI bus by setting SCK, MOSI, and SS to outputs, pulling SCK and MOSI low, and SS high.

2. SPI.setClockDivider(divider)

USE: To Set the SPI clock divider relative to the system clock. The available dividers are 2, 4, 8, 16, 32, 64 or 128.

Dividers:

SPI_CLOCK_DIV2

SPI_CLOCK_DIV4

SPI_CLOCK_DIV8

SPI_CLOCK_DIV16

SPI_CLOCK_DIV32

SPI_CLOCK_DIV64

SPI_CLOCK_DIV128

3. SPI.attachInterrupt(handler)

USE: This function is called when a slave device receives data from the master.

4. SPI.transfer(val)

USE: This function is used to simultaneous send and receive the data between master and slave.

So now let’s start with practical demonstration of SPI protocol in Arduino. In this tutorial we will use two arduino one as master and other as slave. Both Arduino are attached with a LED & a push button separately. Master LED can be controlled by using slave Arduino’s push button and slave Arduino’s LED can be controlled by master Arduino’s push button using SPI communication protocol present in arduino.

Components Required

Arduino UNO (2)

LED (2)

Push Button (2)

Resistor 10k (2)

Resistor 2.2k (2)

Breadboard

Connecting Wires

Arduino SPI Communication Circuit Diagram

Programming Explanation

This tutorial has two programs one for master arduino and other for slave arduino. Complete programs for both the sides are given at the end of this project.

Master Arduino Programming Explanation

1. First of all we need to include the SPI library for using SPI communication functions.

#include<SPI.h>

2. In void setup()

We Start Serial Communication at Baud Rate 115200.

Serial.begin(115200);

Attach LED to pin 7 and Push button to pin 2 and set those pins OUTPUT and INPUT respectively.

pinMode(ipbutton,INPUT); pinMode(LED,OUTPUT);

Next we begin the SPI communication

SPI.begin();

Next we set the Clockdivider for SPI communication. Here we have set divider 8.

SPI.setClockDivider(SPI_CLOCK_DIV8);

Then set the SS pin HIGH since we didn’t start any transfer to slave arduino.

digitalWrite(SS,HIGH);

3. In void loop():

We read the status of the pushbutton pin connected to pin2 (Master Arduino) for sending those value to the slave Arduino.

buttonvalue = digitalRead(ipbutton);

Set Logic for Setting x value (To be sent to slave) depending upon input from pin 2

if(buttonvalue == HIGH) { x = 1; } else { x = 0; }

Before sending the value we need to LOW the slave select value to begin transfer to slave from master.

digitalWrite(SS, LOW);

Here comes the important step, in the following statement we send the push button value stored in Mastersend variable to the slave arduino and also receive value from slave that will be store in Mastereceive variable.

Mastereceive=SPI.transfer(Mastersend);

After that depending upon the Mastereceive value we will turn the Master Arduino LED ON or OFF.

Note: We use serial.println() to view the result in Serial Motor of Arduino IDE. Check the Video at the end.

Slave Arduino Programming Explanation

1. First of all we need to include the SPI library for using SPI communication functions.

#include<SPI.h>

2. In void setup()

We Start Serial Communication at Baud Rate 115200.

Serial.begin(115200);

Attach LED to pin 7 and Push button to pin2 and set those pins OUTPUT and INPUT respectively.

pinMode(ipbutton,INPUT); pinMode(LED,OUTPUT);

The important step here is the following statements

pinMode(MISO,OUTPUT);

The above statement sets MISO as OUTPUT (Have to Send data to Master IN). So data is sent via MISO of Slave Arduino.

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

SPCR |= _BV(SPE);

Then turn ON interrupt for SPI communication. If a data is received from master the Interrupt Routine is called and the received value is taken from SPDR (SPI data Register)

SPI.attachInterrupt();

The value from master is taken from SPDR and stored in Slavereceived variable. This takes place in following Interrupt Routine function.

ISR (SPI_STC_vect){ Slavereceived = SPDR; received = true; }

3. Next in void loop () we set the Slave arduino LED to turn ON or OFF depending upon the Slavereceived value.

if (Slavereceived==1) { digitalWrite(LEDpin,HIGH); //Sets pin 7 as HIGH LED ON Serial.println("Slave LED ON"); }else { digitalWrite(LEDpin,LOW); //Sets pin 7 as LOW LED OFF Serial.println("Slave LED OFF"); }

Next we read the status of the Slave Arduino Push button and store the value in Slavesend to send the value to Master Arduino by giving value to SPDR register.

void loop()
{ if(received) //Logic to SET LED ON OR OFF depending upon the value recerived from master
{
if (Slavereceived==1)
{
digitalWrite(LEDpin,HIGH); //Sets pin 7 as HIGH LED ON
Serial.println("Slave LED ON");
}else
{
digitalWrite(LEDpin,LOW); //Sets pin 7 as LOW LED OFF
Serial.println("Slave LED OFF");
}

Comments

Hello, Great tutorial, I am going to mess with this a bit to see if it works for me. Question. I noticed the "Master" code uses pin10 as SS (Slave Select). My understand from this article is so that the slave knows wheter communication is bound for it or not. however in the code for the slave, I don't see the SS utilized. This would make me thing that the slave unit in this example would listen and respond to any and all communication on the SPI without regard to the masters SS. Is this correct? How would you correct this? in my use case I have multiple slave devices on my SPI bus.