An SPI bus usually has one master and several slaves: a flash, a sensor, a display controller. They share the clock and data lines, and the master picks one at a time with its chip select. This article designs an SPI slave, connects two of them to one master, and covers the alternative wiring, the daisy chain.

9 min read | Intermediate

What You'll Learn

  • Design an SPI slave that works in any mode
  • Share MISO between slaves with high-impedance outputs
  • Address several slaves with independent chip selects
  • Understand daisy-chained SPI devices

Sharing the Bus

With independent chip selects, SCLK and MOSI go to every slave, and every slave's MISO connects to the master's MISO. Only the selected slave may drive MISO; every other slave leaves it in high impedance. A slave also ignores SCLK and MOSI while its chip select is high. The cost is one chip select pin per slave.

The Slave

This slave runs on its own system clock and oversamples SCLK through a synchronizer, which is common in FPGAs and in chips whose SPI port is slow compared with their clock. Its protocol is two bytes per transaction: a command byte (bit 7 = 1 for a write, bits 1:0 the register), answered with the slave's ID, and a data byte.


// SPI slave with four 8-bit registers, oversampling SCLK with its own clock.
// A transaction is two bytes with chip select held low:
//   byte 1 from the master: command {rw, 5'b0, addr[1:0]}, rw = 1 for a write
//   byte 1 to the master:   the slave's ID
//   byte 2: write data from the master, or the register value to the master for a read
// MISO is high impedance while the slave is not selected, so several slaves can share it.
module spi_slave #(
  parameter CPOL = 0,
  parameter CPHA = 0,
  parameter ID   = 8'hA5
) (
  input        clk,
  input        rst,
  input        sclk,
  input        mosi,
  output       miso,
  input        cs_n,
  output [7:0] reg0,
  output [7:0] reg1
);
  reg [7:0] regs [0:3];
  reg [2:0] sclk_s;                    // synchronizer plus previous value
  reg [1:0] cs_s;
  reg [1:0] mosi_s;
  reg [2:0] bitc;
  reg       second;                    // receiving the second byte
  reg [7:0] cmd;
  reg [7:0] rx_sh;
  reg [7:0] tx_sh;
  reg       miso_r;
  integer   i;

  assign reg0 = regs[0];
  assign reg1 = regs[1];
  assign miso = cs_s[1] ? 1'bz : miso_r;

  wire rise     = sclk_s[1] && !sclk_s[2];
  wire fall     = !sclk_s[1] && sclk_s[2];
  wire leading  = CPOL ? fall : rise;
  wire trailing = CPOL ? rise : fall;
  wire sample   = CPHA ? trailing : leading;
  wire change   = CPHA ? leading : trailing;
  wire selected = !cs_s[1];
  wire cs_fall  = cs_s[1] && !cs_n;    // chip select is about to become active

  always @(posedge clk) begin
    sclk_s <= {sclk_s[1:0], sclk};
    cs_s   <= {cs_s[0], cs_n};
    mosi_s <= {mosi_s[0], mosi};
  end

  always @(posedge clk) begin
    if (rst) begin
      for (i = 0; i < 4; i = i + 1)
        regs[i] <= 8'h00;
      miso_r <= 1'b0;
    end
    else if (cs_fall) begin
      bitc   <= 3'd0;
      second <= 1'b0;
      if (CPHA == 0) begin
        miso_r <= ID[7];               // the first bit is on MISO before the first edge
        tx_sh  <= {ID[6:0], 1'b0};
      end
      else begin
        tx_sh <= ID;
      end
    end
    else if (selected) begin
      if (sample) begin
        rx_sh <= {rx_sh[6:0], mosi_s[1]};
        bitc  <= bitc + 3'd1;
        if (bitc == 3'd7) begin        // a whole byte has arrived
          if (!second) begin
            cmd    <= {rx_sh[6:0], mosi_s[1]};
            second <= 1'b1;
            tx_sh  <= regs[{rx_sh[0], mosi_s[1]}];   // the reply for a read
          end
          else if (cmd[7]) begin
            regs[cmd[1:0]] <= {rx_sh[6:0], mosi_s[1]};
          end
        end
      end
      if (change) begin
        miso_r <= tx_sh[7];
        tx_sh  <= {tx_sh[6:0], 1'b0};
      end
    end
  end
endmodule

The edge detection is done in the system clock domain: rise and fall compare the synchronized SCLK with its previous value, and CPOL and CPHA turn them into sample and change, the mirror image of the master. On the falling edge of chip select the slave restarts: it loads its ID, and for CPHA = 0 puts the first bit on MISO immediately. When the eighth bit of the command arrives, it loads the reply for the second byte, which for a read is the addressed register.

Quick Check

Q: Why must the slave load its reply as soon as the last bit of the command arrives, rather than at the start of the second byte?

Show Answer

Because the first bit of the reply goes out on the very next change edge, half an SCLK period later. There is no gap between bytes in which the slave could prepare it.

Two Slaves

The testbench decodes one chip select per slave and gives the slaves different IDs. miso is declared as a tri-state net shared by both:


reg  sel = 0;                            // which slave the next transaction is for
wire cs0_n = cs_n || sel != 0;
wire cs1_n = cs_n || sel != 1;
tri  miso;                               // shared: only the selected slave drives it
Output
SPI mode 0 (CPOL=0, CPHA=0)
1535  slave 0: write reg1 = 0x11   (ID 0xa5)
3055  slave 1: write reg1 = 0x22   (ID 0x5a)
4575  slave 0: read  reg1 = 0x11   (ID 0xa5)
6095  slave 1: read  reg1 = 0x22   (ID 0x5a)

Each slave answers with its own ID and keeps its own register value, although both saw every clock on SCLK and MOSI. Their chip selects kept them apart.

Daisy Chains

Some devices, such as LED drivers and shift-register-style DACs, are designed to be chained: the MISO of one feeds the MOSI of the next, all share one chip select, and the MISO of the last returns to the master. The whole chain is one long shift register. To update three 8-bit devices, the master clocks 24 bits with chip select low; the bits for the last device go first. Chip select rising then latches every device's byte at once. Daisy chains save pins but every access touches every device.

Quick Check

Q: In a daisy chain of four 16-bit devices, how many clocks does the master need to update all of them?

Show Answer

64: the chain is one 64-bit shift register, and every device's data must be shifted all the way to its position.

Running It in ChipVerify Lab

The example contains the master, two slaves and the testbench with two chip selects. Change sel and watch MISO switch between the slaves.

Common Mistakes

Mistake #1: A slave that always drives MISO

A slave that drives MISO while not selected fights the selected slave. MISO must be high impedance when CS_n is high.

Mistake #2: Two chip selects active at once

A decode bug that selects two slaves makes both drive MISO, and the master reads garbage.

Mistake #3: A slave that reacts to SCLK while not selected

Traffic to another slave would shift into its register. Every slave must ignore the bus while its chip select is high.

Practice Exercise

Challenge: A Decode Bug

Break the chip select decode so that slave 1 is also selected whenever slave 0 is. Predict what the master reads from slave 0, then run it.

Hint

Two outputs driving opposite values on the same net give X in simulation.

Solution

wire cs1_n = cs_n || (sel != 1 && sel != 0);   // BUG: slave 1 also selected for slave 0
Output
1535  slave 0: write reg1 = 0x11   (ID 0xxx)
3055  slave 1: write reg1 = 0x22   (ID 0x5a)
4575  slave 0: read  reg1 = 0xXX   (ID 0xxx)
6095  slave 1: read  reg1 = 0x22   (ID 0x5a)

While "slave 0" is addressed, both slaves drive MISO with their different IDs and data, and every bit where they disagree becomes X. On a real board the two outputs fight, drawing current, and the master reads whichever wins. Slave 1 also received slave 0's write, which a later read of slave 1 would reveal if the second write had not overwritten it.

Open the ready-made example in the lab and run the simulation.

Summary

  • Slaves share SCLK, MOSI and MISO; each has its own chip select.
  • A slave drives MISO only while selected and ignores the bus otherwise.
  • An oversampling slave detects SCLK edges in its own clock domain and mirrors the master's leading/trailing logic.
  • The reply byte must be ready immediately after the last bit of the command.
  • A daisy chain turns several devices into one long shift register with a shared chip select.
Did you find what you were looking for?

Quiz

No quiz questions available for this article.