Good DFT decisions made during PCB layout directly reduce test time, fixture cost, and escapes at ICT, functional test, and in-system programming. A board that's hard to probe is hard to test automatically. This guide covers the mechanical and electrical decisions that make automated testing with OpenHTF and TofuPilot practical.
What DFT Means for PCBAs
Design for Testability (DFT) is the set of layout and schematic decisions that make a PCBA observable and controllable during manufacturing test.
| Property | Definition | Test impact |
|---|---|---|
| Observability | Can you measure the signal? | Missing test points force blind assumptions |
| Controllability | Can you force the circuit into a known state? | Missing isolation makes component-level testing impossible |
| Accessibility | Can the probe physically reach the pad? | Covered vias and undersized pads break fixturing |
Test Point Placement Guidelines
Test points are the interface between your board and the test fixture. Every net you want to probe at ICT or functional test needs one.
Physical Requirements
| Parameter | Minimum | Preferred |
|---|---|---|
| Test point diameter | 0.9 mm (35 mil) | 1.27 mm (50 mil) |
| Pad-to-pad spacing | 1.27 mm center-to-center | 2.54 mm (100 mil grid) |
| Clearance from components | 0.5 mm | 1.0 mm |
| Board edge clearance | 3.0 mm | 5.0 mm |
| Max probe travel (spring pin) | 3.0 mm | 1.5 mm nominal |
Place test points on a 100 mil grid where possible. Bed-of-nails fixtures are built on that grid.
Which Nets Need Test Points
Cover these at minimum:
- Power rails (VCC, VBAT, VIO, all regulator outputs)
- Ground (one per power domain)
- Digital I/O on microcontrollers and FPGAs
- Analog signal paths (input and output)
- Crystal oscillator pins
- Reset lines
- Communication buses (UART TX/RX, SPI CS/CLK/MOSI/MISO, I2C SDA/SCL)
- Programming and debug interfaces (SWDIO, SWDCLK, TDI, TDO, TMS, TCK)
Placement Rules
Put test points on the primary side (component side) when possible. Double-sided fixtures are expensive and slow cycle time. If a net only routes on the back side, add a via to the top with a test point.
Do not cover test point vias with soldermask. Soldermask-covered vias are common for density but kill ICT access.
Common DFT Mistakes and Test Cost Impact
| Mistake | How it manifests | Cost impact |
|---|---|---|
| Test points on bottom side only | Requires double-sided fixture | 2x fixture cost, slower cycle time |
| Test points under connectors or heatsinks | Unreachable by spring pin | Net is untestable without rework |
| SMD vias with soldermask | Probe can't make contact | False failures at ICT, escapes |
| No test point on power rail | Can't verify regulation voltage | Power faults go undetected |
| Missing ground reference near analog TP | Floating measurement | Noise, false limits |
| No reset test point | Can't force DUT into known state | Functional test must rely on POR only |
| 0.5 mm or smaller test point pads | Spring pins miss or skip | Intermittent contact, low fixture yield |
| Test points at arbitrary coordinates | Off-grid pins, fixture complexity | Higher fixture build cost |
Boundary Scan (JTAG) Considerations
JTAG boundary scan (IEEE 1149.1) tests interconnect and basic component function without a bed-of-nails fixture.
For JTAG to work in manufacturing:
- All JTAG-capable devices must be in the scan chain (no unconnected TAP pins)
- TDO of each device connects to TDI of the next
- TMS and TCK are bussed across all devices
- TRST is pulled high with a 10k resistor (active-low)
- The chain must be accessible through a header or test points
Include a populated 10-pin ARM JTAG or 20-pin JTAG header on EVT boards. Depopulate the connector on production builds but keep the footprint and test points.
Programming Headers and Debug Interfaces
| Interface | Header | Signals needed |
|---|---|---|
| ARM SWD | 10-pin Cortex Debug | SWDIO, SWDCLK, GND, VCC, nRESET |
| JTAG (ARM) | 20-pin JTAG | TDI, TDO, TMS, TCK, nRESET, VCC, GND |
| UART bootloader | 4-pin 2.54 mm | TX, RX, GND, VCC |
| SPI flash | 6-pin | CS, CLK, MOSI, MISO, GND, VCC |
| FPGA JTAG | 6-pin | TDI, TDO, TMS, TCK, GND, VCC |
Many microcontrollers have BOOT0/BOOT1 pins that select the programming mode. These need to be controllable from the test fixture. Add a test point to BOOT0.
How DFT Enables Automated Testing with OpenHTF and TofuPilot
With test points, JTAG access, and a controllable programming interface, you can build a fixture that drives the DUT through a full test sequence without human intervention.
import time
import subprocess
import serial
import openhtf as htf
from tofupilot.openhtf import TofuPilot
def program_firmware(test):
"""Flash firmware over SWD using pyocd."""
result = subprocess.run(
["pyocd", "flash", "--target", "stm32g431rb", "firmware.hex"],
capture_output=True,
text=True,
timeout=30,
)
test.logger.info(result.stdout)
if result.returncode != 0:
test.logger.error(result.stderr)
return htf.PhaseResult.STOP
@htf.measures(
htf.Measurement("vcc_3v3")
.in_range(minimum=3250, maximum=3350),
htf.Measurement("vbat")
.in_range(minimum=3500, maximum=4200),
)
def measure_power_rails(test):
"""Probe VCC and VBAT test points with DMM."""
test.measurements.vcc_3v3 = 3312 # Replace with real DMM read * 1000
test.measurements.vbat = 3850 # Replace with real DMM read * 1000
@htf.measures(
htf.Measurement("uart_echo_ok").equals(True),
htf.Measurement("uart_response_time")
.in_range(minimum=0, maximum=100),
)
def test_uart_comms(test):
"""Send command over UART, verify echo and response time."""
with serial.Serial("/dev/ttyUSB0", baudrate=115200, timeout=1) as port:
port.write(b"PING\r
")
t0 = time.monotonic()
response = port.readline().decode().strip()
elapsed_ms = (time.monotonic() - t0) * 1000
test.measurements.uart_echo_ok = response == "PONG"
test.measurements.uart_response_time = round(elapsed_ms, 1)
def main():
test = htf.Test(
program_firmware,
measure_power_rails,
test_uart_comms,
test_name="PCBA Functional Test",
)
with TofuPilot(test):
test.execute(test_start=lambda: input("Serial: "))
if __name__ == "__main__":
main()Each phase maps to a test point or interface on the board. program_firmware uses SWD. measure_power_rails uses test points on VCC and VBAT. test_uart_comms uses the UART header.
Well-Designed Board vs. Poorly-Designed Board
| Step | Well-designed DUT | Poorly-designed DUT |
|---|---|---|
| Fixture contact | 100% spring pin contact on 100-mil grid | 40% contact due to off-grid and covered vias |
| Firmware programming | SWD header, automated with pyocd | Manual USB cable plug, operator-dependent |
| Power rail verification | Test point on each rail, DMM probe | No test points, inferred from UART only |
| UART comms test | Header with TX/RX/GND, 3-second phase | Requires board modification or probing SMD pad |
| Cycle time | 45 seconds automated, zero operator steps | 4 minutes with two operator interventions |
| Escape rate | Low (full coverage) | High (partial coverage, manual steps) |
DFT Checklist
| Category | Check | Pass criteria |
|---|---|---|
| Test points | All power rails have test points | One TP per rail, top side |
| Test points | All ground domains have a ground reference TP | Within 25 mm of critical measurement points |
| Test points | Key digital I/O are testable | UART, SPI, I2C, GPIO have test points |
| Test points | All TPs are 0.9 mm minimum diameter | Verified in DRC |
| Test points | All TPs on 100-mil grid | Verify in layout with grid snap |
| Test points | No TPs under connectors, heatsinks, or shields | Manual check |
| Vias | No soldermask-covered vias on critical nets | Review with fab DFM report |
| JTAG | Scan chain connected end-to-end | TDO_n to TDI_(n+1) |
| JTAG | TRST pulled high at power-on | 10k resistor to VCC |
| JTAG | JTAG header footprint present | Populated on EVT |
| Programming | SWD or JTAG header accessible on top side | Verified with fixture clearance |
| Programming | BOOT mode pins accessible as test points | BOOT0 or equivalent exposed |
| Debug | UART or SWO accessible via header or TP | Baud rate documented |
| Mechanical | Board edge clearance >= 3 mm for all TPs | DRC clean |
| Mechanical | Component clearance >= 0.5 mm around TPs | Spring pin travel verified |