Deep Dive7 min read
What Is SPI Communication in Simple Terms
SPI is a fast communication protocol that uses four wires to connect microcontrollers to sensors, displays, and memory cards. Learn how it works and when to use it.

SPI, or Serial Peripheral Interface, is one of the fastest communication protocols you will use in your microcontroller projects. It connects your main controller to devices like SD card readers, TFT displays, and wireless transceivers. In my projects, whenever I need to transfer large files or stream video data quickly, SPI is always my first choice.
It is a synchronous, full-duplex protocol, which means data can flow in both directions at the exact same time. The protocol works on a Controller-Peripheral model (historically called Master-Slave), where a single main controller coordinates communication with one or more connected peripheral devices.
The Four Wires of SPI
To establish an SPI connection, you need four dedicated physical wires. While I2C only needs two, SPI's extra wires are the secret behind its high speed. Here is what each wire does:
- MOSI (Master Out Slave In): The data line carrying signals from the controller to the peripheral device.
- MISO (Master In Slave Out): The data line carrying signals from the peripheral device back to the controller.
- SCK (Serial Clock): The clock pulse generated by the controller that keeps both devices perfectly in sync.
- SS / CS (Slave Select / Chip Select): The line used to enable a specific peripheral device. The controller pulls this pin LOW to select it.
While the clock, MOSI, and MISO lines can be shared among multiple peripheral devices in a daisy-chain or bus configuration, each individual device needs its own unique Chip Select (SS) line. When the controller wants to talk to a device, it pulls that specific device's SS line LOW while keeping the others HIGH.
| SPI Wire Name | Direction | Primary Purpose |
|---|---|---|
| MOSI / COPI | Controller to Peripheral | Carries data packets to the peripheral. |
| MISO / CIPO | Peripheral to Controller | Carries response packets back to the controller. |
| SCK | Controller to Peripheral | Synchronizes the transmission timing. |
| SS / CS | Controller to Peripheral | Selects which device is currently active. |
SPI vs I2C: Which Should You Choose?
A question I get asked a lot is whether to use SPI or I2C. The main difference lies in speed versus wiring simplicity. SPI is much faster because it has dedicated data lines for both directions and doesn't waste clock cycles sending address bytes. However, adding more SPI devices requires adding more Chip Select pins, which can quickly run your board out of digital pins.
I2C uses only two wires no matter how many devices you connect, as each device has a unique address built into its software. In my experience, I2C is great for slow sensors (like temperature or barometric pressure sensors), while SPI is necessary for high-bandwidth modules like displays or storage cards.
| Feature | SPI Communication | I2C Communication |
|---|---|---|
| Wiring Pins Required | 4 pins + 1 extra pin per device | Always 2 pins total |
| Data Flow Mode | Full-Duplex (Both directions) | Half-Duplex (One direction at a time) |
| Speed Capacity | Very High (Up to 80+ MHz) | Standard (100 kHz - 3.4 MHz) |
| Device Addressing | Hardware-based (via CS pin selection) | Software-based (via address byte) |
How to Write SPI Code in Arduino
To communicate with an SPI device in Arduino, we use the built-in SPI library. This library handles all the clock transitions and bit shifting automatically behind the scenes. Here is a simple code snippet showing how to send data to an SPI peripheral register:
C++ Source
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <SPI.h>
const int chipSelectPin = 10; // Connect to the CS pin on your peripheral
void setup() {
// Initialize the chip select pin as an output
pinMode(chipSelectPin, OUTPUT);
// Keep the device deselected initially by pulling CS HIGH
digitalWrite(chipSelectPin, HIGH);
// Turn on the SPI bus
SPI.begin();
}
void writeToDevice(byte address, byte dataValue) {
// Select the peripheral device (pull CS LOW)
digitalWrite(chipSelectPin, LOW);
// Send the target register address
SPI.transfer(address);
// Send the data byte to write into that register
SPI.transfer(dataValue);
// Deselect the peripheral device (pull CS HIGH)
digitalWrite(chipSelectPin, HIGH);
}
void loop() {
// Write the value 0xFF to register 0x01 every second
writeToDevice(0x01, 0xFF);
delay(1000);
}In this code, we pull the
chipSelectPin LOW before sending any bytes. This tells the target peripheral to prepare for incoming data. The SPI.transfer() function shifts out one byte on the MOSI line while simultaneously shifting in one byte on the MISO line. Once the transfer completes, we pull the chip select pin back HIGH to return the device to idle mode.Categories for this post
Tags
#spi #communication #beginner #arduino
About The Author
Muhammad Ichsanul FadhilI am a 21-year-old IoT enthusiast who loves microcontrollers and exploring new components. I built IoTSimulator to help beginners learn without needing a pile of hardware.
Related Articles
Continue reading


