The site for those who love tinkering with Arduino, Raspberry Pi & Co.

Arduino SPI, serial communication between components

by

Arduino SPI: in this tutorial we will learn what the SPI standard is and we will learn how to use it with our Arduino board.

Serial Peripheral Interface

The Serial Peripheral Interface (SPI) standard is a synchronous, full duplex communication bus with master / slave architecture, originally developed by Motorola.

Arduino SPI - Basic Connection
Basic connections of the SPI protocol

It is based on small registers, generally of 8 bits, positioned one on the Master device and one for each slave device.

Communication occurs through the "shift" of the bits of these registers and a link that we will see later allows you to see these 2 registers as if they were contiguous to each other.

We can therefore see the aforementioned registers as a single 16-bit register, where the last bit is connected with the first.

The master can read and write data only in the first 8 bits of the register, the slave can only do it in the last 8.

Thanks to a line reserved for the clock signal that synchronizes the communication, the shift can take place between the 2 registers.

Hardware interface

SPI (Serial Peripheral interface) has a hardware interface consisting of 4 main pins:

  • SCLK (Searial CLocK): This channel passes the clock signal generated by the card and is used for the synchronization of the channels used for the exchange of messages
  • MISO (Master Input Slave Output): Used to make the first bit of the Master register contiguous to the last bit of the slave register
  • MOSI (Master Output Slave Input): Used to make the last bit of the Master register contiguous to the first bit of the slave register
  • SS (Slave Select): This pin is used to select the desired slave

Arduino SPI Connection

SPI allows 2 architectural modes for connecting multiple slaves to the same master.

The first mode is by using more slave select pins (SS), in the second way, on the other hand, called daisy chain, the slave select pin is shared and the slaves are connected together forming a chain:

Connection with multiple select slaves

Arduino SPI - Parallel connection
Connection with multiple Slave Select

In this type of connection it can be seen that the SCLK, MISO and MOSI channels are shared, but the SS channels are one for each slave.

This mode allows you to select a single slave and communicate only with it.

The advantage is that this method has a high data rate.

The limit of this connection is given by the number of pins that our controller can dedicate for the selection of the slaves.

Daisy chain

Arduino SPI - Daisy Chain Connection
Daisy Chain connection diagram

The "daisy chain" method has the particularity that all the slaves are connected one after the other, forming a chain.

As shown in the image, the MISO channel of the first slave is connected to the MOSI channel of the next slave and so on for all the slaves with the exception of the MISO of the last slave which is connected with the MISO of the master.

Unlike the previous mode, here we have to communicate with all slaves simultaneously.

This mode has a lower data transfer rate than the previous one.

The SPI functions of Arduino

SPI is easily usable on Arduino thanks to the SPI.h library that can be easily imported from the Arduino IDE. The main functions of the library are described below:

  • SPISetting (speed, dataOrder, dataMode): Connection settings. These settings may vary from device to device and we can find them in the datasheets of the components with which we must communicate;
  • SPI.beginTransaction (settings): the connection is activated with the previously declared settings;
  • SPI.transfer (val): transfers the value inserted in brackets and returns the value present in the device with which we are communicating.
  • SPI.endTransaction (): puts the end of the previously opened connection.

Once you have made the connections, as shown in the figure (see figure of the connection to multiple slaves), between your card and your sensor that supports SPI or between your card and another card you can try to execute the code presented below .

#include <SPI.h>

// Pin slave select
#define SLAVE_PIN 20

uint8_t val1, val2;
char values[] = "hello";

/ * Set the speed, bit order, and mode.
 * Bit order indicates in which order the bits should be shifted
 * (each device shifta them differently, so we recommend
 * check datasheets to see which bit is shifted first):
 *    
 * MSBFIRST = Most significant bits are shifted before those
 * less significant
 * LSBFIRST = The reverse of the above.
 *  
 * Mode: Not all devices use the same mode. The mode
 * it can be found on the datasheet of the device you will use
 * | ------------------------------------------------ --------------- |
 * | MODE | CPOL | CPHA | Output Edge | Data Capture |
 * | ------------------------------------------------ --------------- |
 * | SPI_MODE0 | 0 | 0 | Falling | Rising |
 * | ------------------------------------------------ --------------- |
 * | SPI_MODE1 | 0 | 1 | Rising | Falling |
 * | ------------------------------------------------ --------------- |
 * | SPI_MODE2 | 1 | 0 | Rising | Falling |
 * | ------------------------------------------------ --------------- |
 * | SPI_MODE3 | 1 | 1 | Falling | Rising |
 * | ------------------------------------------------ --------------- |
 *  
* /
SPISettings settings (2000000, MSBFIRST, SPI_MODE1); 

void setup () {
  pinMode (SLAVE_PIN, OUTPUT);
  // SPI initialization:
  SPI.begin (); 
  Serial.begin (9600);
}
void loop () {
  / * >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PART 1 <<<<<<<<< <<<<<<<<<<<<<<<<<<<<<<<<<<<<< * /
  
  / * The first part of the code reads 2 bytes. If you use this
   * standard for communicating with sensors, generally the values are there 
   * assume in this way.
  * /
  SPI.beginTransaction (settings);
  / * When the SS pin is low, it means that the slave has been selected
  * /
  digitalWrite (SLAVE_PIN, LOW);
  / * Since it's read only, we don't care what value 
   * pass to the slave here we put 0
  * /
  val1 = SPI.transfer (0);
  val2 = SPI.transfer (0);
  digitalWrite (SLAVE_PIN, HIGH);
  SPI.endTransaction ();
  
  Serial.println ("Value 1 =" + val1);
  Serial.println ("Value 2 =" + val2);

/ * >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PART 2 <<<<<<<<< <<<<<<<<<<<<<<<<<<<<<<<<<<<<< * /

  / * Transmission: Since this standard allows communication too
   * between 2 devices such as and example 2 Arduino, then below I put an example
   * transmission of data that you want to send to the other card. Note that
   * the function used is the same as for reading, as the actions performed in
   * reading are the same as writing.
  * /
  SPI.beginTransaction (settings);
  digitalWrite (SLAVE_PIN, LOW);
  / * Write string values
  * /
  for (int i = 0; i <sizeof (values) / sizeof (char); i ++) {
    SPI.transfer (value[i]s);
  }
  digitalWrite (SLAVE_PIN, HIGH);
  SPI.endTransaction ();
}

As you can see, the code is divided into 2 parts: one relating to data reading (mainly used for reading values from sensors), the second relating to data transmission.

In the code there are step-by-step comments explaining what the related functions do.

I would like to further reiterate that the values of the communication speed, the first bit to be transmitted and the transmission mode vary from device to device and you can find this information in the datasheets of the relevant devices.

Finally, if you encounter any problems or doubts, do not hesitate to write a comment!

SPI library reference W
ikipedia: SPI E
xplanation of how SPI works at the physical level


Various SPI Peripherals to try

Ti è rimasta una domanda o un dubbio?

Iscriviti e chiedi nella community

Leave a Reply

Your email address will not be published. Required fields are marked *