Commit Graph

6 Commits

Author SHA1 Message Date
onur 791ca5c9fa Restack the generator and source board to eight layers, matching the deliverable
The routed deliverable has always been eight layers (JLC08161H-3313), but
generate_pcb.py still emitted ten and hardware/board.kicad_pcb was itself still
a ten-layer board. Source and generator agreed with each other and disagreed
with what is actually being fabricated, so running the documented regeneration
flow would have silently replaced the eight-layer design with a conflicting
ten-layer one and destroyed the routing.

generate_pcb.py now builds the real stack: SetCopperLayerCount(8), no L8_PWR /
L9_SIG, and the STACKUP string taken verbatim from board_routed.kicad_pcb - the
two are now byte-identical. Silkscreen reads JLC08161H-3313 8L instead of
JLC10161H 10L, and the title block follows.

The zone layout follows the same correction. With only one dedicated power
plane there is no third plane for the two big FPGA I/O rails, so they are
carried as islands on the routing layers that have room: VCC1V8 on L6 and
VCC3V3 on B.Cu, replacing the ten-layer arrangement of a VCC3V3 background on
L8 and a board-wide GND pour on B.Cu. The regenerated board now reproduces the
routed board's 26 copper zones exactly (the 27th, the F.Cu RF ground pour, is
added later by finalize_routing).

Also drops the In7_Cu/In8_Cu remnants from finalize_routing's RF_NO_DIGITAL
layer set and route_local_power's RF_REGION_LAYERS - those layers do not exist
on this board, so they were dead bits in a layer mask - and corrects the
JLC10161H reference in board.kicad_dru.

The placement check now reports 21 isolated_copper warnings rather than 17.
That is expected and explained in README.md: on an unrouted board the I/O-rail
islands on L6 and B.Cu have nothing joining them yet. The routed board still
reports zero.

Verified: regenerated board is 8 layers with a stackup identical to the routed
board, 312 footprints (311 + R108), TEMP keepouts at their corrected extents.
design_data assertions pass, ERC 0/0, routed board still 0 DRC violations,
0 unconnected, every net one copper group, parity unchanged at 402.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012KaTmCCxCEW4awsmXRNT1d
2026-09-01 13:26:37 +03:00
onur 4fa38e35bd Fix the RF launch: relieve the planes under J2 and put the ESD on the line
The 0.164/0.200 CPWG geometry was fine; the calculation just stopped at the
trace and never covered the connector launch, which is where the real
discontinuity was.

J2's centre land is 1.5 mm wide because that is what the connector's centre pin
needs mechanically. Sitting on solid L2_GND only 0.0994 mm below, that land is
a 10.7 ohm transmission line, not a 50 ohm one. The 1.84 mm of it over the
plane is 6.7 degrees at L1 and reflects 12 dB (VSWR 1.67) - by far the worst
discontinuity in the chain, and worse than everything the carefully built
0.164 mm line downstream avoids.

RF_LAUNCH_RELIEF voids L2_GND and L3_SIG under the land, (172.35, 40.95) to
(175.10, 43.05). The reference drops to L4_PWR - VCC3V0_RF, an AC ground -
0.587 mm below, which raises the launch to 37 ohm and 30 dB. L3 carried no
pour and no copper there, so only L2 actually had to go; the area covers L3 as
well so a later edit cannot fill the gap back in. It stops where the land ends
and the 0.164 mm line begins, verified: L2 GND is absent across the whole land
and present again at x = 172.0 and inboard.

D1's ESD clamp sat at the end of a 1.34 mm spur, where its 0.3 pF presented
-j228 ohm and cost 3.4 dB for nothing. D1 is rotated onto the run at
(171.30, 42.416) so pad 1 overlaps the line directly and pad 2 lands in the
RF ground pour; the spur is deleted.

