PoE上电前先查六组0Ω电阻

2026-10-241

一块 PoE 供电板,电源已经有了 53V,网络接口也焊好了,接下来是不是插上摄像头就行?

先别急。板上那几颗不起眼的 0Ω 电阻,可能决定它执行标准电阻检测、兼容旧式设备,还是进入芯片生产测试模式。电源做得再漂亮,装配选项选错,后面的调试也会走偏。

这次把检查范围收紧到 PD69101 周围的六组配置电阻,完成一套能读取实际 EDA 网表的装配审查程序。目标很具体——标准 AT 电流档、普通 LED 工作方式、Host 角色,只启用标准电阻检测。整个过程在主机上验证,不把配置检查当成整板通电合格证明。

图1 两个互斥0Ω电阻的连接示意

先看清每颗电阻连到哪里

从实际工程的 P2 页重新导出高清原理图,再把配置区单独截出来。每个输入都留了两个 0603 位置,一个接 GND,一个接 DVDD。这里的 DVDD 是芯片的 3.3V 数字电源域,不能和 53V 供电母线混为一谈。

图2 P2页六组互斥配置电阻的真实EDA导出局部

拿 CURRENT_SET 举例。R34 把它拉到 GND,R37 把它拉到 DVDD。

只装 R34,逻辑为 0;只装 R37,逻辑为 1。两颗都不装,这个外部配置没有定义电平;两颗都装,则形成 DVDD—R37—CUR_SET—R34—GND 的低阻通路。0Ω 电阻有实际阻值和额定电流,但它们并不因此成为合理的电源限流器。

检查导出的网表还能看到一个容易忽略的细节,这十二个位置均标为“加入 BOM”。这份信息表达的是工程中有哪些元件,不能直接当作某个装配版本的实装清单。工程提供了选择位置,也不等于作者真的把两边都焊了。交付装配时,要另外明确每一颗的 FIT 和 DNP,后者就是不装。

电流档位不能只看 AT 两个字

PD69101 数据手册表 3-2 将 AF/AT 与 CURRENT_SET 一起解释,两个输入不能分开凭名称猜。

AF/AT CURRENT_SET 手册中的电流档
0 0 标准 AF,Icut 350mA
1 0 标准 AT,Icut 600mA
1 1 高功率档,Icut 720mA
0 1 扩展高功率档,Icut 1000mA

这里列的是手册对应配置的 Icut,不能把它和瞬时限流阈值 Ilim、设备端可用功率混在一起。提高电流档也不会自动得到 IEEE 802.3bt 系统,网线、连接器、分级方式和保护都还在各自的约束里。

本文限定标准 AT 配置,因此选择 AF_AT=1、CURRENT_SET=0,对应装 R39、R34,R38、R37 不装。程序会拒绝与这个目标不同的档位;这表示“不符合本次配置”,并不表示所有其他档位都没有用途。

名叫 MODE_2 的网络接的是 MODE0

这是必须查真实引脚的一处。网表显示,U4 的 21 脚接项目网络 MODE_2,22 脚接 MODE_1;数据手册却把 21 脚定义为 MODE0、22 脚定义为 MODE1。

图3 U4的真实EDA引脚连接,MODE_2连21脚

网络名是设计者起的名字,引脚号才把它和芯片手册接起来。若把 MODE_2 理解成“另一个更高位”,后面即使算对二进制也没有意义。

手册表 3-3 的顺序是 MODE0、MODE1。00 为普通工作方式,LED0/LED1 用于状态指示;01 为串行监测;10 和 11 都是芯片生产测试模式。本文目标为 00,所以 MODE_2 对应的 R40 要装、R41 不装,MODE_1 对应的 R42 要装、R43 不装。

STD_DET/LEGACY 也有容易反着理解的语义。24 脚为 1 时只使用标准电阻检测;为 0 时还启用旧式、非标准负载检测。本文选择只做标准电阻检测,因此装 R47、DNP R46。手册提到的 19kΩ~26.5kΩ,是此器件检测有效负载时的接受范围,不是建议随手给普通设备并上一颗电阻就改成 PoE。

23 脚为 Host/Client,本文固定选择 Host,装 R45、DNP R44。于是六组选择可以收成一张表。

芯片输入 项目网络 装上 不装
CURRENT_SET,1脚,0 CUR_SET R34 R37
AF/AT,2脚,1 AF_AT R39 R38
MODE0,21脚,0 MODE_2 R40 R41
MODE1,22脚,0 MODE_1 R42 R43
Host/Client,23脚,1 H_C R45 R44
STD_DET,24脚,1 STD_LEG R47 R46

