Skip module-die and truncated QFN pintable false PE-BOM hits (2.63.3).
WROOM lands are not the ESP32 die table (U11). QFN-48 pads 25–48 are not extras when extraction stopped at 1–24 (U12). VQFN is the QFN family (U19 24-QFN 4×4). Real extra signal pads still ERROR.
This commit is contained in:
@@ -277,3 +277,247 @@ def test_lib_vs_embedded_pcb_is_separate_finding(tmp_path: Path):
|
||||
if f.rule_id == "PE-BOM-011"
|
||||
]
|
||||
assert any("embedded" in f.finding.lower() or "PCB" in f.finding for f in findings)
|
||||
|
||||
|
||||
def _ic(
|
||||
ref: str,
|
||||
mpn: str,
|
||||
footprint: str,
|
||||
n_sch: int,
|
||||
) -> Component:
|
||||
return Component(
|
||||
reference=ref, value=mpn, footprint=footprint,
|
||||
component_type=ComponentType.IC, mpn=mpn,
|
||||
pins={str(i): "SIG" for i in range(1, n_sch + 1)},
|
||||
)
|
||||
|
||||
|
||||
def test_wroom_module_pads_vs_die_pintable_not_bom_011():
|
||||
"""U11: WROOM land ≠ ESP32 die 61-pin pintable."""
|
||||
cons = ComponentConstraints(
|
||||
mpn="ESP32-S31-WROOM-3",
|
||||
package_info=PackageInfo(
|
||||
base_family="ESP", package="QFN-56", pin_count=61,
|
||||
),
|
||||
pintable=[Pin(number=str(i), name=f"P{i}") for i in range(1, 62)],
|
||||
absolute_maximum_ratings=[],
|
||||
rules=[],
|
||||
)
|
||||
pads = [LayoutPad(number=str(i), x=0, y=0, net="SIG") for i in range(1, 100)]
|
||||
graph = DesignGraph(
|
||||
components={
|
||||
"U11": _ic(
|
||||
"U11", "ESP32-S31-WROOM-3",
|
||||
"MIKILAB_ESP32_S31_WROOM_3:ESP32-S31-WROOM-3", 41,
|
||||
),
|
||||
},
|
||||
)
|
||||
layout = LayoutGraph(
|
||||
footprints={
|
||||
"U11": LayoutFootprint(
|
||||
reference="U11",
|
||||
footprint="MIKILAB_ESP32_S31_WROOM_3:ESP32-S31-WROOM-3",
|
||||
x=0, y=0, pads=pads,
|
||||
),
|
||||
},
|
||||
)
|
||||
ids = _ids(check_bom_pcb_datasheet(graph, {"ESP32-S31-WROOM-3": cons}, layout))
|
||||
assert "PE-BOM-011" not in ids
|
||||
|
||||
|
||||
def test_wroom_missing_die_pin_still_fires():
|
||||
cons = ComponentConstraints(
|
||||
mpn="ESP32-S31-WROOM-3",
|
||||
package_info=PackageInfo(
|
||||
base_family="ESP", package="QFN-56", pin_count=61,
|
||||
),
|
||||
pintable=[Pin(number=str(i), name=f"P{i}") for i in range(1, 62)],
|
||||
absolute_maximum_ratings=[],
|
||||
rules=[],
|
||||
)
|
||||
pads = [LayoutPad(number=str(i), x=0, y=0, net="SIG") for i in range(1, 60)]
|
||||
graph = DesignGraph(
|
||||
components={
|
||||
"U11": _ic(
|
||||
"U11", "ESP32-S31-WROOM-3",
|
||||
"MIKILAB_ESP32_S31_WROOM_3:ESP32-S31-WROOM-3", 40,
|
||||
),
|
||||
},
|
||||
)
|
||||
layout = LayoutGraph(
|
||||
footprints={
|
||||
"U11": LayoutFootprint(
|
||||
reference="U11",
|
||||
footprint="MIKILAB_ESP32_S31_WROOM_3:ESP32-S31-WROOM-3",
|
||||
x=0, y=0, pads=pads,
|
||||
),
|
||||
},
|
||||
)
|
||||
assert "PE-BOM-011" in _ids(
|
||||
check_bom_pcb_datasheet(graph, {"ESP32-S31-WROOM-3": cons}, layout),
|
||||
)
|
||||
|
||||
|
||||
def test_qfn48_truncated_pintable_24_not_extra_error():
|
||||
"""U12: pintable 1–24 vs QFN-48 lands is extraction, not a wrong footprint."""
|
||||
cons = ComponentConstraints(
|
||||
mpn="Si4684-A10-GM",
|
||||
package_info=PackageInfo(
|
||||
base_family="Skyworks", package="QFN-48", pin_count=24,
|
||||
),
|
||||
pintable=[Pin(number=str(i), name=f"P{i}") for i in range(1, 25)],
|
||||
absolute_maximum_ratings=[],
|
||||
rules=[],
|
||||
)
|
||||
pads = [LayoutPad(number=str(i), x=0, y=0, net="SIG") for i in range(1, 49)]
|
||||
pads.append(LayoutPad(number="49", x=0, y=0, net="GND", pinfunction="EP"))
|
||||
graph = DesignGraph(
|
||||
components={
|
||||
"U12": _ic(
|
||||
"U12", "Si4684-A10-GM",
|
||||
"Package_DFN_QFN:QFN-48-1EP_7x7mm_P0.5mm_EP5.3x5.3mm_ThermalVias",
|
||||
48,
|
||||
),
|
||||
},
|
||||
)
|
||||
layout = LayoutGraph(
|
||||
footprints={
|
||||
"U12": LayoutFootprint(
|
||||
reference="U12",
|
||||
footprint="Package_DFN_QFN:QFN-48-1EP_7x7mm_P0.5mm_EP5.3x5.3mm_ThermalVias",
|
||||
x=0, y=0, pads=pads,
|
||||
),
|
||||
},
|
||||
)
|
||||
assert "PE-BOM-011" not in _ids(
|
||||
check_bom_pcb_datasheet(graph, {"Si4684-A10-GM": cons}, layout),
|
||||
)
|
||||
|
||||
|
||||
def test_qfn24_extra_pad_30_still_fires():
|
||||
cons = ComponentConstraints(
|
||||
mpn="IC24",
|
||||
package_info=PackageInfo(base_family="QFN", package="QFN-24", pin_count=24),
|
||||
pintable=[Pin(number=str(i), name=f"P{i}") for i in range(1, 25)],
|
||||
absolute_maximum_ratings=[],
|
||||
rules=[],
|
||||
)
|
||||
pads = [LayoutPad(number=str(i), x=0, y=0, net="SIG") for i in range(1, 25)]
|
||||
pads.append(LayoutPad(number="30", x=1, y=0, net="SIG"))
|
||||
graph = DesignGraph(
|
||||
components={"U1": _ic("U1", "IC24", "Package_DFN_QFN:QFN-24-1EP", 24)},
|
||||
)
|
||||
layout = LayoutGraph(
|
||||
footprints={
|
||||
"U1": LayoutFootprint(
|
||||
reference="U1", footprint="Package_DFN_QFN:QFN-24-1EP",
|
||||
x=0, y=0, pads=pads,
|
||||
),
|
||||
},
|
||||
)
|
||||
assert "PE-BOM-011" in _ids(
|
||||
check_bom_pcb_datasheet(graph, {"IC24": cons}, layout),
|
||||
)
|
||||
|
||||
|
||||
def test_qfn_vs_vqfn_same_24_qfn_land_not_bom_010():
|
||||
"""U19: datasheet QFN vs CAD VQFN-24 4×4 is the same land family."""
|
||||
cons = ComponentConstraints(
|
||||
mpn="LAN8720A",
|
||||
package_info=PackageInfo(
|
||||
base_family="SMS", package="QFN-24", pin_count=24,
|
||||
),
|
||||
pintable=[Pin(number=str(i), name=f"P{i}") for i in range(1, 25)],
|
||||
absolute_maximum_ratings=[],
|
||||
rules=[],
|
||||
)
|
||||
pads = [LayoutPad(number=str(i), x=0, y=0, net="SIG") for i in range(1, 25)]
|
||||
pads.append(LayoutPad(number="25", x=0, y=0, net="GND", pinfunction="EP"))
|
||||
graph = DesignGraph(
|
||||
components={
|
||||
"U19": _ic(
|
||||
"U19", "LAN8720A",
|
||||
"Package_DFN_QFN:VQFN-24-1EP_4x4mm_P0.5mm_EP2.5x2.5mm_ThermalVias",
|
||||
24,
|
||||
),
|
||||
},
|
||||
schematic_fields={
|
||||
"U19": {
|
||||
"footprint": (
|
||||
"Package_DFN_QFN:VQFN-24-1EP_4x4mm_P0.5mm_EP2.5x2.5mm_ThermalVias"
|
||||
),
|
||||
},
|
||||
},
|
||||
bom_fields={"U19": {"footprint": "VQFN-24"}},
|
||||
)
|
||||
layout = LayoutGraph(
|
||||
footprints={
|
||||
"U19": LayoutFootprint(
|
||||
reference="U19",
|
||||
footprint=(
|
||||
"Package_DFN_QFN:VQFN-24-1EP_4x4mm_P0.5mm_EP2.5x2.5mm_ThermalVias"
|
||||
),
|
||||
x=0, y=0, pads=pads,
|
||||
),
|
||||
},
|
||||
)
|
||||
ids = _ids(check_bom_pcb_datasheet(graph, {"LAN8720A": cons}, layout))
|
||||
assert "PE-BOM-010" not in ids
|
||||
assert "PE-BOM-011" not in ids
|
||||
|
||||
|
||||
def test_hubaudio_u11_u12_u19_software_not_error():
|
||||
if not _HUB_PCB.is_file():
|
||||
return
|
||||
layout = parse_kicad_pcb(_HUB_PCB)
|
||||
slim = LayoutGraph(
|
||||
footprints={k: layout.footprints[k] for k in ("U11", "U12", "U19")
|
||||
if k in layout.footprints},
|
||||
)
|
||||
graph = DesignGraph(
|
||||
components={
|
||||
"U11": _ic(
|
||||
"U11", "ESP32-S31-WROOM-3",
|
||||
"MIKILAB_ESP32_S31_WROOM_3:ESP32-S31-WROOM-3", 61,
|
||||
),
|
||||
"U12": _ic(
|
||||
"U12", "Si4684-A10-GM",
|
||||
"Package_DFN_QFN:QFN-48-1EP_7x7mm_P0.5mm_EP5.3x5.3mm_ThermalVias",
|
||||
48,
|
||||
),
|
||||
"U19": _ic(
|
||||
"U19", "LAN8720A",
|
||||
"Package_DFN_QFN:VQFN-24-1EP_4x4mm_P0.5mm_EP2.5x2.5mm_ThermalVias",
|
||||
24,
|
||||
),
|
||||
},
|
||||
)
|
||||
cmap = {
|
||||
"ESP32-S31-WROOM-3": ComponentConstraints(
|
||||
mpn="ESP32-S31-WROOM-3",
|
||||
package_info=PackageInfo(base_family="ESP", package="QFN-56", pin_count=61),
|
||||
pintable=[Pin(number=str(i), name=f"P{i}") for i in range(1, 62)],
|
||||
absolute_maximum_ratings=[],
|
||||
rules=[],
|
||||
),
|
||||
"Si4684-A10-GM": ComponentConstraints(
|
||||
mpn="Si4684-A10-GM",
|
||||
package_info=PackageInfo(base_family="Sky", package="QFN-48", pin_count=24),
|
||||
pintable=[Pin(number=str(i), name=f"P{i}") for i in range(1, 25)],
|
||||
absolute_maximum_ratings=[],
|
||||
rules=[],
|
||||
),
|
||||
"LAN8720A": ComponentConstraints(
|
||||
mpn="LAN8720A",
|
||||
package_info=PackageInfo(base_family="SMS", package="QFN-24", pin_count=24),
|
||||
pintable=[Pin(number=str(i), name=f"P{i}") for i in range(1, 25)],
|
||||
absolute_maximum_ratings=[],
|
||||
rules=[],
|
||||
),
|
||||
}
|
||||
findings = check_bom_pcb_datasheet(graph, cmap, slim)
|
||||
err = [
|
||||
f for f in findings
|
||||
if f.rule_id in {"PE-BOM-010", "PE-BOM-011"} and f.status == "ERROR"
|
||||
]
|
||||
assert err == [], [f.finding for f in err]
|
||||
|
||||
Reference in New Issue
Block a user