SPI — Serial Peripheral Interface Explanation

Fatma Vural
7 min readMay 30, 2024

--

SPI (Serial Peripheral Interface) is a serial communication protocol used in electronic devices. SPI Communications, I2C, and UART are slightly slower than protocols such as USB, Ethernet, Bluetooth, and WiFi, but they are much simpler and use fewer hardware and system resources. SPI, I2C, and UART are ideal for communication between microcontrollers and between microcontrollers and sensors where large amounts of high-speed data do not need to be transferred.

A unique advantage of SPI is that data can be transferred without interruption. Any number of bits can be sent or received in a continuous stream. With I2C and UART, data is sent in packets limited to a certain number of bits. Start and stop conditions define the beginning and end of each packet so that data is not interrupted during transmission. In the SPI protocol, electronic devices communicate with each other by sending data bits through physically connected cables between the devices. The communicating devices are in a master-slave relationship. The master is the controller (usually a microcontroller), while the slave device (usually a sensor, display, or memory chip) receives instructions from the master. The simplest configuration of SPI is a single master, single slave system, although a master can control multiple slaves.

The four-line communication is as follows:

MOSI (Master Output/Slave Input): The line through which the master sends data to the slave. MISO (Master Input/Slave Output): The line through which the slave sends data to the master. SCLK (Clock): Line required for the clock signal. SS/CS (Slave Select/Chip Select): The line where the master selects which slave to send data to.

  • In the SPI protocol, there is only one Master, but the slave can theoretically be unlimited.

One master device can manage multiple slave devices. A separate SS/CS line is used for each slave device, thus determining which device will be active. SPI communication is always initiated by the master because the master configures and generates the clock signal. Any communication protocol in which devices share a clock signal is known as synchronous. SPI is a synchronous communication protocol. The master can choose which slave it wants to talk to by setting the slave’s CS/SS line to a low voltage level. In the idle, non-transmitting state, the slave selection line is maintained at a high voltage level. Multiple CS/SS pins may be available on the master, allowing multiple slaves to be connected in parallel.

SPI MODES

The SPI (Serial Peripheral Interface) protocol can operate in four different modes that determine how the clock signal (SCLK) and data lines (MOSI, MISO) operate. These modes depend on the clock polarity (CPOL) and clock phase (CPHA) settings. CPOL and CPHA control how the clock signal and data are sampled and transmitted. The clock signal in SPI can be changed using the clock polarity and clock phase properties. These two features work together to determine when to extract bits and when to sample them.

CPOL determines whether the clock signal is high or low when it is idle.

  • CPOL = 0: The clock signal is low (0) when idle.
  • CPOL = 1: The clock signal is high (1) when idle.

CPHA determines on which edge of the clock signal (rising or falling) the data will be sampled and manipulated.

CPHA = 0: Data is sampled on the first edge of the clock signal (if the first edge is rising, data is sampled on the rising edge, if it is falling, data is sampled on the falling edge). CPHA = 1: Data is sampled on the second edge of the clock signal (if the first edge is rising, data is sampled on the falling edge, if it is falling, data is sampled on the rising edge).

Combinations of CPOL and CPHA create four different SPI modes:

Mode 0 (CPOL = 0, CPHA = 0): The clock signal is low (0) when idle. Data is sampled on the rising edge (first edge) of the clock signal and changes on the falling edge.

Mode 1 (CPOL = 0, CPHA = 1): The clock signal is low (0) when idle. Data is sampled on the falling edge of the clock signal (second edge) and varies on the rising edge.

Mode 2 (CPOL = 1, CPHA = 0): Clock signal is high (1) at idle. Data is sampled on the falling edge of the clock signal (first edge) and changes on the rising edge.

Mode 3 (CPOL = 1, CPHA = 1): Clock signal is high (1) at idle. Data is sampled on the rising edge (second edge) of the clock signal and changes on the falling edge.

Advantages of SPI Communication Protocol;

In all respects, the asynchronous serial communication protocol has a much faster performance. In communication processes, suddenly has a more powerful connection. It is accepted as a universal protocol. It is very suitable and costly to use.

Disadvantages of the SPI Communication Protocol; It requires more cables than other communication protocols in its use. Master Slave communications must be checked. Slave-Slave communication is impossible Many of the Slaves during its use led to circuit turmoil.