下面是同一工程的 PCB 顶层、底层低压侧,按相同顶视坐标展示,底层文字反向是这种观察方式的结果。图中没有把 DNP 焊盘删掉;焊盘要保留,装配清单负责告诉生产环节哪些位置留空。

图4 同版PCB低压侧顶层和底层,未改走线

让网表先证明自己还是这一版

装配审查不能只把十二个电阻编号写死,然后永远信任它们。换版后 R41 可能接到了别处,芯片引脚也可能调整。这里先做版本与连接绑定,再检查装配选择。

在嘉立创 EDA 专业版打开文末工程,进入原理图的“导出→网表文件”,类型选择“嘉立创EDA(专业版)(.enet)”,范围为 Board1 的 Schematic1。把下列完整代码保存为 poe_straps.py,使用 Python 3.10 或更新版本即可运行,无需额外依赖。

代码把三件事分开处理。bind 核对工程编号、U4 型号、六个真实引脚和十二颗电阻两端的网络;audit 要求每组恰好实装一颗,再检查其是否符合本次目标。最后的报告只写 six_straps_only,避免把局部通过读成整板通过。

"""PD69101 six-strap assembly review, v1.0.0. MIT license.

Python 3.10+, standard library only. Scope: the twelve specified straps.
Does not authorize powering or certify the complete PSE board.
"""
import argparse
import hashlib
import json
from pathlib import Path

PROJECT = "cc856e57f02b4916b03e796c38f60e3b"
# name, U4 pin, project net, low resistor, high resistor, target bit
GROUPS = (
    ("CURRENT_SET", "1", "CUR_SET", "R34", "R37", 0),
    ("AF_AT", "2", "AF_AT", "R38", "R39", 1),
    ("MODE0", "21", "MODE_2", "R40", "R41", 0),
    ("MODE1", "22", "MODE_1", "R42", "R43", 0),
    ("HOST", "23", "H_C", "R44", "R45", 1),
    ("STD_DET", "24", "STD_LEG", "R46", "R47", 1),
)
REFS = tuple(r for *_, lo, hi, bit in GROUPS for r in (lo, hi))
TARGET = {r: (r == (hi if bit else lo))
          for *_, lo, hi, bit in GROUPS for r in (lo, hi)}


def bind(netlist):
    if netlist.get("projectId") != PROJECT:
        raise ValueError("projectId differs; review a new engineering version")
    by_ref = {}
    for c in netlist["components"].values():
        ref = c["props"]["Designator"]
        if ref in by_ref:
            raise ValueError(f"duplicate designator {ref}")
        by_ref[ref] = c
    u4 = by_ref["U4"]
    if u4["props"].get("Manufacturer Part") != "PD69101ILQ-TR":
        raise ValueError("U4 part differs")
    for _, pin, net, lo, hi, _ in GROUPS:
        if u4["pinInfoMap"][pin]["net"] != net:
            raise ValueError(f"U4 pin {pin} differs")
        for ref, rail in ((lo, "GND"), (hi, "DVDD")):
            c = by_ref[ref]
            pins = c["pinInfoMap"]
            nets = {p["net"] for p in pins.values()}
            if len(pins) != 2 or nets != {rail, net}:
                raise ValueError(f"{ref} connectivity differs")
            if c["props"].get("Value", "").strip() not in ("0", "0R", "0Ω"):
                raise ValueError(f"{ref} is not a verified zero-ohm strap")
    return by_ref


def audit(population):
    if set(population) != set(REFS):
        raise ValueError("population must contain exactly the twelve straps")
    if any(type(v) is not bool for v in population.values()):
        raise ValueError("use JSON true/false, not strings or integers")
    errors, bits = [], {}
    for name, _, _, lo, hi, target in GROUPS:
        low, high = population[lo], population[hi]
        if low == high:
            errors.append(f"{name}: {'RAIL_SHORT' if low else 'FLOATING'}")
        else:
            bits[name] = int(high)
            if int(high) != target:
                errors.append(f"{name}: outside AT_LED_HOST_STANDARD policy")
    return {"scope": "six_straps_only", "pass": not errors,
            "bits": bits, "errors": errors}


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("netlist", type=Path)
    group = parser.add_mutually_exclusive_group()
    group.add_argument("--population", type=Path)
    group.add_argument("--literal-bom", action="store_true")
    args = parser.parse_args()
    raw = args.netlist.read_bytes()
    components = bind(json.loads(raw.decode("utf-8-sig")))
    if args.population:
        pop = json.loads(args.population.read_text(encoding="utf-8-sig"))
    elif args.literal_bom:
        pop = {r: components[r]["props"].get("Add into BOM") == "yes"
               for r in REFS}
    else:
        pop = TARGET.copy()
    report = audit(pop)
    report.update(version="1.0.0", netlist_sha256=hashlib.sha256(raw).hexdigest(),
                  fit=[r for r in REFS if pop[r]],
                  dnp=[r for r in REFS if not pop[r]])
    print(json.dumps(report, ensure_ascii=False, indent=2))
    raise SystemExit(0 if report["pass"] else 2)


