Skip to content
VLSI Mentor

SPI · Module 1

Bus Topologies and Daisy-Chain

What the four-wire model costs as devices are added: shared clock and data with one select per device, or a daisy chain that turns several peripherals into one long shift ring. Pin arithmetic, ownership consequences, and why chaining is a device property.

Every chapter so far has quietly assumed one master and one slave. Chapter 1.2 named the exception — a shared MISO net needs an ownership rule — but stopped there, and Chapter 1.3 built its ring between exactly two registers.

Real boards rarely look like that. A controller typically reaches a boot flash, a converter and a sensor or two, and the question this chapter answers is what that costs: which wires can be shared, which cannot, how the count grows, and what changes about the mental model when several devices sit on the same nets.

There are two standard answers, and the second one is stranger and less universal than it is usually presented. The independent-select topology keeps the ring of Chapter 1.3 between the master and whichever device is selected. The daisy chain does something genuinely different: it extends the ring through several devices, so they become one long shift register.

1. The Starting Point: One Master, One Slave

Restate the baseline precisely, because the multi-device cases are defined as departures from it.

Four signals. The master drives SCLK, MOSI and CS; the selected slave drives MISO. Each wire has exactly one driver. The shift ring runs master → MOSI → slave → MISO → master, and after a word's worth of bit times the two registers have exchanged contents.

Nothing here scales badly except the select line, and that turns out to be the whole story.

2. Independent Selects — Sharing What Can Be Shared

Add a second device. Go signal by signal and ask what changes.

SCLK can be shared. The master is the only driver, and an unselected device receiving clock edges it must ignore costs nothing — provided it genuinely ignores them, which is what selection is for. Every device sees every edge.

MOSI can be shared. Again one driver, the master, and unselected devices simply do not act on what they receive.

MISO can be shared — but only because of the ownership rule. Every device connected to the net has an output stage on it. Sharing works only if exactly one enables that stage at a time, which is precisely the rule Chapter 1.2 established: a slave drives MISO only while selected, and releases it to high impedance otherwise.

CS cannot be shared. Its entire job is to distinguish one device from the others. Two devices on one select line are, by definition, one device as far as the bus is concerned.

So N peripherals cost three shared signals plus N select lines. The shared three are paid once; each additional device costs one pin on the master and one trace.

An SPI master connected to three peripherals in the independent select topology. SCLK and MOSI fan out from the master to all three devices. A shared MISO net returns to the master. Each device has its own dedicated chip select line driven by the master, and only the selected device enables its MISO output.Masterdrives SCLK, MOSI, all CSSCLK + MOSIshared — one driver, manylistenersMISO netshared — one driver at atimeFlashCS0ADCCS1 — selected, drives MISOSensorCS2 — released, high-Zdrivesto all devicesdriveshigh-Zsamples12
Figure 1 — independent-select topology. Clock and both data lines are shared; each device has its own select. Exactly one device has its MISO output enabled at any moment, which is what makes the shared return line work.

Two properties of this topology are worth stating, because the daisy chain reverses both.

Each transaction involves exactly one device. The ring of Chapter 1.3 is between the master and the selected slave; every other device is electrically present and logically absent. A transfer's length, framing and meaning are entirely that device's contract.

Addressing is physical and immediate. Selecting a different device is asserting a different pin — no addressing bytes, no bus turnaround, no ordering constraint between devices.

3. Where the Pin Cost Actually Bites

The arithmetic is simple; the engineering judgement is about when it stops being acceptable.

At two or three devices, three shared signals plus a handful of selects is unremarkable, and the simplicity is worth far more than the pins. At a dozen, the master is spending a dozen pins on selection alone, plus the routing to reach each device — and on a pin-constrained part that is the point where designers start reaching for alternatives.

The alternatives split into three families, and it is worth knowing they exist even though none is this chapter's subject.

