Time Domain Reflectometry (TDR) Properties, Semiconductor Industry Failure Analysis Applications, and Implementation on FPGA

15 minute read

Published:

In this report, we will explain the physics and math behind TDR, including how impedance mismatches cause signal reflections and how timing is used to determine fault locations. Then, we will explore how TDR is applied in semiconductor failure analysis. Finally, we will explain how TDR can be implemented on an FPGA.

Principles of TDR

TDR is a technique that is used to detect and locate impedance changes along an electrical path by injecting a fast pulse and observing reflections (discontinuities) in the time domain. We can compare it to radar where a pulse is launched, and any echo we receive after tells us there is a change or fault. In both cases, we can use the time delay between the signal/pulse launch and the echo reception to calculate where the discontinuity is.

TDR operates on transmission line principles: a fast-rising voltage pulse is injected into a conductive line, and any change in the line’s characteristic impedance causes a portion of the signal to reflect back. If the line is uniform at characteristic impedance \(Z_0\), the injected pulse is completely absorbed with no reflections. When a pulse encounters a discontinuity, a reflection will be observed. The magnitude and polarity of this reflected wave are defined by the reflection coefficient \(\rho\), which is calculated mathematically for a line with characteristic impedance \(Z_0\) and load impedance \(Z_L\) using the equation:

\[\rho = \frac{Z_L - Z_0}{Z_L + Z_0}\]

as seen in transmission line theory 1. This value ranges from -1 to +1. A \(\rho\) of 0 means that there is no reflection, which indicates a perfectly matched load and no discontinuity. A positive reflection coefficient indicates that the reflection wave is in-phase (same polarity) with the incident pulse, and a negative coefficient indicates that the reflection wave has inverse polarity to the incident pulse. Notably, an open circuit (\(Z_L=\infty\)) yields \(\rho=+1\), a full positive reflection. A short circuit (\(Z_L=0\)) yields \(\rho=-1\), a full negative reflection. This means that when looking at the waveform, the TDR trace will rise upward for an open and dip downward for a short relative to the incident pulse level 1. Less extreme impedance mismatches will produce smaller hills and valleys.

TDR waveform example

Short vs Open TDR waveforms: A TDR trace(green) will jump downward for a short circuit (upper left) and upward for an open circuit (lower left). A load with the same impedance absorbs the signal with no reflection (upper right), while a mismatched impedance produces a slight reflection (lower right) whose magnitude is proportional to the difference in load and characteristic impedance.

When a reflection is observed, the time delay between launching the pulse and receiving the reflection can be used to determine where along the line the fault is located. The signal travels along the line at a known velocity \(v\) which will be a fraction of the speed of light \(c\). By measuring the round trip travel time \(\Delta t\), the distance from the source to the impedance change can be calculated using the formula:

\[d = \frac{v \cdot \Delta t}{2}\]

since the pulse covers the distance twice (to the fault and back). For example, if a pulse reflects 10 ns after launch where the signal travels at \(2/3 c\), the discontinuity is approximately 1 meter from the launch point. For semiconductors, since the density of electronics is much higher, the delays are much shorter (in the picoseconds). That’s really darn fast. So, modern TDR tools used for Failure Analysis (FA) in semiconductors pinpoint faults at the scale of centimeters, millimeters, or even microns.

TDR spatial resolution is limited by the rise time of the incident signal. A faster rise time allows the TDR tool to distinguish between two closely spaced discontinuities, while a slower rise time would blur them together into one big discontinuity blob. Generally, the minimum resolvable distance between two faults is around half of the system rise time. If two impedance changes occur within a time separation shorter than:

\[d_{\text{min}} \approx \frac{v \cdot T_{\text{rise}}}{2}\]

their reflections will overlap and appear as one combined disturbance on the waveform. If we have a super fast rise time of 35 ps, the pulse would yield a very fine resolution- small impedance changes like connector imperfections that would appear as small stubs would become very visible bumps. But a 1 ns rise time would smooth over all these details 1. Here, we can see a trade-off. Faster edges give more detail, but also make the TDR waveform more sensitive to every tiny discontinuity, whereas slower edges average out the small imperfections.