Return loss, worst term first:
  SMA launch land      12.0 -> 30.0 dB   (10.7 -> 37.0 ohm)
  D1 ESD clamp         19.2 -> 22.6 dB   (now just the part's own 0.3 pF)
  C85 DNP tuning stub  25.5 dB unchanged, intentional provision
  C84 DNP land in line 30.1 dB unchanged, negligible
  worst-case coherent   7.0 -> 14.4 dB
The dominant term is now a component choice rather than a layout defect.

Verified: ERC 0/0, DRC 0 violations, 0 unconnected, every net one copper group,
parity unchanged at the 402 pre-existing warnings, RF still 10 segments all on
F.Cu at exactly 0.164 mm.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012KaTmCCxCEW4awsmXRNT1d
2026-09-01 12:55:49 +03:00
onur 1ea2bc64ac Add the missing TPS2121 status pull-up (R108) and correct the power-mux docs
The power mux's status output had no pull-up, which broke the USB current
budget interlock.

TPS2121 ST is an open-drain output; the datasheet lists RST = 6-20 kOhm under
Recommended Operating Conditions, alongside RILM, so it is an external part.
ST is driven low only while IN2 (the J3 external 5 V header) is sourcing OUT,
and is high impedance whenever IN1 (the J7 USB-C input) is sourcing. U10 gate 2
inverts MUX_ST into EXT_SELECTED, and MAIN_EN = USB_3A_OK OR EXT_SELECTED
enables the 15 A core buck. With MUX_ST floating on USB-C power, a drift low
asserts MAIN_EN no matter what the TUSB320 advertised, so the board would try
to bring up the core rail on a 500 mA port. Every other open-drain net here
already has its pull-up (R7/R8, R30, R33/R34, R98/R104/R105/R106); this one was
missed.

R108 (10 k, VCC3V3_AUX -> MUX_ST) is appended at the end of design_data.py
rather than beside the mux: reference designators are assigned in call order,
so inserting it mid-file would renumber every later resistor and invalidate the
routed board. Placed at (53.0, 101.6), 2.4 mm from the U10 gate it holds up,
on a site checked clear of existing copper, and routed with close_remaining.py.

Also corrects POWER_TREE.md, which credited PR1 for giving the external input
priority. PR1 = GND actually *disables* priority mode; CP2 (tied to VCC3V3_AUX)
is what selects IN2. Since CP2 derives from the mux's own output the behaviour
is two-phase - highest-voltage wins at cold start, IN2 unconditionally once the
aux rail is up - so with both inputs connected there can be one seamless
switchover at startup. Documented, with the numbers: both eFuses UV 3.98 V /
OV 5.80 V, ILIM 2.69 A (USB-C) and 4.04 A (header), mux OV 5.69 V / ILIM 4.5 A.
The two inputs are never summed: both eFuses block reverse current and the mux
bonds exactly one input at a time.

board_routed.kicad_sch/.kicad_sym are now gitignored byte copies of the tracked
schematic; kicad-cli needs them beside the board for --schematic-parity, and
deleting them in the previous commit had silently disabled that check.

Verified: ERC 0/0, DRC 0 violations, 0 unconnected, every net one copper group,
schematic parity unchanged at the 402 pre-existing warnings.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012KaTmCCxCEW4awsmXRNT1d
2026-09-01 12:28:00 +03:00
onur 95609a6b6a Complete the routing: 0 DRC violations, 0 unconnected
The board now routes end to end. Every net carrying two or more pads is a
single connected copper group (216 nets, 1175 pads); kicad-cli reports 0 DRC
violations and 0 unconnected items with zones refilled.

Freerouting was never the blocker. The 14 remaining opens were three separate
defects:

1. Obstacles in route_local_power.py modelled every pad as its axis-aligned
   bounding box. A 0.8-mm BGA dogbone site sits diagonally between four lands:
   true clearance 0.1407 mm, but the box test measured 0.4 mm from the box edge
   and rejected it, so no via could be placed anywhere in the Ti375 escape
   field. Replaced with an exact rounded-rectangle model, validated against
   KiCad's own SHAPE::Collide to 0.00 um over 14850 samples. Same 0 DRC and one
   fewer unconnected at the route_local_power stage.

2. CLOCK's 0.15-mm clearance cannot physically escape the BGA: two adjacent
   0.45-mm dogbone vias on 0.8-mm pitch leave a 0.35-mm channel and a 0.10-mm
   trace needs 0.40 mm. HARD_TCK and MAX_SCLK could never leave the package.
   New rule "Ti375 escape field copper clearance" relaxes clearance to the
   0.10 mm this field already uses, only where both objects are inside U1's
   courtyard. The clock trunk keeps 0.15 mm outside it.

3. RF_NO_DIGITAL was a rectangle reaching 7 mm past the RF line, covering the
   MAX2771's whole digital pin field and forcing every U21 output onto F.Cu
   alone. Narrowed to the corridor generate_pcb.py already reserves as
   TEMP_RF_LINE (y <= 43.7), clearing RF copper by 1.1 mm. The RF return path
   is guaranteed by the unrouted L2/L7 ground planes, not by this area.

scripts/close_remaining.py replaces the ad-hoc residual scripts: a multi-layer
maze over (x, y, layer) at 0.1 mm on all five routable layers, seeded from all
copper of both groups, exact clearances, 0.10-mm necking inside the escape
field, and reversible rip-up that rolls back entirely if a displaced net cannot
be put back. ~150 s for the whole board.

Also removes the regenerable intermediate boards, one-off session logs and the
superseded residual scripts, and tracks board_routed.* as the deliverable.

The 402 schematic-parity warnings are pre-existing and unchanged: 199
auto-named unconnected pins, 199 footprint library-nickname mismatches, and 4
mounting holes with no symbol. None affects connectivity or fabrication.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012KaTmCCxCEW4awsmXRNT1d
2026-09-01 11:58:41 +03:00
onur af7c43b2a8 Restack to four signal layers and route the board
The Ti375 fanout could not be resolved with three routing layers, so L5
stops being a dedicated 1.8-V plane and becomes a signal layer.  No rail
owns a whole layer any more: the supplies are split into zone islands on
L4 and L6, L2 and L7 stay solid and completely unrouted, and F.Cu, L3, L5
and B.Cu are all available for signals.

Routing is staged rather than handed to the autorouter wholesale.  The
BGA escape, the buck high-current loops, plane stitching and the local
power completion all run first and are locked; Freerouting then sees only
the ordinary digital classes, with everything else present as fixed
copper.  finalize_routing.py installs the audited RF and USB geometry and
closes whatever the autorouter left.

Four bugs behind the routing failures, all of them the same shape - a
layer list written down instead of read from the board, which was correct
while L5 was a plane and silently wrong afterwards:

- export_routing_stage.py emitted via keepouts for three layers only, so
  every existing via was invisible to the router on L5.  It drove traces
  straight through them: 102 shorting_items in DRC.
- route_local_power.py never used L5 at all, and picked up escape vias on
  two layers instead of all four.
- add_rf_ground() judged fence positions against vias and pads but not
  tracks.  It runs after the session import, when that region already has
  routed copper, and dropped a ground via on top of a signal trace.

route_local_power.py also grew a via cloud on every rail: reaching a
plane counted as progress even when it merged nothing, so the same pad
collected a via per pass, 0.4 mm further out each time.  Progress is now
measured by the group count actually falling, and groups already sitting
on their plane are skipped.  That removed 404 redundant vias.

The MAX2771 PLL loop filter was spread across three corners of the
package, which forced the charge-pump node onto an inner layer under the
GPS front end.  All three parts now sit in the pocket at U21's north-west
corner and the net stays on F.Cu.  A permanent RF_NO_DIGITAL area plus a
scoped rule keeps that region free of non-power copper on L3/L5/L6/B.Cu,
and the local router enforces the same restriction, since it is the one
stage that runs after the temporary keepout is deleted.

Also enables the solder-mask bridge check that was switched off
board-wide; the board passes it with no violations.

Final board: DRC clean - no shorts, clearance, disallowed-item or
dangling-copper violations - with 26 unconnected endpoints left.  Routing
is spread 37% L3, 27% F.Cu, 26% L5, 10% B.Cu over 6548 mm and 971 vias.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-16 01:41:43 +03:00
onur b706197667 Initial Ti375 GNSS IMU board design and documentation 2026-08-15 18:09:17 +03:00