if __name__ == "__main__":
    main()

将导出的文件名作为第一个参数,例如:

python poe_straps.py Netlist_Schematic1_2026-10-24.enet
python poe_straps.py Netlist_Schematic1_2026-10-24.enet --literal-bom

第一条检查代码中明确列出的目标装配。第二条做一个反例,把网表的“加入 BOM”字段按字面当成实装。后者返回退出码 2,并报告六组 RAIL_SHORT,正好说明工程 BOM 与具体装配版本之间少不了一道转换。

要检查自己的清单,可用 --population assembly.json。JSON 必须完整列出这十二个编号,值严格使用 true 或 false。漏项、额外拼错的编号、字符串“false”以及整数 0/1 都会拒绝;不能让工具把“没填”默认为“不装”。

{
  "R34": true,  "R37": false,
  "R38": false, "R39": true,
  "R40": true,  "R41": false,
  "R42": true,  "R43": false,
  "R44": false, "R45": true,
  "R46": false, "R47": true
}

把十二个位置的全部组合跑一遍

十二个位置各有装、不装两种状态,共 4096 种组合。测试使用实际网表里的电阻端点建立独立连通图,检查 DVDD 是否能通过实装电阻连到 GND,以及配置网络是否与两条电源轨都断开,再与审查程序比较。

结果中,3367 种组合至少有一组形成电源轨低阻通路;排除这些后,665 种组合仍有配置悬空;余下 64 种组合六组电平都有定义。其中只有 1 种符合本文选择的 AT、普通 LED、Host、标准电阻检测策略。其余 63 种需要按各自目标解释,不能统称为坏配置。

图5 根据本机实际日志排版的验证结果,不是通电测试

同时执行了输入类型检查,以及工程编号、U4 引脚网络、电阻网络、阻值和重复位号的故障注入,4 项测试通过。目标配置返回退出码 0,按字面全装的反例返回退出码 2。报告记录网表 SHA-256,便于确认复查的仍是同一份输入。

这份程序适合放在导出装配文件之后、交给生产之前。它能拦住指定十二个位置里的误装、漏装和目标模式不一致;不能证明实物阻值正确,也没有覆盖 LED/串行接口路由、PoE 供电线对、网络变压器、电源完整性或市电隔离。涉及这些部分的整板调试仍要独立检查。尤其不要因为看到 pass=true 就直接接上市电或待保护的设备。

把这一层边界讲清,0Ω 电阻就不再只是图上的几个占位符,而是一份能随工程版本复核的装配决定。

资料与验证范围

电路与 PCB 依据 magee 的“多输入POE(PSE)电源”,OpenAtom OHL 1.0,工程更新于 2026-03-04,图框 V1.0。工程地址 https://oshwhub.com/magee/poe_pse_sc8708_tmi7604 。图2~4从同版实际 EDA 重新高清导出,仅裁剪、亮度校正与轻度锐化,未改走线;图1为连接示意,图5为真实主机日志排版。本文装配审查代码独立实现,版本1.0.0,按 MIT 许可提供,完整可运行源码已嵌入正文。

引脚和模式依据 Microchip《PD69101 Datasheet》DS00004280A,第17~18页,官方入口 https://www.microchip.com/en-us/product/PD69101 。截至2026-10-24,该器件官方状态为“不推荐用于新设计”,本篇面向现有工程维护及装配审查方法;新产品应重新选择在产器件并核对设计。本文完成网表检查和主机测试,未做实体通电、IEEE一致性或安规认证。

技术交流,欢迎关注微信公众号:美男子玩编程。

创作许可协议

本项目采用 CC BY(署名) 进行许可。

评论(0)
- 没有更多了 -