Applications of TDR in Semiconductor Failure Analysis

Because semiconductors are complex and expensive to produce, a single defect in a wafer or die can lead to the loss of thousands of dollars in both materials and time. Failure analysis methods such as FIB and TEM (which requires FIB preparation) take away material which irreversibly alters the structure of the sample. TDR is especially useful because it can quickly pinpoint where an electrical connection is open or shorted without physically damaging the part. TDR can localize defects in all the main regions of a packaged IC- the on-chip interconnect (die metallization or bump connections), the package substrate, or the package-to-board interconnects 2. It is effective for ball-grid-array (BGA) packages as well as wire-bonded packages, and it can even be used on fully assembled boards. Testing lines in such a way offers a non-invasive way to “see” inside an IC package which is very valuable. This is especially important when working with expensive or limited-quantity samples where physical disassembly isn’t an option.

TDR’s visual waveform effectively creates a one-dimensional impedance map of the signal path. By analyzing the amplitude and timing of reflection steps, we can deduce both the type of fault (open vs short) as well as the position of the fault. These faults typically appear as sharp transitions in the TDR waveform— an indicator we discussed above. By measuring the time it takes for a reflection to return, engineers can pinpoint the exact location of the discontinuity, all without having to physically open up the device. TDR is equally effective at the board level, allowing analysis of PCB traces, connectors, or vias without needing to desolder components or disassemble the system.

What makes TDR especially powerful is that it doesn’t just tell you where the fault is—it also gives insight into what kind of fault you’re dealing with. A large positive reflection generally indicates an open circuit, such as a cracked solder joint or a broken interconnect. A strong negative reflection points to a short, like a solder bridge or internal breakdown. More subtle impedance mismatches show up as smaller deviations in the waveform and could indicate voids, delaminations, or constricted signal paths. This ability to both locate and classify faults adds valuable precision to the failure analysis process—before anything is physically altered.

TDR also plays an important role in guiding destructive analysis. Once a fault is located, destructive techniques like FIB or TEM can be used with more precision, focusing only on the suspected failure site. This reduces unnecessary sample damage and speeds up root-cause identification.

In short, TDR offers a fast, informative, and minimally invasive way to zero in on electrical defects.

Implementing a TDR Simulation on the DE10-Nano (Cyclone V FPGA)

Implementing a TDR system on FPGA involves creating a digital model of pulse propagation and reflection, and then visualizing the results on a display. The implementation platform we are using is the Terasic DE10-Nano.

Core Modules and Signal Processing Blocks

In a classic TDR setup we would need a pulse source, a transmission line, and measurement electronics. However, for this FPGA simulation, we will replicate these functions digitally.

Pulse Generator: A digital circuit to launch fast-rising test pulses. In hardware TDRs, this pulse would be analog, but for this project we can use the rising edge of a clock cycle or a step change register that represents the source voltage. This module needs to be capable of producing a narrow pulse on command to emulate the TDR excitation signal. The pulse width and repetition rate can be adjusted as needed later when we produce our testbench (e.g. a pulse every 2 ms). For this we can implement a state machine or a simple counter.

Transmission Line Emulator: This will be the core of our simulation. It will digitally model the signal propagation as it travels down the transmission line and any reflections that may occur due to impedance mismatches. In practice, a real TDR cable propagates a wave at ~2e8 m/s and has reflections at discontinuities 3. We can emulate this by using a delay line or a pipeline. The line will be divided into \(N\) segments, each representing a small length (a small propagation delay). For example, we can use a line of registers that moves a 1 or multi-bit value (for analog amplitude) step by step each clock cycle. This module should output the line’s input node voltage at each simulation step for sampling. For this we can implement a pipeline of D flip-flops (DFFs).