Decode the selects. Drive an external decoder from a few master pins so k pins select up to 2^k devices. This trades pins for a component and for the decoder's timing behaviour — and introduces a real hazard, because a decoder's outputs glitch while its inputs change, which can momentarily select the wrong device. §7 returns to this.

Use a bus with in-band addressing. If device count is the dominant pressure, an interface that transmits an address instead of asserting a wire scales differently by design. That is the trade Chapter 1.1 framed, and Why I²C Exists develops from the other side.

Chain the devices. Keep one select and one clock, and pass data through each device in turn. That is the next section, and it is the one that changes the mental model.

4. Daisy Chain — One Long Shift Register

The daisy chain starts from an observation about Chapter 1.3: a shift register has a serial input and a serial output, and there is no reason the thing on the other end of that output has to be the master.

Wire the master's MOSI to the first device's serial input. Wire that device's serial output to the second device's serial input. Continue, and bring the last device's serial output back to the master's MISO. Share SCLK, and tie every device's select together so they all participate at once.

The result is not several rings. It is one ring, passing through every device — the master's register, then each device's register in series, then back to the master.

An SPI master connected to three peripherals in a daisy chain. MOSI enters the first device. Each device's serial output feeds the next device's serial input along the top row. The third device's serial output returns along a lower path back to the master's MISO input, closing the ring. A single shared select and clock reach all three devices.Masterone CS, one SCLKDevice 18-bit registerDevice 28-bit registerDevice 38-bit registerReturn pathlast device back tothe masterMOSIserial outMISO12
Figure 2 — daisy chain. One select and one clock reach every device, and data passes through each register in turn. Three 8-bit devices form a single 24-bit shift ring, so the master must clock the whole chain to reach any one of them.

Everything that feels strange about daisy-chained SPI follows from that single sentence.

The chain length sets the transfer length. Three devices with 8-bit registers form a 24-bit ring. To load a value into the first device, the master must clock 24 bits — the value plus 16 more to push it through — because the devices in front of it are part of the path.

Data arrives in reverse order of position. The word the master sends first ends up furthest along the chain. Composing a chain update means assembling the whole frame in the right order, which is a driver responsibility and a classic source of off-by-one-device bugs.

Reading is the same operation. Clocking 24 bits both loads new contents and returns the chain's previous contents, because it is still the exchange of Chapter 1.4 — just with a longer ring. There is no separate read.

Everything happens at once or not at all. One select means the master cannot address one device. Updating any device means clocking a frame that passes through all of them, so every device sees a new value every time.

5. Choosing Between Them

State the trade rather than a winner.

Independent selects cost one pin per device and give you direct, immediate, per-device addressing with short transactions. Each device's transaction is its own contract and devices can be completely different parts. This is the default, and the right answer for the overwhelming majority of boards — a flash, a converter and a sensor have nothing in common and gain nothing from being chained.

Daisy chain costs one pin regardless of device count and gives you a single atomic update across the whole chain — which for something like a bank of DACs driven in lockstep is not a workaround but exactly the desired semantics. It costs transfer length proportional to the chain, forces every device to be updated together, requires driver-side frame assembly, and is available only on devices that document it.

The deciding question is usually not pin count but whether the devices are alike and updated together. Many identical channels wanting simultaneous update is the daisy chain's natural home. A handful of unrelated peripherals is not, however tempting the pin saving looks.

6. Ownership Across a Multi-Device Bus

Return to Chapter 1.2's rule and apply it to each topology, because the answers differ.

In the independent-select topology, MISO is a shared net with several potential drivers, and correctness depends on exactly one enabling its output at a time. The master's obligation is that at most one select is asserted; each device's obligation is that it drives MISO only when its own select is asserted. Both are required — a master that asserts two selects breaks the bus even if every device is well behaved, and a device that drives while unselected breaks it even if the master is perfect.

In the daisy chain, there is no shared return net at all. Each inter-device link is point-to-point with exactly one driver, and the shared select means selection is not doing ownership work. The contention class of failure simply does not exist here — which is a genuine and underappreciated advantage. What replaces it is a different failure class: a chain whose frame length or ordering is wrong quietly writes the right data into the wrong device, with no electrical symptom whatsoever.

That contrast is worth holding: independent selects can fail electrically; daisy chains fail semantically. The first shows up on a scope, the second only in behaviour.

7. Making Selection Exclusive — a Small Decoder, Three Ways

Multi-device selection is where a small piece of RTL earns its place. The master must produce N active-low selects with the invariant that at most one is ever asserted, and it must not glitch while changing which.

Architecture

A registered one-hot decoder. An index and an enable go in; N active-low select lines come out. The outputs are registered rather than combinational, which is the whole point: a combinational decoder's outputs pass through transient states while its index inputs change, which on a real bus means momentarily selecting a device that was not intended. Registering the outputs means they change once, together, on a clock edge.

State. One N-bit register holding the active-low select vector, reset to all-inactive.

Combinational logic. A shift-and-invert that builds the next one-hot pattern from the index and the enable. With enable low the next value is all ones — nothing selected.

Clocking and reset. Rising edge of the system clock, asynchronous active-low reset to the all-deselected state. Reset deselecting everything is the safe direction: an unknown or asserted select at power-up could let a device drive the shared MISO net before the master has decided anything.

Ownership. All outputs, unconditionally driven — these are master-side signals, exactly as Chapter 1.2 described.

Timing assumption. That index and enable are stable at the clock edge. Nothing here knows about SCLK or about the CS-to-SCLK setup the device requires — Module 2 covers that timing and Module 13 integrates it with the transfer FSM.

Limitation. This is the selection fragment only. A real master must also assert the select before the first clock edge, hold it after the last, honour the minimum deselect time between transactions, and sequence all of that with the transfer state machine. That is Module 13's work.

Azvya Education Pvt. Ltd.VLSI Mentor
spi_cs_decode.sv — registered one-hot active-low selects; at most one asserted, by construction
   module spi_cs_decode #(
       parameter int N_SLAVES = 4,
       parameter int IDX_W    = 2            // must satisfy 2**IDX_W >= N_SLAVES
   ) (
       input  logic                clk,
       input  logic                rst_n,     // asynchronous, active-low
       input  logic                enable,    // 0 = deselect everything
       input  logic [IDX_W-1:0]    index,     // which slave to select
       output logic [N_SLAVES-1:0] cs_n       // active-low, registered
   );
       logic [N_SLAVES-1:0] next_cs_n;

       always_comb begin
           // Default: nothing selected. An out-of-range index therefore
           // deselects rather than wrapping onto an innocent device.
           next_cs_n = '1;
           if (enable && (index < N_SLAVES))
               next_cs_n[index] = 1'b0;       // exactly one bit driven low
       end

       always_ff @(posedge clk or negedge rst_n) begin
           if (!rst_n) cs_n <= '1;            // reset deselects everything
           else        cs_n <= next_cs_n;     // outputs change once, together
       end
   endmodule

The invariant the module exists to guarantee is exactly the one worth asserting, and the assertion is one line:

Azvya Education Pvt. Ltd.VLSI Mentor
spi_cs_onehot.sva — at most one select asserted, ever
   // $onehot0 is true for a vector with zero or one bits set. cs_n is
   // active-low, so invert it: at most one slave may be selected.
   a_cs_onehot0 : assert property (
       @(posedge clk) disable iff (!rst_n) $onehot0(~cs_n)
   ) else $error("more than one chip select asserted: cs_n=%b", cs_n);

Be precise about what it proves. It proves no two devices are ever selected simultaneously, which is the condition under which a shared MISO net has at most one legitimate driver. It does not prove the right device was selected — that needs a reference model holding the transaction's intent — and it does not prove that the selected device actually released or enabled its output correctly, because that is the device's obligation and lives on the other side of the pin. Checking that requires observing MISO itself, which is Module 16.

Azvya Education Pvt. Ltd.VLSI Mentor
spi_cs_decode.v — the same registered one-hot decoder in Verilog-2001
   module spi_cs_decode #(
       parameter N_SLAVES = 4,
       parameter IDX_W    = 2                 // must satisfy 2**IDX_W >= N_SLAVES
   ) (
       input                     clk,
       input                     rst_n,
       input                     enable,
       input  [IDX_W-1:0]        index,
       output reg [N_SLAVES-1:0] cs_n
   );
       reg [N_SLAVES-1:0] next_cs_n;

       always @(*) begin
           next_cs_n = {N_SLAVES{1'b1}};      // default: nothing selected
           if (enable && (index < N_SLAVES))
               next_cs_n[index] = 1'b0;
       end

       always @(posedge clk or negedge rst_n) begin
           if (!rst_n) cs_n <= {N_SLAVES{1'b1}};
           else        cs_n <= next_cs_n;
       end
   endmodule
Azvya Education Pvt. Ltd.VLSI Mentor
spi_cs_decode.vhd — the same registered one-hot decoder in VHDL
   library ieee;
   use ieee.std_logic_1164.all;
   use ieee.numeric_std.all;                  -- to_integer / unsigned

   entity spi_cs_decode is
       generic (
           N_SLAVES : positive := 4;
           IDX_W    : positive := 2           -- must satisfy 2**IDX_W >= N_SLAVES
       );
       port (
           clk    : in  std_logic;
           rst_n  : in  std_logic;            -- asynchronous, active-low
           enable : in  std_logic;
           index  : in  std_logic_vector(IDX_W-1 downto 0);
           cs_n   : out std_logic_vector(N_SLAVES-1 downto 0)
       );
   end entity spi_cs_decode;

   architecture rtl of spi_cs_decode is
       signal next_cs_n : std_logic_vector(N_SLAVES-1 downto 0);
       signal cs_n_q    : std_logic_vector(N_SLAVES-1 downto 0);
   begin
       decode_proc : process (enable, index)
           variable idx : natural;
       begin
           next_cs_n <= (others => '1');      -- default: nothing selected
           idx := to_integer(unsigned(index));
           if enable = '1' and idx < N_SLAVES then
               next_cs_n(idx) <= '0';
           end if;
       end process decode_proc;

       reg_proc : process (clk, rst_n)
       begin
           if rst_n = '0' then
               cs_n_q <= (others => '1');     -- reset deselects everything
           elsif rising_edge(clk) then
               cs_n_q <= next_cs_n;
           end if;
       end process reg_proc;

       cs_n <= cs_n_q;
   end architecture rtl;

The testbench proves the invariant, not just the happy path

A decoder testbench that only checks "index 2 selects device 2" misses the bug that matters. This one sweeps every index including an out-of-range one, checks one-hot-or-none on every cycle, and confirms that disabling deselects everything.

Azvya Education Pvt. Ltd.VLSI Mentor
spi_cs_decode_tb.sv — sweeps every index, asserts one-hot-or-none on every cycle
   module spi_cs_decode_tb;
       localparam int N_SLAVES = 4;
       localparam int IDX_W    = 3;           // deliberately wide: lets us drive 4..7

       logic clk = 1'b0, rst_n, enable;
       logic [IDX_W-1:0]    index;
       logic [N_SLAVES-1:0] cs_n;
       int   errors = 0;

       spi_cs_decode #(.N_SLAVES(N_SLAVES), .IDX_W(IDX_W)) dut (
           .clk(clk), .rst_n(rst_n), .enable(enable), .index(index), .cs_n(cs_n));

       always #5 clk = ~clk;

       // The invariant, checked continuously rather than only where we look.
       always @(posedge clk) if (rst_n && !$onehot0(~cs_n)) begin
           $error("multiple selects asserted: cs_n=%b", cs_n); errors++;
       end

       initial begin
           rst_n = 1'b0; enable = 1'b0; index = '0;
           @(posedge clk); #1;
           if (cs_n !== '1) begin $error("reset must deselect all, got %b", cs_n); errors++; end
           rst_n = 1'b1;

           // Every legal index selects exactly its own device.
           for (int i = 0; i < N_SLAVES; i++) begin
               enable = 1'b1; index = i[IDX_W-1:0];
               @(posedge clk); #1;
               if (cs_n[i] !== 1'b0) begin
                   $error("index %0d did not select slave %0d (cs_n=%b)", i, i, cs_n); errors++;
               end
           end

           // Boundary: an out-of-range index must deselect, not wrap.
           enable = 1'b1; index = 3'd6;
           @(posedge clk); #1;
           if (cs_n !== '1) begin
               $error("out-of-range index selected something: cs_n=%b", cs_n); errors++;
           end

           // Disable deselects everything regardless of index.
           enable = 1'b0; index = 3'd2;
           @(posedge clk); #1;
           if (cs_n !== '1) begin
               $error("enable low must deselect all, got %b", cs_n); errors++;
           end

           if (errors == 0) $display("PASS: one-hot-or-none held for every index, incl. out-of-range");
           else             $display("FAIL: %0d errors", errors);
           $finish;
       end
   endmodule
Azvya Education Pvt. Ltd.VLSI Mentor
spi_cs_decode_tb.v — the same sweep in Verilog-2001, with an explicit one-hot count
   module spi_cs_decode_tb;
       parameter N_SLAVES = 4;
       parameter IDX_W    = 3;

       reg clk = 1'b0;
       reg rst_n, enable;
       reg  [IDX_W-1:0]    index;
       wire [N_SLAVES-1:0] cs_n;
       integer i, j, asserted, errors;

       spi_cs_decode #(.N_SLAVES(N_SLAVES), .IDX_W(IDX_W)) dut (
           .clk(clk), .rst_n(rst_n), .enable(enable), .index(index), .cs_n(cs_n));

       always #5 clk = ~clk;

       // $onehot0 is SystemVerilog; in Verilog-2001 count the asserted bits.
       always @(posedge clk) if (rst_n) begin
           asserted = 0;
           for (j = 0; j < N_SLAVES; j = j + 1)
               if (cs_n[j] === 1'b0) asserted = asserted + 1;
           if (asserted > 1) begin
               $display("ERROR multiple selects asserted: cs_n=%b", cs_n);
               errors = errors + 1;
           end
       end

       initial begin
           errors = 0;
           rst_n = 1'b0; enable = 1'b0; index = 0;
           @(posedge clk); #1;
           if (cs_n !== {N_SLAVES{1'b1}}) begin
               $display("ERROR reset must deselect all, got %b", cs_n); errors = errors + 1;
           end
           rst_n = 1'b1;

           for (i = 0; i < N_SLAVES; i = i + 1) begin
               enable = 1'b1; index = i[IDX_W-1:0];
               @(posedge clk); #1;
               if (cs_n[i] !== 1'b0) begin
                   $display("ERROR index %0d did not select slave %0d (cs_n=%b)", i, i, cs_n);
                   errors = errors + 1;
               end
           end

           enable = 1'b1; index = 3'd6;
           @(posedge clk); #1;
           if (cs_n !== {N_SLAVES{1'b1}}) begin
               $display("ERROR out-of-range index selected something: cs_n=%b", cs_n);
               errors = errors + 1;
           end

           enable = 1'b0; index = 3'd2;
           @(posedge clk); #1;
           if (cs_n !== {N_SLAVES{1'b1}}) begin
               $display("ERROR enable low must deselect all, got %b", cs_n);
               errors = errors + 1;
           end

           if (errors == 0) $display("PASS: one-hot-or-none held for every index, incl. out-of-range");
           else             $display("FAIL: %0d errors", errors);
           $finish;
       end
   endmodule
Azvya Education Pvt. Ltd.VLSI Mentor
spi_cs_decode_tb.vhd — the same sweep in VHDL, counting asserted selects each cycle
   library ieee;
   use ieee.std_logic_1164.all;
   use ieee.numeric_std.all;

   entity spi_cs_decode_tb is
   end entity spi_cs_decode_tb;

   architecture sim of spi_cs_decode_tb is
       constant N_SLAVES : positive := 4;
       constant IDX_W    : positive := 3;
       constant TP       : time     := 10 ns;

       signal clk    : std_logic := '0';
       signal rst_n  : std_logic := '0';
       signal enable : std_logic := '0';
       signal index  : std_logic_vector(IDX_W-1 downto 0) := (others => '0');
       signal cs_n   : std_logic_vector(N_SLAVES-1 downto 0);
       signal done   : boolean := false;
       signal errors : natural := 0;

       constant ALL_HIGH : std_logic_vector(N_SLAVES-1 downto 0) := (others => '1');
   begin
       clk <= not clk after TP/2 when not done else '0';

       dut : entity work.spi_cs_decode
           generic map (N_SLAVES => N_SLAVES, IDX_W => IDX_W)
           port map (clk => clk, rst_n => rst_n, enable => enable,
                     index => index, cs_n => cs_n);

       -- The invariant, checked on every clock edge.
       check_onehot : process (clk)
           variable asserted : natural;
       begin
           if rising_edge(clk) and rst_n = '1' then
               asserted := 0;
               for j in 0 to N_SLAVES-1 loop
                   if cs_n(j) = '0' then
                       asserted := asserted + 1;
                   end if;
               end loop;
               if asserted > 1 then
                   report "multiple selects asserted" severity error;
                   errors <= errors + 1;
               end if;
           end if;
       end process check_onehot;

       stim : process
           variable errs : natural := 0;
       begin
           wait until rising_edge(clk); wait for 1 ns;
           if cs_n /= ALL_HIGH then
               report "reset must deselect all" severity error; errs := errs + 1;
           end if;
           rst_n <= '1';

           for i in 0 to N_SLAVES-1 loop
               enable <= '1';
               index  <= std_logic_vector(to_unsigned(i, IDX_W));
               wait until rising_edge(clk); wait for 1 ns;
               if cs_n(i) /= '0' then
                   report "index did not select its slave" severity error; errs := errs + 1;
               end if;
           end loop;

           -- Boundary: out-of-range index must deselect, not wrap.
           enable <= '1';
           index  <= std_logic_vector(to_unsigned(6, IDX_W));
           wait until rising_edge(clk); wait for 1 ns;
           if cs_n /= ALL_HIGH then
               report "out-of-range index selected something" severity error; errs := errs + 1;
           end if;

           -- Disable deselects everything.
           enable <= '0';
           index  <= std_logic_vector(to_unsigned(2, IDX_W));
           wait until rising_edge(clk); wait for 1 ns;
           if cs_n /= ALL_HIGH then
               report "enable low must deselect all" severity error; errs := errs + 1;
           end if;

           if errs = 0 then
               report "PASS: one-hot-or-none held for every index" severity note;
           else
               report "FAIL" severity error;
           end if;

           done <= true;
           wait;
       end process stim;
   end architecture sim;

What the three versions agree on, and where they differ

All three infer the same hardware: a combinational one-hot encode with an all-deselected default, followed by an N_SLAVES-wide register with an asynchronous active-low reset to all-deselected. The meaningful language differences are in the testbenches rather than the design. SystemVerilog has $onehot0 as a built-in, so the invariant is one expression; Verilog-2001 and VHDL both count asserted bits in a loop to express the same property. VHDL additionally needs numeric_std and an explicit to_integer(unsigned(...)) conversion, because std_logic_vector carries no numeric interpretation of its own — a strictness that catches real bugs elsewhere and costs a line here.

One design note common to all three: the out-of-range guard. Without index < N_SLAVES, an index outside the range either wraps or writes outside the vector, and the failure would be selecting an innocent device. Defaulting to deselected and guarding the index makes the illegal case safe rather than merely undefined.

8. Failure Modes, by Topology

The two topologies fail differently, and knowing which family you are in narrows a diagnosis quickly.

Independent selects

Two selects asserted at once. Two devices enable their MISO outputs onto one net. The sampled data is whatever the contending drivers produce, the symptom is data-dependent, and it may look correct whenever the two devices happen to agree — the mechanism Chapter 1.2 worked through in detail. Caught by the one-hot assertion in §7, and by a master-side design that makes multiple assertion impossible by construction.

A device that never releases MISO. One device drives the shared net regardless of its select. The signature is distinctive: the bus works perfectly with that device alone and fails for every other device. Anyone who has added a second peripheral to a working board and watched it break has met this one.

A decoder glitch. Combinational select decoding passes through transient patterns while the index changes, briefly asserting a select that was never intended. The victim device may begin a transaction, or drive MISO for a few nanoseconds. Registering the decoder's outputs — §7's whole design decision — prevents it.

Select asserted but no device answers. MISO sits at a constant level for the whole transfer. That constant is the tell: a floating net or a device that never enabled its output, not a data error.

Daisy chain

Frame length wrong. Clocking the wrong number of bits leaves the chain rotated. Every device ends up holding a value intended for its neighbour — plausible data in the wrong place, with no electrical symptom at all.

Ordering reversed. The driver assembled the frame in device order rather than chain order, so the values land mirrored. Same signature: entirely well-formed waveforms and completely wrong behaviour.

A non-chainable device in the chain. A device whose serial output does not present its shifting register contents breaks the ring, and everything downstream receives nothing meaningful. This is the failure the §4 callout exists to prevent, and it is a wiring error that no amount of firmware will fix.

Notice the pattern once more: independent-select failures leave electrical evidence; daisy-chain failures do not. On a chain, the waveform can be immaculate while the behaviour is wrong, which is why a chain needs a model of expected contents rather than a scope.

9. Why a Verification Engineer Cares

Multiple devices change what a testbench has to represent, in three specific ways.

A transfer needs a device identity. Chapter 1.4's transaction item carried a cs_index field, and this is why: on a multi-device bus, an exchange is not fully described by its two byte streams. Which device participated is part of the observation, a monitor must derive it from the select lines, and a scoreboard must route the transfer to the right device model.

Ownership becomes a checkable property, not an assumption. The one-hot assertion in §7 is the master-side half. The bus-side half is observing MISO and confirming that exactly one device is driving it whenever the master samples — which cannot be proven from the select lines alone, because a misbehaving device drives regardless of them. A complete environment checks both, and Module 16 builds that monitor.

A daisy chain needs a chain model, not a device model. Because one transfer updates every device at once and the returned frame is the chain's previous contents, the reference model is a shift of the whole chain rather than N independent devices. A scoreboard built for independent selects will not describe a chain correctly, and a test suite that covers one topology says nothing about the other — a coverage point worth writing down early.

10. Common Misconceptions

11. Reason It Through

Work this before reading the answers.

A board has a working SPI link between an FPGA and a serial flash, running reliably for months. An ADC is added on the same SCLK, MOSI and MISO nets, with its own select line. After the change, flash accesses begin failing intermittently — and ADC accesses work perfectly.

Why is the direction of the symptom the most informative fact here? Because the device that broke is the one that did not change. Nothing about the flash, its wiring or its firmware was modified, so the failure must come from something the ADC introduced onto shared nets. That immediately rules out the flash's command encoding, its timing configuration and its driver — the places an engineer instinctively looks first.

Which shared net can a newly added device break, and how? MISO. SCLK and MOSI have exactly one driver — the master — and another listener on them changes nothing logically. MISO is the only shared net with more than one potential driver, and the ADC has an output stage on it now. If the ADC drives MISO while its own select is inactive, then during every flash transaction two devices are driving the return path.

Why intermittent rather than constant? Because contention corrupts only where the two drivers disagree. When the ADC's output happens to match the flash's bit, the sampled value is correct. The failure therefore tracks the data — the flash's own contents — which is exactly the pattern that makes it survive short tests and appear at random later. A fault whose rate depends on data rather than on time is a strong contention signature.

What is the single most decisive measurement? Probe MISO during a flash transaction with the ADC's select confirmed inactive. If MISO shows drive strength or transitions attributable to the ADC — or if the levels are intermediate rather than clean rails — two devices are driving. A cleaner variant of the same test: physically remove or hold the ADC in reset and see whether flash reliability returns. That isolates the mechanism without any protocol analysis.

What are the plausible root causes, and how do they differ? Either the ADC's output-enable logic is wrong — it drives MISO whenever powered rather than only when selected, which is a device or configuration fault — or the master is asserting both selects, which is a controller fault and is exactly what §7's one-hot design and assertion exist to prevent. Distinguishing them is one more measurement: watch both select lines during a flash transaction. If the ADC's select is genuinely inactive and it is still driving, the device is at fault; if both selects go low together, the master is.

Why is "lower the clock rate" a bad response even if it helps? Because it may well help — contention windows and marginal levels are both sensitive to timing — while leaving two drivers fighting on a net. The symptom moves, the fault remains, and it returns with temperature, a different part lot or a faster build. Chapter 1.6 takes up the cases where clock rate genuinely is the mechanism, which is precisely why it must not be the reflex here.

12. Understanding Check

13. Summary

Adding devices to an SPI bus is cheap in exactly one direction. SCLK and MOSI are shareable because the master is their only driver. MISO is shareable only because selection makes ownership exclusive — every device has an output stage on that net, and the bus works because at most one enables it. CS is not shareable, because distinguishing devices is its purpose. So N peripherals cost three shared signals plus N selects, and the marginal device costs one pin.

The daisy chain is a different arrangement, not merely a cheaper one. Wiring each device's serial output to the next one's input extends the ring of Chapter 1.3 through the devices, making them a single long shift register with one select and one clock. That buys simultaneous update of every device and costs transfer length proportional to the chain, driver-side frame assembly in chain order, and the loss of per-device addressing. It is right when the devices are alike and meant to move together, and wrong for a handful of unrelated peripherals — and it is a device feature that must be documented, not something SPI provides.

The topologies fail in different layers, which is the most portable diagnostic fact in this chapter. Independent-select failures are electrical: two selects asserted, a device that never releases MISO, a glitching decoder — all leaving contention or a stuck level that a scope can see, and all data-dependent enough to survive short tests. Daisy-chain failures are semantic: a wrong frame length or ordering produces immaculate waveforms carrying correct values into the wrong devices, detectable only against a model of the chain's expected contents.

In RTL, multi-device selection is small but not trivial: a registered one-hot decoder with an all-deselected default and an out-of-range guard makes "at most one select" true by construction rather than by convention, and makes it assertable in one line.

14. What Comes Next

Every chapter so far has treated the wires as ideal — a bit driven at one end appears at the other. Chapter 1.6 — Electrical and Board-Level Limits removes that assumption and asks the question this chapter's multi-device bus makes urgent: why does a link that runs happily at one clock rate fail at a higher one, with identical logic, and why does adding a device to a shared net sometimes lower the rate the whole bus can sustain? That is where the abstraction meets capacitance, propagation delay and the round trip a returned bit has to complete.

Browse the path on the SPI curriculum index, or revisit Master, Slave, and Signal Ownership for the ownership rule this chapter scales up. For a bus that answers the same multi-device problem by transmitting an address instead of asserting a wire, see Why I²C Exists.

Continue learning