4、设计可测试性(DFT):测试点设计、边界扫描、内建自测试

各位做系统集成的兄弟,咱们聊聊DFT。说白了,就是你在设计电路板的时候,就得提前想好「这玩意儿将来怎么测」。别等到产线上一堆板子堆在那儿,测试工位卡住了,你才拍大腿——那时候就晚了。

我这些年经手的彩超项目,从16通道到256通道的波束合成板,DFT做得好不好,直接决定了量产爬坡的速度。有些板子设计时没留测试点,产线工人得拿示波器探头在BGA底下戳,那画面……嗯,不提也罢。

4.1 测试点设计:给产线留条活路

测试点设计,核心就一句话:让测试探针能碰到该碰的地方。但实际做起来,坑多得很。

关键原则:

  • 覆盖率优先:每个关键节点(电源、时钟、数据总线、控制信号)都要有测试点
  • 物理可达:测试点直径建议≥0.8mm,间距≥1.27mm,别让探针打架
  • 信号完整性:高速信号(比如LVDS、DDR)的测试点要加在stub上,别直接打断走线
  • 分组布局:把同一功能模块的测试点聚在一起,方便飞针测试或针床夹具设计

我记得有一次,一个同事设计的128通道模拟前端板,测试点全放在BGA背面,而且直径只有0.3mm。产线反馈说探针一压就歪,良率直接掉了5%。后来我让他改成0.8mm的方形焊盘,间距拉开到1.5mm,问题才解决。你想想看,产线工人一天要测几百块板子,探针定位不准,那就是灾难。

我的个人习惯:

在原理图阶段,我就给每个测试点加一个「TP_」前缀的net label。这样Layout工程师一看就知道:这是测试点,不能随便挪。另外,我会在PCB上预留一排「地测试点」,方便示波器接地——这招在调试阶段特别管用。

4.2 边界扫描:JTAG不只是用来下载程序的

很多人以为JTAG就是给FPGA烧录用的。其实,JTAG的边界扫描功能,是产测的一把利器。尤其是BGA封装的芯片,引脚藏在肚子底下,肉眼根本看不到虚焊。

边界扫描的原理不复杂:芯片内部有一串移位寄存器,可以「捕获」每个引脚的电平状态。你通过TDI/TDO串行读出这些数据,就能知道每个引脚是否正常连接。

// 一个简单的边界扫描测试流程(伪代码)
1. 通过JTAG加载BSDL文件(边界扫描描述语言)
2. 发送EXTEST指令(外部测试模式)
3. 向所有输出引脚写入已知数据(比如0xAA)
4. 从所有输入引脚读取数据
5. 对比期望值,判断开路/短路

// 实际产线脚本中,我会这样写:
jtag_chain_init("chain1.cfg");
bsdl_load("FPGA_bsdl", "xc7k325t.bsdl");
bsdl_load("ADC_bsdl", "ads52j90.bsdl");
set_pin_state("FPGA", "IO_L1P_T0", 1);
set_pin_state("FPGA", "IO_L1N_T0", 0);
capture_pin_state("ADC", "CLK_P");
capture_pin_state("ADC", "CLK_N");
compare_result("ADC_CLK", expected_0x55);

我曾经在一个64通道的超声前端板上,用边界扫描抓出了3处BGA虚焊。那批板子外观完全正常,上电也能工作,但信噪比就是差。用JTAG一扫描,发现ADC的时钟差分对有一根断了。如果没有边界扫描,这种问题得用热成像仪慢慢找,效率差太多了。

避坑指南:

我曾经吃过一次亏:某款ADC的BSDL文件里,把电源引脚也定义成了可扫描的I/O。结果产线一跑EXTEST,直接把电源对地短路了,烧了3块板子。后来我学乖了——跑边界扫描前,一定要先检查BSDL文件里的「power_pin」和「gnd_pin」定义,该屏蔽的引脚要手动排除。

4.3 内建自测试:让板子自己「体检」

内建自测试,英文叫BIST。说白了,就是让芯片或模块自己跑一段测试程序,然后告诉你「我好不好」。这在彩超系统里特别实用,因为通道数太多了,人工测不过来。

常见的BIST类型有几种:

BIST类型 适用场景 我常用的实现方式
Memory BIST DDR、SRAM、FIFO March C+算法,跑一遍读写校验
Analog BIST ADC、DAC、LNA 注入已知信号,比对输出幅值
Digital BIST FPGA逻辑、SerDes PRBS伪随机码,环回测试
System BIST 整机链路 发射-接收环回,检测增益和噪声

以彩超的模拟前端为例,我会在FPGA里写一个BIST控制器。上电后,它先让发射电路发出一个固定频率的脉冲(比如5MHz,50%占空比),然后通过T/R开关环回到接收通道。ADC采样后,FPGA计算信号的幅度和相位,跟预设值对比。如果偏差超过±3dB,就报错。

// FPGA内部BIST状态机(简化版)
always @(posedge clk) begin
  case (bist_state)
    IDLE: begin
      if (bist_start) bist_state <= TX_PULSE;
    end
    TX_PULSE: begin
      tx_enable <= 1;          // 开启发射
      tx_freq <= 5_000_000;    // 5MHz
      tx_cycles <= 10;         // 发10个周期
      bist_state <= WAIT_ADC;
    end
    WAIT_ADC: begin
      if (adc_done) begin
        // 计算RMS值
        rms_value <= sqrt(accum_data / sample_count);
        if (rms_value > threshold_low && rms_value < threshold_high)
          bist_pass <= 1;
        else
          bist_fail <= 1;
        bist_state <= DONE;
      end
    end
    DONE: begin
      tx_enable <= 0;
      // 输出结果到LED或UART
    end
  endcase
end

我的建议:

BIST不要只做「通过/不通过」的二元判断。我会把测试结果量化,比如ADC的DNL、INL,或者链路的噪声系数。这样产线不仅能知道板子好坏,还能看出「哪块板子快坏了」——比如噪声系数从3.5dB漂到了4.2dB,虽然还在规格内,但已经是个预警信号了。

4.4 三种DFT方法的协同

实际量产中,这三种方法不是孤立的。我一般这样搭配:

  • 上电自检阶段:先跑BIST,快速筛掉「死板」——电源短路、时钟没起振、FPGA配置失败。这个阶段耗时约5秒。
  • 连接测试阶段:用边界扫描,检查BGA、连接器、电阻排的焊接质量。耗时约30秒。
  • 功能测试阶段:用测试点做信号质量验证——看眼图、测抖动、量幅值。这个阶段最耗时,但DFT做得好,可以大幅减少探针移动次数。

我记得有个项目,刚开始产线测试一片板子要8分钟。后来我重新规划了测试点布局,把BIST和边界扫描整合到一个测试序列里,时间压缩到了3分钟以内。良率也从92%提到了97%。说白了,DFT不是「额外工作」,而是「省时间的投资」。

总结一下我的经验:

  • 测试点:宁可多,不可少。多一个测试点,产线少一次飞线。
  • 边界扫描:别只当下载口用。它是最便宜的ICT(在线测试)替代方案。
  • 内建自测试:让板子自己说话。BIST跑得越快,产线效率越高。

嗯,DFT这部分就先聊到这儿。下一章咱们讲讲生产测试流程的搭建,那又是另一套学问了。