Skip to content

SYN-40 - Two independent USB pairs with declared length and skew budgets - #148

Open
JeffMboya wants to merge 14 commits into
absmach:mainfrom
JeffMboya:SYN-40-dual-usb
Open

JeffMboya wants to merge 14 commits into
absmach:mainfrom
JeffMboya:SYN-40-dual-usb

Conversation

@JeffMboya

@JeffMboya JeffMboya commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

What type of PR is this?

This is a feature.

What does this do?

Adds qualification/class-c/dual-usb-compute: four declared pairs, two max_skew classes, checked on routed copper.

Which issue(s) does this PR fix/relate to?

Related Issue #40. Uncovered #146 and #157.

Have you included tests for your changes?

No. The board is data; E-SYNTH-DRC-014 and -019 check its budgets.

Did you document any new/modified features?

Yes. README.md carries the stackup, pair table, netclasses and connector pinouts.

Notes

Routed copper is rejected: 58 tracks under 0.127 mm, because rp2350's 0.4 mm QFN cannot escape.

@JeffMboya

JeffMboya commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor Author

Rendered from this branch with KiCad 10.0.6.

PCB, 3D top view
dual_usb_pcb_3d_top

Schematic
dual_usb_schematic

@SammyOina

Copy link
Copy Markdown
Collaborator

[P1] Add reproducible qualification evidence before treating this as the Class-C case-3 result.

The PR adds the Synth source and registry part, but the current CI routability gate only runs the generic unrouted-net regression test; it does not export or route this board, run DRC, or verify the declared pair and group skew budgets. There is also no routed PCB or measured skew report in the PR. Issue #40 requires production-reviewable evidence and expert sign-off, so please add a reproducible qualification step and its resulting artifacts, or narrow the PR claim to adding the input fixture only.

@SammyOina

Copy link
Copy Markdown
Collaborator

[P1] The claimed USB 3.x interface is not actually implemented on this board. The SuperSpeed nets from J2 terminate at the generic J3 expansion header (dual_usb_compute.synth:243-249); neither RP2350 provides a USB 3.x SuperSpeed PHY/controller, and no other USB 3.x device is present. This can demonstrate/export differential-pair constraints, but it cannot qualify a working USB 3.x interface for #40 case 3. Please either add the required USB 3.x endpoint/PHY and route it, or narrow the PR claim to a differential-pair routing fixture and explain how the external endpoint is part of the qualification.

@JeffMboya

Copy link
Copy Markdown
Contributor Author

Both P1s taken, and you were right on both counts. a633179.

The USB 3.x claim is withdrawn

Your reading of dual_usb_compute.synth:243-249 is correct and the header was
wrong. Neither RP2350 has a SuperSpeed PHY — the die carries a USB 1.1/2.0
controller — and there is no hub, redriver or host controller on the board to
terminate the lanes, so what the SuperSpeed pairs have is a header, not an
endpoint.

I looked at adding one before narrowing, because an endpoint would have been
the better answer. KiCad 10 does ship real SuperSpeed devices — TUSB8041,
TUSB564, GL3224-ONY, MS2130 — and a USB 3.0 hub is the topology that
would make this board honest: upstream on the C port, downstream on the A
port. It needs a 24-pin Type-C receptacle part (the registry's
usb_c_receptacle is the 12-pin HRO, which has no SuperSpeed pins at all), a
64-pin hub part I cannot verify against a datasheet I do not have, and a
0.5 mm VQFN whose escape needs the via-in-pad path on #155. That is a
different board, and shipping an unverified 64-pin part to claim a checkbox is
the thing #51 exists to stop.

So the source says which of the two each pair is:

The two SuperSpeed pairs are not. No device on this board speaks USB 3.x:
the RP2350 has a USB 1.1/2.0 controller and no SuperSpeed PHY, and there is
no hub, redriver or host controller here to terminate the lanes. They are
routed as a controlled-impedance pass-through from the receptacle to the
expansion header, which is what a lane carried across a connector actually
is, and the endpoint is whatever the header is mated to.