HDL -Verilog Code

  • When the reset signal (rst_n) is asserted to ‘0’, the design transitions to the IDLE state.
  • When the reset signal (rst_n) is de-asserted to ‘1’ and the SS_n signal is ‘1’, the design transitions to the IDLE state.
  • When the reset signal (rst_n) is de-asserted to ‘1’ and the SS_n signal is ‘0’, the design starts operating and transitions to the CHECK MODE state.
  • While in the CHECK MODE state, when the MOSI signal is ‘0’, the design transitions to the WRITE state.
  • While in the CHECK MODE state, when the MOSI signal becomes ‘1’ for the first time, the design transitions to the READ ADDRESS state.
  • After the READ ADDRESS state, a FLAG signal is set to ‘1’, and when the SS_n signal is deasserted, the design transitions to the READ DATA state.
module SPI_Slave (
input clk, // Clock signal
input rst_n, // Reset signal (active low)
input SS_n, // Slave select signal (active low)
input MOSI, // Master out slave in
output reg MISO, // Master in slave out
output reg CS // Check state output
);

// Enumeration: FSM states
typedef enum logic [2:0] {
IDLE_STATE, // There will be 3 states, so a 2-bit reg is used.
CHECK_MODE_STATE,
WRITE_STATE,
READ_ADDRESS_STATE,
READ_DATA_STATE
} state_type;

// FSM state
reg [2:0] state;

// FLAG signal
reg flag;

// Initial state assignment
initial begin
state = IDLE_STATE;
end

// FSM
always @(posedge clk or negedge rst_n) begin
if (~rst_n) begin
// Reset states
state <= IDLE_STATE;
flag <= 0;
MISO <= 0;
CS <= 0;
end else begin
// FSM
case (state)
IDLE_STATE: begin
if (~SS_n) begin
state <= CHECK_MODE_STATE;
end
end
CHECK_MODE_STATE: begin
if (SS_n && MOSI) begin
state <= WRITE_STATE;
end else if (SS_n && !MOSI) begin
state <= READ_ADDRESS_STATE;
end
end
WRITE_STATE: begin
if (~SS_n && !MOSI) begin
state <= CHECK_MODE_STATE;
end
end
READ_ADDRESS_STATE: begin
if (~SS_n) begin
flag <= 1;
state <= READ_DATA_STATE;
end
end
READ_DATA_STATE: begin
if (flag && SS_n) begin
state <= IDLE_STATE;
end
end
default: state <= IDLE_STATE;
endcase
end
end

// Update outputs
always @(posedge clk) begin
case (state)
IDLE_STATE: begin
MISO <= 0;
CS <= 0;
end
CHECK_MODE_STATE: begin
MISO <= 0;
CS <= 1;
end
WRITE_STATE: begin
MISO <= 0;
CS <= 1;
end
READ_ADDRESS_STATE: begin
MISO <= 0;
CS <= 1;
end
READ_DATA_STATE: begin
MISO <= 1;
CS <= 1;
end
default: begin
MISO <= 0;
CS <= 0;
end
endcase
end

endmodule

TestBench

`include "SPI_Slave.sv" /

module testbench;

// Clock signal
logic clk;
// Reset signal
logic rst_n;
// Slave select signal
logic SS_n;
// Master out slave in signal
logic MOSI;
// Master in slave out signal
logic MISO;
// Check state output
logic CS;

// Instantiation of SPI Slave module
SPI_Slave dut (
.clk(clk),
.rst_n(rst_n),
.SS_n(SS_n),
.MOSI(MOSI),
.MISO(MISO),
.CS(CS)
);

// Clock signal generation task
task clk_gen();
forever begin
#5 clk = ~clk;
end
endtask

// Reset signal generation task
task reset_gen();
rst_n = 0;
#10;
rst_n = 1;
#10;
endtask

// Test scenario task
task test_scenario();
// initial state: IDLE_STATE
SS_n = 1;
MOSI = 0;
// Reset status is not enabled at startup because there is no RST_n signal
#100;
// Switching scenario to CHECK_MODE_STATE
SS_n = 0;
MOSI = 0;
#10;
// Scenario to switch to WRITE_STATE
SS_n = 1;
MOSI = 1;
#10;
// Scenario to switch to READ_ADDRESS_STATE
SS_n = 0;
MOSI = 1;
#10;
// Scenario to switch to READ_DATA_STATE
SS_n = 1;
MOSI = 1;
#10;
// Scenario to return to IDLE_STATE again
SS_n = 1;
MOSI = 0;
#10;
endtask

// Test scenario and running clock/generators
initial begin
$dumpfile("testbench.vcd");
$dumpvars(0, testbench);
clk = 0;
// Initialize clock and reset generators
fork
clk_gen();
reset_gen();
test_scenario();
join_any;
end

endmodule

References

--

--

Fatma Vural

I’m a analog person in digital world also part - time engineer.. ✨