Reflection Handler: Although this is part of the line emulator, it will have its own logic block. This module will handle how the signal behaves at the boundary conditions and impedance discontinuities (source or load). At the far end of the line, it implements the reflection coefficient for the load which will either be an open or a short. Before, we discussed \(\rho\) having a value of either \(\rho=+1\) or \(\rho=-1\). For this project we will implement a lossless transmission line. In digital terms, if we represent the wave as a signed value, an open can be modeled by copying the incident pulse value to a returning wave, and a short by copying the negated value. For example, if the forward wave at the last segment is \(V\), on the next cycle produce a backward-traveling wave of \(+V\) for an open or \(-V\) for a short. On the source end, we set a source reflection coefficient, \(\rho_S\). When the source impedance equals the transmission line impedance, \(\rho_S=0\). Giving the system a \(\rho_S\) of 0 will prevent an endless bouncing of signals between the source and load since some magnitude of the signal will always be reflected by each one. This ensures that a signal will only be reflected if there’s an impedance mismatch. If we wanted to simulate an impedance mismatch in the middle (not just at the ends), we can insert a partial reflection node. When the signal reaches this point, it will split into two components:

  • The reflected component: \(\rho * V\) (the reflected signal, where \(\rho\) is the reflection coefficient at that point)
  • The transmitted component: \((1- \rho) * V\) (the part of the signal that continues to propagate down the line)

This allows for simulating points along the line where the impedance isn’t perfectly matched, and it gives a more realistic testbench. This reflection logic can be implemented using simple conditional statements or multipliers (if we use fractional coefficients for the partial mismatches).

Sampler/Oscilloscope Logic: In a real TDR, a fast analog to digital converter (ADC) captures the voltage vs. time. In our digital model, we already know the signal value at the source node for each simulation clock tick, so an ADC isn’t needed. This logic will store this value in a register and output it each clock cycle instead. So, we will record the waveform of the source-end voltage as the pulse propagates and any reflections that return. For our FPGA, a memory buffer (BRAM) will be used to store the voltage values over each simulation timestep. This memory is structured to hold an array of waveform samples, where each sample corresponds to a moment in time during the simulation. So if we want to display 1000 points on the time axis of the waveform, we have to allocate 1000 spaces in memory to hold these samples, each representing a snapshot of the voltage at that particular time. As simulation progresses, the BRAM is filled with these data points, building a trace of the TDR waveform. For this project, we will display the sampling of the source node continuously and display it real time onto an HDMI/VGA display. To implement this, we can use sequential, edge-triggered logic to capture samples at each clock tick.

VGA/HDMI Output Controller: This module will control the visual aspect of this project. The video controller will display our waveform on a screen using horizontal synchronization (HSYNC), vertical synchronization (VSYNC), and pixel coordinates. We will use the 640x480 VGA mode. A framebuffer stores the pixel data (color and brightness) for each frame to be displayed. We can have the controller use the sample memory as a framebuffer: for each X pixel (time), read the corresponding sample (voltage) and draw a dot or line at the appropriate Y magnitude. This will save us memory since we won’t have to use a full framebuffer; instead, we will generate our waveform “on the fly”. So, only the waveform samples and the graphical elements need to be stored. This “on the fly” rendering will require a column counter (X-axis) and a row counter (Y-axis) to keep track of where the current pixel is being drawn. The controller will read the sample value for the current pixel and compare it to the current row to decide if a pixel should be drawn or skipped. For example, if the sample value for a given X-coordinate is higher than the current Y-coordinate, it will draw a pixel at that position. To implement this we will use comparators and counters.

Control and Interface Logic: This logic will be for user interface which will improve usability. Push buttons and switches can be used to adjust parameters like line length and pulse repetition. A reset switch and a start switch will also be implemented for trigger/re-arm. This will all be integrated into the modules above.

Modeling Signal Propagation and Reflection in SystemVerilog

