Leo generated the vendor part with easyeda2kicad (C5120257) -> Drogheda-v6.kicad_sym / .pretty / .3dshapes, now registered in sym-lib-table and fp-lib-table. CROSS-CHECK: the EasyEDA/LCSC symbol independently CONFIRMS the datasheet transcription - pads 1-54 match the u-blox pin assignment function for function, and the 21 Reserved pads are identical. Pads 55-102 are 48 extra GND pads (the ground array under the module), which our symbol was missing; T3a2 adds them stacked on the pin-1 coordinate so one GND label serves all. Symbol is now 102/102 pins, footprint = Drogheda-v6:LCC-LGA-102_L22.0-W17.0_FM660. Block N as wired (verified by rebuilding connectivity from label-on-pin geometry): GNSS_TX U16.16 + U18.43 GNSS_RX U16.17 + U18.42 DOUT_4G U18.26 (RXD2, RTCM in - modem end lands in T4) USART1_RX U16.43 + Rdfu1.1 + U18.27 (TXD2 uplink; K1.1 also on this net per the PCB) GNSS_RESET_N U16.53 (PC12) + U18.49 + R105 10k pull-up to 3V3_GNSS GNSS_TIMEPULSE U16.23 (PA7) + U18.53 GNSS_ANT_DETECT U16.9 (PC1) + U18.4 GNSS_ANT_SHORT_N U16.10 (PC2) + U18.6 GNSS_RTK_STAT U16.11 (PC3) + U18.20 <- hardware answer to are-corrections-being-used 3V3_GNSS = U21.5 + U18.33/34 + C120-C124 + R105; U21 fed from SW_5V (stays MCU-gated) V_BCKP = U18.36 on the UNGATED 3V3 so ephemeris survives a power-cycle 33 no-connects: the 21 reserved pads plus V_USB, USB_DM/DP, ANT_OFF, SDA, SCL, TX_READY, D_SEL (open = UART mode), SAFEBOOT_N, EXTINT, GEOFENCE_STAT and the LDO NC/NR pin. T3c fixes two coordinates the generators emitted as 3.552713679e-15 (i.e. zero); KiCad is not guaranteed to accept exponent notation. See the script header for the lesson: a first attempt used a bare numeric regex over the whole file and corrupted 264 UUIDs, because segments such as 895e-4153 parse as scientific notation. Reverted from backup and redone scoped to (at ...) forms only, with a UUID-integrity guard. Verified 2298 UUIDs, 0 malformed, 0 exponent coordinates. STILL OPEN: the PCB has no U18/U21/passive footprints yet - that is a KiCad Update-PCB-from-Schematic. And confirm the -04B datasheet pin assignment on paper. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJ4eAB6zjQT49RVwpgfKdt
79 lines
3.6 KiB
Python
79 lines
3.6 KiB
Python
#!/usr/bin/env python3
|
|
"""v6 T3a2 - patch Drogheda-sym:ZED-F9P for the REAL LGA-102 land pattern.
|
|
|
|
Cross-check performed 2026-08-24 against the EasyEDA/LCSC part C5120257 generated by
|
|
easyeda2kicad (Drogheda-v6.kicad_sym + Drogheda-v6.pretty):
|
|
|
|
* pads 1-54 map EXACTLY to the u-blox datasheet pin assignment - every function matched
|
|
(GND set, RF_IN 2, ANT_DETECT 4, ANT_OFF 5, ANT_SHORT_N 6, VCC_RF 7, GEOFENCE_STAT 19,
|
|
RTK_STAT 20, RXD2 26, TXD2 27, VCC 33/34, V_BCKP 36, V_USB 38, USB_DM/DP 39/40,
|
|
TXD 42, RXD 43, SDA 44, SCL 45, TX_READY 46, D_SEL 47, RESET_N 49, SAFEBOOT_N 50,
|
|
EXTINT 51, TIMEPULSE 53, and the identical 21 Reserved pads).
|
|
* pads 55-102 are 48 ADDITIONAL GND pads - the ground/thermal array under the module.
|
|
|
|
So the datasheet transcription is independently confirmed, and the only thing missing from
|
|
our symbol is the ground array. This patch adds pads 55-102 as GND, stacked on the pin-1
|
|
coordinate so a single GND label connects them all, and points Footprint at the real land
|
|
pattern.
|
|
|
|
Usage: python3 2026-08-24_v6_T3a2_f9p_ground_array.py [--apply]
|
|
"""
|
|
import os, sys, shutil, re
|
|
|
|
KI = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '03-Architecture-Hardware', 'kicad')
|
|
LIB = os.path.join(KI, 'Drogheda-sym.kicad_sym')
|
|
APPLY = '--apply' in sys.argv
|
|
FP = 'Drogheda-v6:LCC-LGA-102_L22.0-W17.0_FM660'
|
|
|
|
src = open(LIB, encoding='utf-8').read()
|
|
i = src.find(' (symbol "ZED-F9P"\n')
|
|
if i < 0: sys.exit('ZED-F9P symbol not found')
|
|
j = src.find(' (symbol "LDO_SOT23-5"\n')
|
|
blk = src[i:j]
|
|
if '(number "102"' in blk: sys.exit('REFUSING: ground array already present')
|
|
|
|
# pin 1 (GND) coordinate, to stack the array on
|
|
m = re.search(r'\(pin power_in line\s*\n\s*\(at ([-\d.]+) ([-\d.]+) (\d+)\)(?:(?!\(pin ).)*?\(number "1"', blk, re.S)
|
|
if not m: sys.exit('could not locate pin 1')
|
|
x, y, rot = m.group(1), m.group(2), m.group(3)
|
|
print('stacking pads 55-102 on pin 1 at (%s, %s) rot %s' % (x, y, rot))
|
|
|
|
extra = ''
|
|
for n in range(55, 103):
|
|
extra += (' (pin passive line\n (at %s %s %s)\n (length 5.08)\n'
|
|
' (name "GND"\n (effects (font (size 1.27 1.27)))\n )\n'
|
|
' (number "%d"\n (effects (font (size 1.27 1.27)))\n )\n )\n'
|
|
) % (x, y, rot, n)
|
|
|
|
k = blk.rindex(' )\n )\n') # close of the _1_1 sub-symbol
|
|
newblk = blk[:k] + extra + blk[k:]
|
|
newblk = newblk.replace('(property "Footprint" "Drogheda:u-blox_ZED-F9P_LGA54"',
|
|
'(property "Footprint" "%s"' % FP, 1)
|
|
newblk = newblk.replace('LCSC C5120257.',
|
|
'LCSC C5120257. Land pattern = LGA-102: pads 1-54 per the datasheet, pads 55-102 are an '
|
|
'additional GND array under the module (stacked on the pin-1 coordinate in this symbol).', 1)
|
|
|
|
new = src[:i] + newblk + src[j:]
|
|
nums = re.findall(r'\(number "(\d+)"', newblk)
|
|
print('pin numbers now: %d, unique %d, missing %s'
|
|
% (len(nums), len(set(nums)), sorted(set(range(1,103)) - set(int(n) for n in nums)) or 'none'))
|
|
print('footprint property ->', FP)
|
|
|
|
def bal(t):
|
|
d=0; instr=False; esc=False
|
|
for ch in t:
|
|
if esc: esc=False; continue
|
|
if ch=='\\': esc=True; continue
|
|
if ch=='"': instr = not instr; continue
|
|
if instr: continue
|
|
if ch=='(': d+=1
|
|
elif ch==')': d-=1
|
|
return d
|
|
print('paren balance:', bal(new))
|
|
if not APPLY:
|
|
print('\nDRY RUN - nothing written. Re-run with --apply.'); sys.exit(0)
|
|
if bal(new) != 0: sys.exit('REFUSING: paren imbalance')
|
|
shutil.copy2(LIB, LIB + '.T3a2bak')
|
|
open(LIB, 'w', encoding='utf-8').write(new)
|
|
print('\nAPPLIED. Backup: Drogheda-sym.kicad_sym.T3a2bak')
|