The two USB 2.0 pairs are unaffected: each ends at an RP2350's native USB
pins, so each is a complete interface with a real endpoint and a budget that
routed copper is measured against. The README's opening sentence now says
where the lanes go instead of what rate they would run at, and neither file
claims a #40 case any more.

The measured run, and it does not pass

Your first P1 asked for reproducible evidence or a narrower claim. Here is the
evidence, on a633179 against main at 2a8a6b4:

synth export-kicad qualification/class-c/dual-usb-compute/dual_usb_compute.synth \
  --out <dir> --router kicad-routing-tools
Nets closed 37 of 38
Open net_9 at U2.11, reaching 1 of 32 pads
Routed copper 1325.0 mm over 900 segments and 59 vias
Tracks below the 0.127 mm floor 58
Vias below the floor 0
Via-in-pad 0
kicad-cli pcb drc 58 errors, all track_width, 9 warnings
Engine verdict rejected
synth export-kicad exit 1, "the routed board failed independent validation"

The 58 widths are 0.0889 mm (37 of them), 0.0998 mm (12), 0.1111 mm (8) and
0.0999 mm (1), against the 0.127 mm jlcpcb standard minimum.

The cause is the package, not the router. Both MCUs are rp2350 in a QFN-60
on 0.4 mm pitch, which leaves 0.200 mm between pads where a minimum track
plus its clearance needs 0.254 mm. There is no legal way out of those pads at
this tier, and the router takes an illegal one rather than stopping. Synth
then catches it — the independent validation rejects the copper and the
command exits 1 — so the toolchain behaves correctly; the board is simply not
buildable on the standard floor.