To simulate the physics of signal reflections, we will use a discrete-time model of the transmission line. We can treat the line as two traveling waves (forward and reverse) moving through a series of delay elements (impedances). As mentioned above, this can be implemented using shift registers (DFFs) with the waves being bit values.

  • Forward wave array \(V_+\): This represents the incident pulse injected from the source. If we imagine the transmission line being split up into \(N\) segments, each element [i] in the array corresponds to the voltage at segment i, and it will be shifted up one segment for \(N\) cycles. This emulates the wave moving one segment further (wave propagating along transmission line).

    forward[i+1] <= forward[i]

    The source injects the initial pulse at segment 0 (forward[0] goes high for one clock tick)

  • Reverse wave array \(V_-\): This represents the reflected wave traveling from the load back toward the source. We can shift this array in the opposite direction each clock cycle.

    reverse[i-1] <= reverse[i]

    Initially, this array will be all zeros.

  • Boundary conditions: When the forward wave reaches the end of the line (highest segment index, \(N\)), we calculate a reflected value. For an open-circuit end, the full forward step reflects back, so we can set the last element of the reverse wave to the same value as the forward wave that got to the end \(\rho_L=+1\). For a short, assign it the negated value \(\rho_L=-1\). Implementing this in SystemVerilog could look like this:

    for a short,

    if (forward[N] != 0) reverse[N] <= -forward[N];

    or for an open,

    reverse[N] <= forward[N];

    On the next clock, that reverse[N] value will propagate to reverse[N-1], reverse[N-2], etc., moving back toward the source.

At the source, we will have to sum the reverse and forward waves together which can be as simple as: V_source = forward[0] + reverse[0] at each time step. If the source has matching impedance to the transmission line, \(\rho_S=0\), so we can just read out reverse[0].

Each shift in our project corresponds to a fixed propagation delay segment. For example, if 1 clock tick = 1 ns of “simulated time” and you have \(N=100\) segments, then the line represents 100 ns two-way delay. We can choose the time-step to scale the simulation. This is important and valuable since our FPGA clock has limits. A smaller step will give finer resolution, but it will require more clock cycles. It wouldn’t be practical for us to simulate at picosecond steps in real time because we would need multi GHz logic speeds. Instead, we can run our simulation slower than real-time which will suit our needs since we are running a demonstration. For our specific FPGA (the DE-10 Nano), we will have a 50 MHz clock (20ns per step), 200 steps would simulate 4 μs of one-way wave propagation. If this translates to around 600m of cable (for demonstration’s sake), it’s plenty to see an effect. When displaying this, we can add a section on the VGA display that labels in “pseudo-units” or we can just scale it accordingly.

Since our digital model is a lossless, ideal transmission line. It doesn’t include frequency-dependent attenuation or dispersion (which real cables have), but it captures the basic behavior of reflections. If needed, we can extend the model. For example, we can include a slight attenuation factor <1 for each segment (multiply the wave by a constant <1 as it propagates to simulate loss) or add a small spread (rising time increase) as it travels. However, each added effect increases complexity and resource use. For the sake of this project, we will use an attenuation as the wave propagates through each segment. If representing amplitude as only 1-bit (presence or absence of a pulse with a 0 or a 1), you can still demonstrate a reflection (the pulse returns). But using, say, 8-bit or 16-bit values allows showing partial amplitudes (for instance, to show the halved voltage on a matched line, or a negative dip for a short). Using an 8-bit signed value for the wave amplitude is a convenient choice: 0 = no signal, 127 = full high, -127 = full inverted reflection. The SystemVerilog can handle the addition and shifting of these just fine.

For this project, I suspect that the biggest hurdle moving forward will be the TDR simulation to VGA output. Since these two components run on different timing domains, they don’t share a common clock. If the simulation writes to a waveform buffer while the VGA is reading it… that’s bad. If the data flow isn’t managed extremely well, getting a flicker-free VGA output that matches the simulation timing will be difficult. As of writing this blog post, I have yet to find an adequate solution to this problem. If you have any tips or tricks please feel free to email me- I would love to hear from you!