Power rail testing validates that voltage regulators produce correct output before any downstream components are exercised. Run these checks first: a failed rail contaminates every subsequent measurement and risks damaging the device under test.
Prerequisites
- TofuPilot account and API key
- OpenHTF and TofuPilot installed (
pip install openhtf tofupilot) - Bench power supply or fixture with controllable power enable line
- Digital multimeter or DAQ accessible from Python
Common Power Rails on a PCBA
| Rail | Typical Source | Nominal (V) | Common Tolerance | Load Range |
|---|---|---|---|---|
| 3.3V | LDO or buck (e.g. TPS62840) | 3.3 | +/-2% | 0-500 mA |
| 5V | Boost or USB VBUS | 5.0 | +/-5% | 0-2 A |
| 1.8V | LDO (e.g. TLV75518) | 1.8 | +/-2% | 0-300 mA |
| 1.2V | Core LDO or buck | 1.2 | +/-3% | 0-1 A |
| 12V | Boost or input direct | 12.0 | +/-5% | 0-3 A |
| VBAT | Li-ion cell | 3.0-4.2 | varies | N/A |
Setting Limits from Datasheets
Pull limits directly from the voltage regulator datasheet.
TPS62840 (3.3V buck, Texas Instruments)
- Typical output accuracy: +/-1.5% at room temperature
- Over temperature: +/-2.5%
- Production test at room temp, use +/-2%: 3.234 V to 3.366 V
TLV75518 (1.8V LDO, Texas Instruments)
- Initial accuracy: +/-0.75%
- Add +/-0.5% for resistor divider tolerance
- Production test, use +/-1.5%: 1.773 V to 1.827 V
Always add margin for your measurement system's accuracy. A 16-bit ADC with a 5 V reference introduces roughly +/-0.08 mV of quantization.
Measurement Techniques
| Measurement | Instrument | When to Use |
|---|---|---|
| DC voltage | DMM / ADC | Every unit |
| No-load current | Current clamp or sense resistor | First article, incoming inspection |
| Full-load current | Power supply readback | Functional test |
| Ripple (peak-to-peak) | Oscilloscope or RMS ADC | Design validation, process escapes |
Power Sequencing
- Enable bench supply or fixture relay
- Wait for the slowest regulator to settle (typically 1-5 ms)
- Measure all rails
- Execute functional tests
- Disable rails in reverse order
Complete OpenHTF Test with TofuPilot
tests/power_rails_test.py
import time
import openhtf as htf
from openhtf.util import units
from tofupilot.openhtf import TofuPilot
class PowerFixturePlug(htf.plugs.BasePlug):
"""Controls fixture relay and reads voltages from a DAQ."""
def enable_power(self):
# Assert fixture relay to apply supply voltage to DUT
pass
def disable_power(self):
# De-assert fixture relay
pass
def read_voltage(self, channel: str) -> float:
# Return DC voltage in volts on the named channel
# Replace with your actual instrument driver
voltages = {
"rail_3v3": 3.312,
"rail_1v8": 1.796,
"rail_5v0": 4.985,
}
return voltages.get(channel, 0.0)
def read_current_amps(self, channel: str) -> float:
# Return current draw in amps via sense resistor
currents = {
"rail_3v3_current": 0.142,
"rail_1v8_current": 0.085,
"rail_5v0_current": 0.310,
}
return currents.get(channel, 0.0)
def tearDown(self):
self.disable_power()
@htf.plug(fixture=PowerFixturePlug)
def enable_and_settle(test, fixture):
"""Enable DUT power and wait for all regulators to settle."""
fixture.enable_power()
time.sleep(0.010) # 10 ms covers TPS62840 and TLV75518 soft-start
@htf.plug(fixture=PowerFixturePlug)
@htf.measures(
htf.Measurement("rail_3v3_voltage")
.in_range(minimum=3.234, maximum=3.366)
.with_units(units.VOLT)
.doc("3.3V rail: TPS62840 +/-2% at room temp"),
htf.Measurement("rail_3v3_current")
.in_range(minimum=0.0, maximum=0.500)
.with_units(units.AMPERE)
.doc("3.3V rail current draw"),
)
def check_3v3_rail(test, fixture):
test.measurements.rail_3v3_voltage = fixture.read_voltage("rail_3v3")
test.measurements.rail_3v3_current = fixture.read_current_amps("rail_3v3_current")
@htf.plug(fixture=PowerFixturePlug)
@htf.measures(
htf.Measurement("rail_1v8_voltage")
.in_range(minimum=1.773, maximum=1.827)
.with_units(units.VOLT)
.doc("1.8V rail: TLV75518 +/-1.5% including divider tolerance"),
htf.Measurement("rail_1v8_current")
.in_range(minimum=0.0, maximum=0.300)
.with_units(units.AMPERE)
.doc("1.8V rail current draw"),
)
def check_1v8_rail(test, fixture):
test.measurements.rail_1v8_voltage = fixture.read_voltage("rail_1v8")
test.measurements.rail_1v8_current = fixture.read_current_amps("rail_1v8_current")
@htf.plug(fixture=PowerFixturePlug)
@htf.measures(
htf.Measurement("rail_5v0_voltage")
.in_range(minimum=4.750, maximum=5.250)
.with_units(units.VOLT)
.doc("5V boost rail +/-5%"),
htf.Measurement("rail_5v0_current")
.in_range(minimum=0.0, maximum=2.000)
.with_units(units.AMPERE)
.doc("5V rail current draw"),
)
def check_5v0_rail(test, fixture):
test.measurements.rail_5v0_voltage = fixture.read_voltage("rail_5v0")
test.measurements.rail_5v0_current = fixture.read_current_amps("rail_5v0_current")
@htf.plug(fixture=PowerFixturePlug)
def disable_power_phase(test, fixture):
"""Disable DUT power after all measurements complete."""
fixture.disable_power()
def main():
test = htf.Test(
enable_and_settle,
check_3v3_rail,
check_1v8_rail,
check_5v0_rail,
disable_power_phase,
test_name="Power Rails Test",
)
with TofuPilot(test):
test.execute(test_start=lambda: input("Enter serial number: ").strip())
if __name__ == "__main__":
main()Power Rail Failure Diagnostics
| Symptom | Likely Cause | First Check |
|---|---|---|
| Voltage reads 0 V | Regulator not enabled; blown input fuse | Check enable pin logic level; measure input voltage |
| Voltage below minimum | Current limit reached; input undervoltage | Measure current draw; check input supply voltage drop |
| Voltage above maximum | Feedback resistor open or wrong value | Measure feedback voltage divider; confirm BOM |
| Voltage oscillates / noisy | Output cap missing or wrong type | Check ESR of output cap; inspect for tombstoned parts |
| Correct voltage, excessive current | Short on downstream net | Disconnect loads one by one to isolate short |
| Soft-start too slow | Large output cap; wrong soft-start resistor | Compare measured rise time to datasheet spec |