Files
rebbarb/hardware/re-bba-rb/CPL_ROTATIONS.md
T
2026-07-31 22:06:21 +02:00

206 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CPL rotation corrections — re-bba-rb
`re-bba-rb-cpl.csv` is generated from `kicad-cli pcb export pos` (raw KiCad
rotation values), **then hand-corrected** for the parts below before each
regeneration. This file exists because that correction step is easy to lose
silently — regenerating the CPL "the normal way" wipes it out, and there is
no automated check that would catch that. Read this before touching the CPL.
## Why this exists
KiCad's per-footprint rotation is measured from an arbitrary reference baked
into whoever drew that footprint — it does not reliably match what JLCPCB's
placement machine expects. This is a well-known, generic problem (see
`cpl_rotations_db.csv` from the JLCKicadTools / kicad-jlcpcb-tools projects
for the community's attempt at a fix), but **the generic community
correction table was tried on this board and found wrong** — it claims
`LQFP-: 270°`, but on this exact board/toolchain pairing (KiCad 10 +
`kicad-cli pcb export pos`, not the dedicated plugin) the raw LQFP/QFN
rotation is already correct. The generic table's values are calibrated
against that plugin's own raw-rotation baseline, which is not the same
baseline `kicad-cli`'s raw CSV export produces (different Y-axis handling
between the two tools). **Do not reapply the community table wholesale to
this board.** Every correction below was derived per-part from direct visual
verification against JLCPCB's placement-preview render, not from that table.
## Rotation sign convention
The CPL uses JLCPCB's Y-up coordinate frame (`kicad-cli`'s csv pos format
already negates Y from KiCad's native Y-down). In that frame, **increasing
rotation angle is counter-clockwise** (standard math convention). So when
the user reports "needs N degrees clockwise", the correction applied is
**`new = (old - N) % 360`**, not `+N`. Get this backwards and every fix
lands 2×N off instead of correct.
## How to reapply — copy this exact dict, don't reconstruct it from memory
This is the complete, current correction set (all 16 parts). **Copy-paste
this block, don't retype it from the table below or from memory** — the one
time it was retyped from a section of prose instead of copied whole, U4 got
silently dropped and shipped with a wrong rotation.
```python
import csv
corrections = {
'U7': 270, # SOIC-8, confirmed 2026-07-31 (net of +90 hypothesis + 180 more) — same net correction as U10
'U10': 270, # SOIC-8, confirmed (net of +90 hypothesis + 180 more)
'U11': -90, # LQFP-64, confirmed 2026-07-31 ("90 degrees clockwise") — SUPERSEDES the earlier "all large chips are right" report, see below
'D1': -90, 'D4': -90, 'D5': -90, 'U12': -90, # SOT-23-6, reconstructed hypothesis
'U1': -180, # SOT-23-5, confirmed (two -90 corrections)
'U4': -90, # SOT-23-5, confirmed ("U4 is good")
'Q1': 180, 'Q2': 180, # SOT-23 bottom layer, confirmed "upside down"
'D2': -90, # custom footprint, confirmed "90 CW"
'D3': 180, # SMA diode, confirmed "180"
'C65': 180, # electrolytic cap, confirmed "180"
'U2': -90, # SOT-583-8, confirmed "90 CW"
'U3': 180, # custom SOT95P280X110-6N footprint, confirmed "180"
} # positive = CCW, negative = CW
with open('re-bba-rb-cpl.csv', newline='') as f:
rows = list(csv.DictReader(f))
for r in rows:
if r['Designator'] in corrections:
old = float(r['Rotation'])
new = (old + corrections[r['Designator']]) % 360
r['Rotation'] = f"{new:.6f}"
with open('re-bba-rb-cpl.csv', 'w', newline='') as f:
writer = csv.DictWriter(f, fieldnames=['Designator','Mid X','Mid Y','Layer','Rotation'])
writer.writeheader()
writer.writerows(rows)
```
If a new correction comes in from a placement-preview check, add it to
*this* dict (and the table below), never work from a hand-copied subset.
When regenerating the CPL from scratch (e.g. after a reroute or component
move), **re-run `kicad-cli pcb export pos` for fresh positions, then
reapply every correction below** — don't just diff/copy the old file, since
positions can legitimately change while rotations still need the same
correction offset applied on top.
## Confirmed correct as-is — apply NO correction
**These are the only parts that take zero correction.** Everything else in
this section title's spirit but requiring a nonzero offset (like U4 below)
lives in the corrections table, not here — filing U4 in this section
previously (saying "confirmed good" without also flagging its required -90°
delta) caused a real bug: a later reapplication pass built its correction
dict from this section's prose and silently skipped U4, regenerating the
CPL with U4 back at raw/wrong rotation. Don't repeat that — if a part needs
*any* nonzero delta from raw, it belongs in the table below, full stop, even
if that delta is "confirmed correct and needs no further correction beyond
it."
- **U8 (LQFP-48)**, **U9 (QFN-48)** — "all large chips are right" (user,
direct placement-preview check). ⚠️ **That single report also covered U11,
and U11 later turned out to need 90° after all** (direct check,
2026-07-31). So the "large chips are fine" observation is now known to be
wrong for at least one of the three parts it covered, and U8/U9 rest
entirely on that same weakened report. Treat both as **unverified**, not
settled — re-check them in the placement preview before assembly. Do not
cite "all large chips are right" as evidence again.
- **D8, D9 (LED_0603, bottom layer)** — verified 2026-07-31 by tracing the
circuit rather than by eye, see "D8/D9 polarity" below. No correction.
- **J2 (HR911105A magjack, rot=90° in the PCB file)** — not a CPL-rotation
question (J2 doesn't need per-part correction below, it's not in the CPL
correction set), but its physical orientation was independently verified:
the RJ45 signal pins (pins 18, footprint local +Y) map to absolute X
under the board's 90° placement rotation, which correctly faces the
board's tongue/cable-exit edge. Pin 1 appearing to "face outside the
board" in the placement render is *expected*, not a defect — the RJ45
contacts are always near the cable-insertion opening by construction.
## Corrections applied (all currently in `re-bba-rb-cpl.csv`)
Each row: designator, package, raw→corrected, confidence.
| Ref | Package | Raw | Corrected | Confidence |
|---|---|---|---|---|
| U7 | SOIC-8 | 90° | **0°** (net: +90° reconstructed hypothesis, then +180° more, user-confirmed 2026-07-31) | **Confirmed.** Note this landed on exactly the same net correction as U10 (+270°), which retroactively makes the two SOIC-8 parts consistent — the original bare "+90°" hypothesis was wrong for *both*, in the same direction and by the same amount |
| U11 | LQFP-64 | -90° | **180°** | **Confirmed** ("90 degrees clockwise", 2026-07-31). Previously filed as needing NO correction on the strength of "all large chips are right" — that report was wrong for this part. See the note in the no-correction section above: U8/U9 inherit the doubt |
| U10 | SOIC-8 | 0° | **270°** (net: +90° reconstructed hypothesis, then +180° more, user-confirmed) | Partially confirmed — the +90° hypothesis alone was WRONG/incomplete (needed another 180° on top). **This means the SOIC "+90°" hypothesis should not be trusted for U7 either** without its own direct check, since it's now proven wrong at least once. |
| U3 | custom `SOT95P280X110-6N` | 0° | **180°** | **Confirmed** ("180°") |
| D1 | SOT-23-6 | 0° | **270°** | Reconstructed hypothesis — not independently re-confirmed |
| D4 | SOT-23-6 | 180° | **90°** | Reconstructed hypothesis — not independently re-confirmed |
| D5 | SOT-23-6 | 180° | **90°** | Reconstructed hypothesis — not independently re-confirmed |
| U12 | SOT-23-6 | 180° | **90°** | Reconstructed hypothesis — not independently re-confirmed |
| U1 | SOT-23-5 | 180° | **0°** (two corrections: -90° then another -90°, user-confirmed both times) | **Confirmed** by direct user feedback, twice |
| U4 | SOT-23-5 | 0° | **270°** (-90°, the same family correction as D1/D4/D5/U12) | **Confirmed** — user checked and said "U4 is good" after this delta, no second correction needed (unlike U1) |
| Q1 | SOT-23 (bottom layer) | -90° | **90°** | **Confirmed** ("upside down" = 180°, direction-agnostic) |
| Q2 | SOT-23 (bottom layer) | -90° | **90°** | **Confirmed** (same as Q1) |
| D2 | custom `SON50P110X213X50-7` | 0° | **270°** | **Confirmed** ("90° clockwise") |
| D3 | `Diode_SMD:D_SMA` | 180° | **0°** | **Confirmed** ("180°", direction-agnostic) |
| C65 | `Capacitor_SMD:CP_Elec_6.3x7.7` | 0° | **180°** | **Confirmed** ("180°", direction-agnostic) |
| U2 | SOT-583-8 | 180° | **90°** | **Confirmed** ("90° clockwise") |
**"Reconstructed hypothesis" parts (U7, U10, D1, D4, D5, U12) explained:**
the user reported "SOIC and SOT chips are rotated 90°, direction unsure."
Cross-referencing against *earlier* feedback in the same session — where a
-90° correction had been applied to the top-layer SOT-23 parts and NOT
flagged as wrong, while the same -90° applied to a SOIC part (U10) WAS
flagged wrong — implies SOT-23 needs -90° and SOIC needs the opposite,
+90°. This is indirect reasoning, not a fresh direct check, and **U1 later
proved that even within one confirmed-wrong-by-90°-family, the correction
does NOT reliably generalize per package type** (U1 and U4 are both
SOT-23-5, both got the -90° family correction, but U1 needed a *second*
-90° on top while U4 was already correct) — so treat every "reconstructed
hypothesis" row above as **worth a fresh placement-preview check**, not
settled fact, despite no contradicting feedback having come in since.
## D8/D9 polarity — checked by circuit tracing, NOT by eye (2026-07-31)
D8 was reported as *possibly* upside down because "it connects with its
negative side to Q1". **That observation is correct behaviour, not a
fault** — D8's cathode is *supposed* to face Q1. Tracing the net:
```
D8: 3V3 → R41 → D8.pad2 (A) ─ D8.pad1 (K) → Q1.pad3 (C) → Q1.pad2 (E) → GND
Q1 is an NPN low-side switch, base Q1.pad1 ← R39.
Current can only flow if the LED cathode is the Q1 end. ✔
D9: 3V3 → Q2.pad2 (E) → Q2.pad3 (C) → R42 → D9.pad2 (A) ─ D9.pad1 (K) → GND
Q2 is a PNP high-side switch, base Q2.pad1 ← R40.
D9's cathode goes straight to GND; it does NOT touch Q2 directly. ✔
```
Both are `LED_SMD:LED_0603_1608Metric` on **B.Cu**, both at raw 90°, and
both have pad 1 = cathode (the footprint's B.Fab chamfer marks the pad-1 /
cathode end). Absolute pad geometry, with the back-layer X-mirror applied:
| | pad 1 (K) | pad 2 (A) | anode's partner |
|---|---|---|---|
| D8 | (167.420, **47.300**) | (167.420, **48.875**) | R41 pad 2 at (166.170, 48.875) |
| D9 | (164.940, **47.340**) | (164.940, **48.915**) | R42 pad 2 at (163.690, 48.917) |
The anode pads land at the *same Y* as their series resistor's pad — that
alignment is what confirms the back-layer mirror was applied correctly when
computing these (get the mirror wrong and pad 1/2 swap, inverting the whole
conclusion). Q1's collector pad sits at (165.350, 45.580), i.e. **above** D8
in Y — the same side as D8's cathode. So "cathode faces Q1" is exactly right.
**Both D8 and D9 are oriented identically** (cathode toward smaller Y). That
is a useful invariant: they are the same part in the same circuit role, so if
a future preview shows one of them needing a flip, *both* need it — a
correction applied to only one of the pair is a mistake.
Note this relationship is **mirror-invariant**: whether the assembler renders
the bottom layer viewed-from-below or seen-through-the-board, "D8's cathode
end is the end nearer Q1" stays true. So it is a safe thing to eyeball in a
preview, unlike absolute left/right or up/down judgements on bottom-layer
parts.
## Parts never checked at all
Every 0402/0603/0805 passive (R/C/L) except C65, J1/J3/J4 connectors, and
anything else not listed in the corrections table above is sitting at
**raw, unverified KiCad rotation** in the CPL. Passives in symmetric
packages are usually fine raw (this matched observed behavior for the ones
implicitly checked), but this has not been confirmed part-by-part the way
the table above was.
## Bottom line for whoever picks this up next
Before ordering assembly, re-check the *entire* board in JLCPCB's (or
whatever assembler's) placement preview — this file only covers what's been
individually verified so far, not a general guarantee the CPL is correct.