4. 边界扫描(JTAG)测试程序开发

任务定义

本案例实现ATE测试程序中的电源电流测试功能,覆盖静态电源电流(IDDQ,器件处于休眠或静止状态下的漏电流)和动态电源电流(IDD,器件在正常工作时钟频率下运行时的平均电流)两类测量。被测对象为数字逻辑芯片,测试目标为验证器件功耗是否满足规格书限值。测试程序通过控制DUT电源电压、时钟输入和测试模式,使用精密电源单元(SMU)完成电流测量,并根据上下限判定测试结果。

测试方案与硬件连接

测试系统由PC控制端、ATE测试头(含SMU和数字通道)以及DUT组成。SMU连接DUT的VDD引脚提供电源并回读电流;数字通道连接时钟引脚(CLK)和测试模式选择引脚(MODE)。静态测试时,MODE置为高电平使DUT进入休眠状态,SMU施加标称电压后等待电流稳定,测量漏电流;动态测试时,MODE置为低电平,数字通道输出指定频率的时钟信号,SMU在测量窗口内连续采样电流并计算平均值。测试完成后,将测量值与规格限值比较,输出PASS/FAIL判定。

PC控制端 测试程序 ATE测试头 SMU(VDD/电流测量) 数字通道(CLK/MODE) DUT 数字逻辑芯片 VDD / CLK / MODE GPIB/USB VDD + 电流回读 CLK / MODE 测量点 IDDQ: 静态 IDD: 动态

代码实现

以下Python代码实现电源电流测试的核心逻辑。代码定义PowerCurrentTest类,包含静态和动态电流测量方法、限值判定以及测试结果输出。SMU和数字通道通过接口抽象,便于适配不同ATE硬件平台。

import time
from dataclasses import dataclass
from typing import List, Tuple

# ---------- 硬件抽象接口 ----------
class SMU:
    """精密电源单元接口(实际ATE中由厂商SDK实现)"""
    def set_voltage(self, voltage_v: float) -> None:
        """设置输出电压"""
        raise NotImplementedError

    def measure_current(self) -> float:
        """回读当前电流值(单位:A)"""
        raise NotImplementedError

    def enable_output(self) -> None:
        """使能输出"""
        raise NotImplementedError

    def disable_output(self) -> None:
        """关闭输出"""
        raise NotImplementedError

class DigitalChannel:
    """数字通道接口"""
    def set_pin(self, pin_name: str, level: int) -> None:
        """设置引脚电平(0或1)"""
        raise NotImplementedError

    def generate_clock(self, frequency_hz: float, duration_s: float) -> None:
        """生成指定频率和时长的时钟信号"""
        raise NotImplementedError

# ---------- 测试参数配置 ----------
@dataclass
class PowerTestConfig:
    vdd_nominal_v: float = 3.3          # 标称电源电压
    iddq_max_ma: float = 0.050          # 静态电流上限(50 µA)
    idd_max_ma: float = 45.0            # 动态电流上限(45 mA)
    idd_min_ma: float = 10.0            # 动态电流下限(10 mA)
    settling_time_s: float = 0.010      # 静态测量稳定时间
    clock_freq_hz: float = 10e6         # 动态测试时钟频率
    measure_window_s: float = 0.005     # 动态测量窗口

# ---------- 测试结果 ----------
@dataclass
class TestResult:
    test_name: str
    measured_ma: float
    lower_limit_ma: float
    upper_limit_ma: float
    passed: bool