The remedy is the via-in-pad path: requires via_in_pad (#155) plus a tier
that fills them, which is what #171's BGA board does and measures. That is a
change to this board rather than a note on it, and it is not in this PR.

So what this PR claims now

A differential-pair and skew-budget fixture, in the language and in the
checks: four pairs declared with polarity, impedance and intra-pair budgets,
two netclass group budgets, all five verified against routed copper by
E-SYNTH-DRC-014 and -019. Two of the four pairs are complete interfaces;
two are a controlled-impedance pass-through, and the source says so. The
routed result is rejected at the standard floor for the reason above, and the
README reports it rather than claiming otherwise.

It does not claim #40 case 3. Case 3 wants technology-specific evidence for a
working high-speed interface, and the board with that is #171 — an iCE40
driving HDMI, where the transmitter is on the board.

@JeffMboya JeffMboya changed the title SYN-40 - Class C case 3: dual-USB board with length and skew budgets SYN-40 - Two independent USB pairs with declared length and skew budgets Oct 17, 2026

@rodneyosodo rodneyosodo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@SammyOina

Copy link
Copy Markdown
Collaborator

I found three issues that need to be addressed before this should be treated as complete:

  1. [P1] J2 VBUS is unconnected. The USB 3.0 Type-A receptacle has no connect J2.vbus statement. The board therefore cannot power a connected USB device, so this is not a functional USB host port. Connect it to an appropriately protected/sourced rail, or explicitly document that J2 is only a passive signal fixture and remove the functional-port framing.

  2. [P1] The USB roles and connector configuration are inconsistent. J1 is labeled as a host port and U2 as host, but the two 5.1 kΩ CC resistors pull down to ground, configuring the USB-C receptacle as a sink/device. J2 is a host-style Type-A receptacle while U4 is labeled as a device. The connector roles, CC configuration, VBUS direction, and RP2350 roles need to be made electrically consistent.

  3. [P1] This should not be accepted as a production-reviewable Class-C qualification in its current form. The measured routed result has one open net, 58 sub-minimum-width tracks, and is rejected by independent DRC. The SuperSpeed pairs also terminate at an expansion header with no on-board USB 3.x endpoint, so they demonstrate constraint syntax/routing only, not a working high-speed interface. Issue Class C: verify dense/high-speed constraints and exported output #40 requires technology-specific evidence, exported-output validity, and expert sign-off. If this remains a routing-language fixture, please narrow and label the board accordingly; otherwise, add a valid endpoint, a passing routed artifact, the relevant export/DRC evidence, and the required human review before treating the Class-C case as satisfied.

JeffMboya added a commit to JeffMboya/synth that referenced this pull request Oct 21, 2026

@rodneyosodo rodneyosodo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed delta: rebase only. LGTM.

JeffMboya added a commit to JeffMboya/synth that referenced this pull request Oct 21, 2026
@JeffMboya

Copy link
Copy Markdown
Contributor Author

J1 relabelled a sink, U2 a device, in 1cf56d3. J2.vbus held: connecting it moves the measured outline.

@JeffMboya

JeffMboya commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor Author

If this remains a routing-language fixture, please narrow and label the board accordingly; otherwise, add a valid endpoint […] before treating the Class-C case as satisfied.

@SammyOina narrowed: J2 is a lane fixture, VBUS deliberately unconnected, functional-port framing removed. Outline unchanged. f642f81.

JeffMboya added a commit to JeffMboya/synth that referenced this pull request Oct 21, 2026
JeffMboya added a commit to JeffMboya/synth that referenced this pull request Oct 21, 2026
JeffMboya added a commit to JeffMboya/synth that referenced this pull request Oct 21, 2026
JeffMboya added a commit to JeffMboya/synth that referenced this pull request Oct 21, 2026
@SammyOina

SammyOina commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator

Visual placement review — the generated result still needs engineering work

I inspected the attached PCB and schematic renders as a human placement review. The board is not yet at a professional Class-C layout standard, even treating it as a routing fixture:

[P1] The RP2350 QFN escape strategy is not viable at the declared manufacturing floor. In the PCB render, both fine-pitch QFNs are placed as if ordinary breakout routing will work, but the reported result contains 58 tracks below the 0.127 mm minimum and is rejected by DRC. This is not just a router-quality problem. Please make Synth recognize the package escape constraint and either require a supported via-in-pad/filled-via strategy, use a package with a manufacturable escape, or fail placement before producing an apparently finished board. A Class-C result should not visually present an unbuildable escape as final.

[P1] Decoupling placement is not pin-specific enough. The capacitors around U2 and U4 are distributed around the package rather than visibly locked to the relevant power pins and return vias. For a dense digital device, generic near-component placement is insufficient: each rail capacitor needs a short, deterministic power/ground path and an explicit placement rule. Please extend Synth’s placement model to bind each decoupler to its target pin/rail, reserve the return-via location, and verify the resulting distance/loop geometry.

[P2] The placement is too sparse and lacks a convincing mechanical plan. Large unused areas remain between the connectors, MCUs, flash, regulator, and passives, while the long expansion header is pushed against the left edge. There is no visible mounting-hole, connector insertion, keepout, or assembly-access strategy. A human-quality final board should define the mechanical envelope first, constrain edge connectors and headers to it, then compact the power and high-speed regions around their real interfaces.

[P2] The high-speed connector regions need deliberate corridor and return-path planning. J1, J2, U2, and U4 are placed as isolated islands without a visible pair corridor, reference-plane strategy, or controlled transition/via plan. The SuperSpeed fixture should at least reserve a continuous route/return corridor from J2 to J3, and each USB 2.0 pair should have a defined path from connector to MCU. These constraints should be represented in Synth rather than left to a later router pass.

[P2] Regenerate and align the schematic presentation with the current design. The attached schematic still visually presents the old host/USB-port framing, while the current source says J2 is a non-functional lane fixture and the USB-C side is a device/sink. The final review artifact should make those roles unambiguous and should not require reconciling an old render with the current source.

The PR must deliver a complete, manufacturable Class-C design with valid package escape, pin-specific decoupling, mechanical constraints, controlled high-speed corridors, and the corresponding qualification evidence. If Synth cannot produce that result, Synth must be improved and the board regenerated; relabelling the output as a routing fixture or narrowing the qualification claim is not an acceptable resolution.

Two RP2350s on six layers, each on its own native USB, each pair at 90 ohm
with `max_skew 0.15mm` and `couple tight`, and `match_length 0.5mm` on the
USB class holding all four nets to one length. Two independent pairs on one
board is what case 3 asks about.

Adapted from the board in absmach#75, whose header carried a STATED LIMITATION
saying SynthSpec had no length-matching or skew syntax so these budgets
could not be declared. They can now, and these are the budgets that
limitation stood in for.

Two substitutions, both forced. The second endpoint is an RP2350 rather than
the ESP32-C3 the design was written around: that part names a symbol and
footprint absent from KiCad 10 and declares USB on two pins the module does
not have (absmach#146), so a board using it cannot export. And the two keepouts are
gone — a declared keepout reaches no exported board (absmach#142), and even when it
does a KiCad keepout is unconditional and would forbid the pair it protects.

What the README says plainly is where the budgets stop. Neither reaches
KiCad (absmach#147) and neither is measured in this build, so the board states them
and nothing yet holds it to them.
Swapping the second endpoint left a group called ESP32-C3 RADIO holding an
RP2350, which the rendered schematic showed plainly. The two MCU groups are
now HOST and DEVICE, which also distinguishes them from each other.
Three netclasses were declared and no net joined any of them, so
`match_length 0.5mm` bounded nothing at all. A `netclass` block assigns no
nets — they join through `class "NAME"` on a `connect` — and without that a
class is inert and reads as satisfied, which is the trap absmach#129 exists for.

Writing the spec sheet is what caught it: every class showed one occurrence
in the source, its own declaration.

Exported net classes now carry USB 4 nets, QSPI 6, PWR 1.
Seven tables with their columns computed rather than hand-padded: board
parameters, the eleven-layer stackup, the netclasses with their member
counts, the pairs with their budgets, the notable parts, what absmach#40 case 3
asks against what the board answers, and the limitations with their issues.

Every figure is taken from the board or its export and checked against
them: 28 components, 38 nets, 21 passives, USB carrying four nets, an
outline the parts fill 84% x 53% of.
Both restated what the PR description and the issues already carry. The
spec sheet is now the board's parameters and nothing else.
The PR description carries it, and a spec sheet is the board's parameters.
Which issue case a board answers belongs to the PR and the issue, not to
the board's own spec sheet.
No issue or PR references, and no commentary on the EDA language's
semantics. What a reader needs is the board's parameters, its stackup, the
constraints each class and pair carries, and the parts.
absmach#40 case 3 names PCIe, USB 3.x and HDMI because those are the rates where
skew and length budgets bind. This board declared 0.15 mm budgets on the
RP2350's native USB, which is USB 1.1 full speed at 12 Mb/s — budgets with
nothing to constrain.

The device port is now a USB 3.0 Type-A receptacle. Its two SuperSpeed
lanes run at 5 Gb/s with their own class: 0.15 mm track, 0.2 mm match
length, 90 ohm, 0.1 mm intra-pair skew. At FR4 velocity that is about
0.7 ps, which is a budget that means something.

The lanes leave through the expansion header rather than stopping at the
receptacle, because a pair that ends nowhere is neither routed nor
measurable.

`usb3_a_receptacle` is a new registry part: ten pins checked one by one
against Connector:USB3_A and the Wuerth 692122030100 footprint, ten symbol
pins against ten pads, numbers 1-9 plus SH.

The board is 64.3 mm square now rather than 83.4 x 89.9, and the parts fill
80% x 76% of it.
…ecks them

The board declared `match_length` on its two differential classes, an
attribute that no longer exists: absmach#145 closed in favour of `netclass
{ max_skew }`, which says the same thing — the spread across a class's
members, longest minus shortest — and is measured against routed copper by
E-SYNTH-DRC-019.

So the budgets are the same numbers, 0.2 mm across the four SuperSpeed nets
and 0.5 mm across the four USB 2.0 nets, and they are now checked rather
than only preserved into the exported net classes. That is the difference
between declaring a constraint and having one.

Both senses of the word are on this board and they are not the same budget:
on a `diff_pair` it bounds that pair's own two halves (E-SYNTH-DRC-014), on
a `netclass` it bounds the class against itself (E-SYNTH-DRC-019). The
source and the README both say which is which.
…ground

`usb3_a_receptacle` declares `drain` and `shield`, and this board connected
neither. A SuperSpeed port whose drain wire and connector shell float has no
defined return for either, which on a 5 Gb/s interface makes the shell an
antenna rather than a shield.

Both now go to board ground. That is the choice this board had already made
everywhere else — there is no separate chassis net to isolate them to — so
tying them is the design rather than a default. Leaving them out was a
decision by omission.

Validates with zero errors.
The header claimed absmach#40 case 3, "PCIe, USB 3.x, or HDMI-class differential
interface". Two of the four pairs on this board do not support that claim.

The USB 2.0 pairs do. Each ends at an RP2350's native USB device pins, so
each is a complete interface with a real endpoint, a 90 ohm geometry and an
intra-pair budget that routed copper is measured against.

The SuperSpeed pairs end at the expansion header. Nothing on the board
speaks USB 3.x: the RP2350 carries a USB 1.1/2.0 controller and no
SuperSpeed PHY, and there is no hub, redriver or host controller here to
terminate the lanes. Routing them to a header is the right thing to do with
them -- a pair that stops at the receptacle is neither routed nor
measurable -- but it makes them evidence about pair routing, polarity,
spacing and skew, not evidence of a working USB 3.x interface.

So the source says which of the two each pair is, and the README's opening
sentence says where the lanes go instead of what rate they would run at.
Neither file claims a case any more; what the board is for belongs in the
pull request, and what it is belongs here.
Three labels asserted roles no component on the board supports.

"USB-C HOST PORT" was the group where VBUS enters, passes through the
polyfuse and feeds the regulator, and where both CC lines carry a 5.1k Rd. A
board that draws its power from a port and advertises Rd on CC is a sink. The
resistors were right and the label was wrong, which is the more dangerous way
round: a reviewer reading the label would have gone looking for the missing
Rp.

"RP2350 HOST" was the group whose MCU terminates J1's pair on its native USB
device pins -- as this file's own header says, each pair "ends at an RP2350's
native USB device pins". U2 is the device this board presents.

What is left is named rather than papered over. A Type-A receptacle is a
host-side connector and the pair behind J2 ends at U4's device pins, so the
port cannot talk to whatever is plugged into it whatever the silkscreen says.
Fixing that is a connector or a controller decision, not a wiring one, and it
is the open question on absmach#40 case 3 -- so the source now says so at the group
it applies to.

No electrical change: the diagnostic set is identical, and `synth place`
returns the same 64.85 x 64.31 mm outline component for component, so no
measured figure in the README moves.
The group was "USB 3.0 PORT" and J2's VBUS was unconnected, which read as an
oversight on a functional port. It is not a port. A Type-A receptacle is a
host-side connector and the USB 2.0 pair behind it ends at U4's native device
pins, so nothing on this board can host what is plugged into it.

So the framing goes rather than the wiring. J2 carries one USB 2.0 pair to U4
and two SuperSpeed lanes to the expansion header, and that is the whole of
what it is evidence for.

VBUS stays unconnected, now as the stated decision. Feeding it would make the
receptacle able to power a device the board still could not talk to, which is
a worse claim than making none. A real port needs a host controller, which is
silicon this board does not have and the open question on absmach#40 case 3.

No electrical change: the placer returns the same 64.85 x 64.31 mm outline.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants