SPI · Module 5
Write Waveform Analysis
Reconstruct a transaction from four unlabelled signals: recover the mode from the idle level and transitions, find the frame, segment the bytes, and see where decoding stops and the datasheet takes over.
Every chapter so far has explained a transaction whose shape you already knew. This one reverses the exercise, and it is the skill the rest of the track has been quietly building toward.
Here is a capture: four signals, no labels, no datasheet, no configuration. What can you reconstruct, and where exactly does reconstruction stop?
The answer divides cleanly. Signalling is fully recoverable from the capture alone. Meaning is not, and the boundary between them is precisely Chapter 4.1's thesis arriving as a practical procedure.
1. The Method, in Order
The steps are ordered so each one narrows what the next has to consider, and every step is cheap:
- Read the idle level — recovers
CPOLwith no interpretation at all. - Find the frame — CS edges bound everything else.
- Determine which edge samples — recovers
CPHA, and with it the mode. - Count the edges — gives the total bit count and constrains the word width.
- Segment into bytes — turns edges into values.
- Assign roles — and this is where the capture stops being sufficient.
Running them out of order is the usual mistake. Deciding what byte one "must be" before establishing the mode means the bytes themselves may be wrong.
2. Steps 1–3: Recover the Mode
An unlabelled capture — enough to recover the mode
10 cyclesStep 1 — the idle level. With CS deasserted, at either end of the figure, SCLK rests low. By Chapter 3.1 §1 that is CPOL = 0, and it is the only fact in this entire procedure that requires no reasoning whatsoever. Read it first, always.
Step 2 — the frame. CS falls once and rises once, so this is a single transaction. Everything between those edges belongs to it; everything outside is not data (Chapter 5.2 §4).
Step 3 — which edge samples. Here is the inference that does the work. MOSI changes on falling edges and is stable across rising edges. A transmitter launches a bit and the receiver samples it later, so the sampling edge is the one the data is stable across — the rising edge.
With CPOL = 0, rising is the leading edge (Chapter 2.2), and sampling on the leading edge is CPHA = 0. So this capture is Mode 0, derived rather than assumed.
Step 4 — count and read. Four rising edges, so four bits. Sampling MOSI at each: 1, 0, 1, 1.
Notice what has not been assumed: nothing about width, nothing about bit order, nothing about what the bits mean. Those come later and some of them never come at all.
3. Steps 4–5: Count Edges and Segment
Extend the same capture to a full transaction and the edge count becomes the structural fact.
Count every active edge between the CS edges. Suppose there are 48. That is 48 bits — and immediately constrains the framing: 48 is six 8-bit words, or three 16-bit words, or two 24-bit words, or one 48-bit transfer. The capture cannot distinguish these (Chapter 4.2 §2), because CS delimits the frame, not the words inside it.
Eight is the right first guess and should be held loosely. It is overwhelmingly the most common (Chapter 4.2 §1), and a count that is a multiple of eight is consistent with it. A count that is not — 36, say — is informative in the other direction: it rules out 8-bit framing outright and points at a 9-bit or 12-bit device.
Assemble MSB-first first. Also the dominant convention (Chapter 4.3 §2). If the resulting bytes look like plausible opcodes and addresses, the guess was right; if they look like noise, try the reversal before concluding anything, because a bit-order mismatch produces values that are exactly the reversal (Chapter 4.3 §8).
4. Step 6: Assign Roles — and Where It Stops
Six bytes out, nothing back
8 cyclesWhat is certain. Six bytes, in this order, inside one frame, with nothing returned.
What is near-certain. Byte 1 is an opcode, because Chapter 4.4 §5 established that a device must decode byte 1 to know how to frame the rest. This holds for essentially every device with a command structure.
What is a reasonable inference. This is a write. MISO is silent for the whole frame, and a read would have to return something (§5).
What is genuinely ambiguous — and this is the point. The split between address and data. All of these are consistent with the capture:
| Reading | Address | Data |
|---|---|---|
| 2-byte address | 0x1F40 | 0x7A B1 00 |
| 3-byte address | 0x1F407A | 0xB1 00 |
| 1-byte address | 0x1F | 0x40 7A B1 00 |
| No address | — | 0x1F 40 7A B1 00 |
Nothing in the capture chooses between them. There is no phase marker (Chapter 4.4 §2), the bytes are physically identical, and the boundary exists only inside the two endpoints. A three-byte address is a good guess for a memory device and the guess is all it is.
This is the honest end of the procedure: a capture recovers signalling completely and structure only partially. Everything past byte 1 requires the datasheet — which is Chapter 4.1 §6's statement about logic analyzers, re-derived from the other direction.
5. Read or Write? The MISO Test
Worth isolating, because it is the single most useful classification and it takes one glance.
MISO silent for the entire frame → a write. The device had nothing to return. A write is one-way on a bidirectional bus (Chapter 5.1 §3).
MISO meaningful only after the first few bytes → a read. The leading bytes are the command and address the master sent; the device starts answering once it knows what was asked (Chapter 4.4).
MISO high-impedance for part of the frame → a read with a dummy phase, and the position of the transition tells you how many turnaround cycles there were.
MISO meaningful throughout → a device with no command structure at all, such as an ADC that returns a sample as soon as it is clocked.
One caution: "MISO is low" and "MISO is undriven" look identical on a single-ended capture unless the line has a pull-up. If distinguishing them matters, look at the transitions at the CS edges — a driven line changes when the device takes control, and a tri-stated one drifts or sits at the pull-up level.
6. Why This Chapter Has No RTL
Deliberate, and the justification is the chapter's subject.
This chapter teaches a procedure performed by an engineer on a capture. There is no hardware that does it, because a device never has this problem: it already knows the mode, the width and the phase structure by configuration. Inventing a module that "decodes an unknown SPI stream" would be inventing a requirement no real design has.
What is buildable — and what §7 builds — is the verification form of the same procedure: a monitor that reconstructs transactions from pins. The difference between the two is exactly the lesson of §4. The engineer works without a datasheet and must stop at segmentation; the monitor is given the configuration and can therefore go further. Neither can infer meaning from the wire.
7. The Monitor That Does This Automatically
A monitor performs steps 2, 4 and 5 continuously. The code below is deliberately explicit about which parameters it is told rather than deriving.
// The monitor is the automated form of §1's procedure, with one crucial
// difference: it is HANDED the mode, width and bit order. It does not
// infer them, because -- Chapter 4.1 §7 -- they are not inferable, and a
// monitor that adapted to the DUT could never detect a disagreement.
class spi_write_monitor extends uvm_monitor;
`uvm_component_utils(spi_write_monitor)
virtual spi_if vif;
spi_cfg cfg; // mode, width, msb_first -- GIVEN
uvm_analysis_port #(spi_txn) ap;
task run_phase(uvm_phase phase);
forever begin
spi_txn txn;
@(negedge vif.cs_n); // step 2: frame opens
txn = spi_txn::type_id::create("txn");
txn.t_start = $time;
fork : frame
collect_bytes(txn);
@(posedge vif.cs_n); // step 2: frame closes
join_any
disable frame;
txn.t_end = $time;
// A frame carrying a partial word is NOT a malformed
// transaction -- it is an abort (Chapter 5.1 §4), and the
// scoreboard must be told which it saw.
txn.truncated = (txn.bit_count % cfg.width) != 0;
ap.write(txn);
end
endtask
// Steps 4 and 5: count edges, assemble words.
task collect_bytes(spi_txn txn);
logic [63:0] shreg = '0;
int n = 0;
forever begin
@(sample_edge()); // the edge cfg.mode selects
shreg = cfg.msb_first ? {shreg[62:0], vif.mosi}
: {vif.mosi, shreg[63:1]};
n++; txn.bit_count++;
if (n == cfg.width) begin
txn.mosi_words.push_back(extract(shreg, cfg.width, cfg.msb_first));
shreg = '0; n = 0;
end
end
endtask
endtaskWhat the monitor establishes. Frame boundaries, bit count, word segmentation under the configured width and order, and whether the frame was truncated.
What it cannot establish, and must not pretend to: which words are opcode, address or data. That mapping belongs to a device-specific layer above the monitor (Chapter 4.1 §7), and putting it in the monitor is what produces an "SPI monitor" that silently fails on the next device.
The truncated field is the one people leave out. Chapter 5.1 §4 established that an aborted frame is a legitimate event with defined semantics — the device discards. A monitor that drops partial frames, or reports them as errors, makes abort testing impossible, and abort is the case Chapter 5.1's coverage model showed is usually unexercised.
8. Coverage of the Decode
covergroup spi_capture_cg @(posedge cs_rose);
// Whether the frame divided evenly into words. Both outcomes are legal
// and the monitor must handle each; only one is ever tested by default.
cp_alignment : coverpoint frame_aligned {
bins aligned = {1};
bins truncated = {0}; // the abort path
}
cp_words : coverpoint words_in_frame {
bins one = {1};
bins cmd_addr = {[2:4]};
bins burst = {[5:256]};
bins huge = {[257:$]};
}
// §5's classification. A decoder tested only on writes has never run
// its tri-state handling.
cp_direction : coverpoint frame_direction {
bins write_only = {DIR_W}; // MISO silent throughout
bins read_after = {DIR_R}; // MISO meaningful after N bytes
bins read_dummy = {DIR_RD}; // MISO high-Z for a turnaround
bins bidi = {DIR_BI}; // both directions meaningful
}
x_dir_words : cross cp_direction, cp_words;
endgroupcp_alignment's truncated bin is the one to insist on, for the reason §7 gave: it is the only bin that exercises the abort path, and a suite of well-formed transactions never reaches it.
9. Failure Signature — The Capture Disagrees With the Driver
Symptom. A driver is believed to send 0x02 0x1F 0x40 0x7A. A capture, decoded by the analyzer, shows 0x40 0x7C 0x81 0xE8. The bytes are the wrong values but the right count, and the transaction framing looks correct. The device misbehaves in a way consistent with the analyzer's version rather than the driver's.
What the correct byte count establishes. The framing is right: CS bounds the transaction properly, the edge count matches four 8-bit words, and nothing is truncated. So this is not a width, framing or abort problem — it is a value problem, and values can only be wrong if the bits were assembled differently.
Plausible mechanisms.
- The analyzer's configuration disagrees with reality — the wrong mode, so it samples on the wrong edge and assembles shifted values (Chapter 4.1 §9).
- A bit-order disagreement between analyzer and master (Chapter 4.3).
- The driver genuinely sends different bytes than believed.
- A mode mismatch between master and device, with the analyzer configured like the device.
The discriminating observations, cheapest first.
Check whether the observed bytes are the expected ones bit-reversed. 0x02 reversed is 0x40 — and the capture's first byte is 0x40. That single arithmetic check, costing nothing, identifies a bit-order disagreement immediately and explains the whole sequence.
If reversal does not explain it, check for a one-position shift, which indicates a phase disagreement (Chapter 3.8 §3) rather than an order one.
Then — and this is the step people skip — set the decoder to raw bits and apply §1's procedure by hand. The analyzer's byte view is an interpretation built on parameters a human typed in; the raw line is evidence. Recovering CPOL from the idle level and the sampling edge from where transitions cluster takes under a minute and settles whether the analyzer or the driver is wrong.
Why the investigation goes wrong. Because a decoded byte list looks like data and gets trusted as data. It is the output of a decoder someone configured, and when the decoder is misconfigured it produces confident, wrong, self-consistent output. Working the capture by hand is the only way to check the tool itself, and it is why this chapter's procedure is worth knowing even when you own a very good analyzer.
10. Common Misconceptions
11. Reason It Through
Work this before reading the answer.
An unlabelled capture shows: SCLK resting high between frames; CS low for one frame; 36 active clock edges; MOSI transitioning immediately after each rising edge; MISO flat low for the first 16 edges, then carrying transitions for the remaining 20.
What can you establish, and what remains open?
Mode, completely. SCLK idles high, so CPOL = 1 (Chapter 3.1 §1). MOSI transitions immediately after rising edges, so rising is the launch edge and falling is the sampling edge. With CPOL = 1 the leading edge is falling (Chapter 2.2), so sampling on the leading edge means CPHA = 0. That is Mode 2 — derived entirely from the capture, with nothing assumed.
Width — and here the edge count is genuinely informative. 36 is not a multiple of 8, so this is not an 8-bit device, and that conclusion is solid rather than a guess. 36 factors as 4×9, 3×12, 2×18 or 1×36. A 9-bit framing is the most likely: 9-bit devices are real and common enough (Chapter 4.2 §4), and four 9-bit words is a plausible transaction. 12-bit is also credible, particularly for a converter.
Direction. MISO is flat for 16 edges and then active for 20. The device began answering partway through, so this is a read, not a write (§5). The master sent something for 16 edges and the device responded for the remaining 20.
And here is the tension worth noticing. 16 is not a multiple of 9. If the framing really is 9-bit, the device started answering inside a word, which is unusual — devices normally begin at a word boundary. That argues either for 12-bit framing, where 16 is still not a boundary, or that MISO's first meaningful transition is not exactly where the response starts: a device may drive a leading zero or the line may be held before the data begins. Two of the three candidate widths are in mild tension with the MISO transition point, and noticing the tension is the analytical result — it tells you which datasheet fact to look up first.
What remains open. The word width, beyond "not 8". The bit order, which is not observable at all. The split between command, address and data among the outbound words. And whether the operation succeeded, which is never visible because nothing acknowledges.
What to do next. The count being non-multiple-of-8 is the strongest lead — it narrows the device class sharply, since most parts are byte-oriented. Identify the part, check its word width, and the rest of the decode follows in a single step.
12. Understanding Check
13. Summary
A capture is decoded in a fixed order, each step narrowing the next: idle level gives CPOL with no interpretation; CS edges bound the transaction; the edge data is stable across gives the sampling edge and therefore CPHA; the edge count gives the bit count; segmentation gives values; and role assignment is where it stops.
The mode is always recoverable, from any capture with a few transitions, because transitions cluster around the launch edge — which is what setup and hold margin means in practice.
The bit count is a fact; the word width is not. Forty-eight edges is 48 bits and equally consistent with six 8-bit, three 16-bit or two 24-bit words. A count that is not a multiple of eight is the more informative case, because it rules out byte framing outright.
Direction is read off MISO: silent throughout means a write; meaningful after some bytes means a read; a high-impedance gap means a read with a dummy phase. The caution is that driven-low and undriven look identical on a single-ended capture.
The procedure stops at role assignment. The split between opcode, address and data is not on the wire, so a six-byte frame is equally consistent with a one-, two- or three-byte address. That is Chapter 4.1's thesis reached from the observer's side.
The verification form of the same procedure is a monitor — which performs the framing and segmentation automatically precisely because it is given the configuration it must not infer, and which must report a truncated frame as an abort rather than an error, since abort is a legitimate event with defined semantics.
And when a capture disagrees with a driver, check the arithmetic relationship first: a bit-reversal means an order disagreement, a one-position shift means a phase one. Then decode by hand, because a misconfigured analyzer produces confident and self-consistent wrong bytes.
14. What Comes Next
That closes Module 5. The write path is complete: its anatomy and commit point, what the master drives and what CS brackets, multi-byte bursts and the page boundary, and the analysis skill that reads any of it off a screen.
The write's defining characteristic was that nothing comes back. Module 6 takes the other direction and inherits a harder problem: a read must return data the device has to fetch, over a path with a round-trip delay, and the master must decide when that data is valid. Everything Module 2 established about output-valid timing and the round-trip budget becomes a transaction-level concern there.
Browse the path on the SPI curriculum index, or revisit Anatomy of a Write Transaction for the commit semantics this module was built on.
Continue learning
Related tutorials
- Related topic
Read Waveform Analysis
Decode an unlabelled read capture including the dummy phase: why the MISO tri-state transition is the most informative event on the bus, how to measure read latency without a datasheet, and checking versus discovery.
- Related topic
Mode Mismatch and Its Failure Signature
What happens when the two ends disagree about the mode. The distinct signature each mismatch produces, how to tell polarity from phase disagreement from the data alone, and the monitor and coverage work that catches it.
- Related topic
MISO Contention and Multiple Slaves Selected
What two active drivers do to a shared net: why the level is undefined rather than wrong, how much current flows, why damage ranges from a corrupted bit to a destroyed output stage, and why contention can be detected but never implemented.
- Related topic
Bit Ordering — MSB-First and LSB-First
Which end of the shift register goes out first, the two multiplexers that make the order configurable in three HDLs, and why a bit-order bug is perfectly deterministic and yet invisible on certain data.