# ---------- 电源电流测试类 ----------
class PowerCurrentTest:
    def __init__(self, smu: SMU, digital: DigitalChannel, config: PowerTestConfig):
        self.smu = smu
        self.digital = digital
        self.config = config
        self.results: List[TestResult] = []

    def _setup_voltage(self) -> None:
        """配置并开启电源电压"""
        self.smu.set_voltage(self.config.vdd_nominal_v)
        self.smu.enable_output()
        time.sleep(0.001)  # 等待电源稳定

    def test_iddq(self) -> TestResult:
        """静态电源电流测试(IDDQ)"""
        # 进入休眠模式:MODE=1
        self.digital.set_pin("MODE", 1)
        # 停止时钟(无时钟翻转)
        self.digital.set_pin("CLK", 0)
        time.sleep(self.config.settling_time_s)

        # 测量静态电流
        current_a = self.smu.measure_current()
        current_ma = current_a * 1000.0

        # 判定:上限0.05 mA
        passed = current_ma <= self.config.iddq_max_ma
        result = TestResult(
            test_name="IDDQ_Static",
            measured_ma=current_ma,
            lower_limit_ma=0.0,
            upper_limit_ma=self.config.iddq_max_ma,
            passed=passed
        )
        self.results.append(result)
        return result

    def test_idd(self) -> TestResult:
        """动态电源电流测试(IDD)"""
        # 进入工作模式:MODE=0
        self.digital.set_pin("MODE", 0)
        # 生成时钟,使DUT内部翻转
        self.digital.generate_clock(
            frequency_hz=self.config.clock_freq_hz,
            duration_s=self.config.measure_window_s
        )

        # 在时钟运行期间测量电流
        current_a = self.smu.measure_current()
        current_ma = current_a * 1000.0

        # 判定:下限10 mA,上限45 mA
        passed = (self.config.idd_min_ma <= current_ma <= self.config.idd_max_ma)
        result = TestResult(
            test_name="IDD_Dynamic",
            measured_ma=current_ma,
            lower_limit_ma=self.config.idd_min_ma,
            upper_limit_ma=self.config.idd_max_ma,
            passed=passed
        )
        self.results.append(result)
        return result

    def run_all(self) -> List[TestResult]:
        """执行全部电源电流测试"""
        self._setup_voltage()
        try:
            self.test_iddq()
            self.test_idd()
        finally:
            self.smu.disable_output()
        return self.results

    def report(self) -> str:
        """生成测试报告文本"""
        lines = ["电源电流测试报告", "=" * 40]
        for r in self.results:
            status = "PASS" if r.passed else "FAIL"
            lines.append(
                f"{r.test_name}: {r.measured_ma:.4f} mA "
                f"(限值: {r.lower_limit_ma:.3f} ~ {r.upper_limit_ma:.3f} mA) → {status}"
            )
        return "\n".join(lines)

# ---------- 模拟硬件实现(用于本地验证) ----------
class MockSMU(SMU):
    """模拟SMU:根据模式返回预设电流值"""
    def __init__(self):
        self.voltage = 0.0
        self.output_enabled = False
        self.mode = 0  # 0=动态, 1=静态

    def set_voltage(self, voltage_v: float) -> None:
        self.voltage = voltage_v

    def enable_output(self) -> None:
        self.output_enabled = True

    def disable_output(self) -> None:
        self.output_enabled = False

    def measure_current(self) -> float:
        # 模拟:静态返回0.02 mA,动态返回28.5 mA
        if self.mode == 1:
            return 0.00002   # 20 µA
        else:
            return 0.0285    # 28.5 mA

class MockDigital(DigitalChannel):
    """模拟数字通道"""
    def __init__(self):
        self.mode_pin = 0
        self.clock_running = False

    def set_pin(self, pin_name: str, level: int) -> None:
        if pin_name == "MODE":
            self.mode_pin = level
            # 同步更新SMU模式(模拟硬件联动)
            smu.mode = level

    def generate_clock(self, frequency_hz: float, duration_s: float) -> None:
        self.clock_running = True
        time.sleep(duration_s)  # 模拟时钟运行时间
        self.clock_running = False

# ---------- 主程序入口 ----------
if __name__ == "__main__":
    # 创建模拟硬件实例
    smu = MockSMU()
    digital = MockDigital()
    config = PowerTestConfig()

    # 实例化测试类并运行
    tester = PowerCurrentTest(smu, digital, config)
    results = tester.run_all()

    # 输出报告
    print(tester.report())

    # 判定整体结果
    all_pass = all(r.passed for r in results)
    print("=" * 40)
    print(f"整体结果: {'PASS' if all_pass else 'FAIL'}")

验证方法与判定标准

本地验证采用模拟硬件(MockSMU和MockDigital)替代真实ATE设备。模拟SMU根据MODE引脚状态返回预设电流值:MODE=1(静态)时返回20 µA,MODE=0(动态)时返回28.5 mA。运行python power_current_test.py后,观察输出报告:IDDQ测试应显示测量值0.0200 mA且判定PASS(上限0.05 mA);IDD测试应显示测量值28.5000 mA且判定PASS(限值10~45 mA)。整体结果输出PASS。

接入真实ATE硬件时,将MockSMU和MockDigital替换为厂商SDK实现,并确认以下判定标准:

  • IDDQ测试:DUT休眠状态下,SMU回读电流≤规格上限(默认0.05 mA)即通过;否则为FAIL,表明存在异常漏电。
  • IDD测试:DUT在10 MHz时钟下运行,SMU回读电流处于规格下限(10 mA)与上限(45 mA)之间即通过;低于下限说明DUT未正常工作,高于上限说明功耗超标。
  • 可重复性:同一DUT连续测试5次,结果应保持一致(波动不超过±2%),确保测量稳定。

若测试结果超出限值,需检查DUT供电是否正常、测试模式设置是否正确、时钟信号是否有效传输至DUT内部电路。