auto-sync 2026-08-12 18:00
This commit is contained in:
parent
a7ac49b59d
commit
21cda79ff0
@ -0,0 +1,188 @@
|
|||||||
|
---
|
||||||
|
title: EinarBoard 3.0 — On-Board MCU Integration — Design Brief & Execution Prompt
|
||||||
|
tags: [project-drogheda, hardware, einarboard, mcu-integration, stm32f411, dfu, design-brief, prompt]
|
||||||
|
project: Project Drogheda
|
||||||
|
author: Helgen CTO + Claude (decisions locked 2026-08-12)
|
||||||
|
date: 2026-08-12
|
||||||
|
status: Active — THE prompt for the 3.0 design sessions. Read this first, then execute the phases in §10.
|
||||||
|
authority: supplements [[watchdog-electrical-design-state]] (canonical) + the 1.1 brief (as executed in v4 = EinarBoard 2.0); where they conflict on 3.0 scope, THIS file wins.
|
||||||
|
---
|
||||||
|
|
||||||
|
# EinarBoard 3.0 — Design Brief ("the prompt")
|
||||||
|
|
||||||
|
> **How to use this doc.** Self-contained instruction set for turning `hbox-watchdog-v4`
|
||||||
|
> (EinarBoard 2.0, as sent to fab ~2026-08-01, git `b505cb3`) into **EinarBoard 3.0**
|
||||||
|
> (`kicad/hbox-watchdog-v5`). Standing rules unchanged from the 1.1 brief: **file-level
|
||||||
|
> KiCad edits only** (KiCad MCP backend clobbered disk state 2026-07-24 — read-only MCP
|
||||||
|
> queries are fine); git checkpoint after every phase; verify every structural edit with an
|
||||||
|
> independent parse; bench gates unchanged.
|
||||||
|
|
||||||
|
## 0. Decisions locked 2026-08-12 (Leo)
|
||||||
|
|
||||||
|
| Topic | Decision |
|
||||||
|
|---|---|
|
||||||
|
| MCU | **On-board STM32F411RET6 (LQFP64)** replaces the Blackpill module + J1/J2 sockets |
|
||||||
|
| Flash path | **USB DFU on a board-mounted USB-C** (BOOT0 + NRST buttons on-board, Blackpill parity) + SWD recovery pads |
|
||||||
|
| Base | `hbox-watchdog-v4` (EinarBoard 2.0: W5500 Ethernet, SC16IS752 serial, PCF8574 expander — all kept) |
|
||||||
|
| Modem / GNSS | **Stay modular** — XBee socket + simpleRTK2B Pro shield (stock already purchased) |
|
||||||
|
| Fixation | Shield **bolted through its UNO-pattern holes** into matching EinarBoard holes (M2.5); **2× M2.5 holes near the XBee** for a heatsink that also clamps the modem |
|
||||||
|
| Fan | **2-pin fan only** — 4-pin header + tach conditioning removed, PB10 freed |
|
||||||
|
| Naming | Product **EinarBoard 3.0** · KiCad project **`hbox-watchdog-v5`** |
|
||||||
|
|
||||||
|
## 1. Why the F411RET6 (and not something else)
|
||||||
|
|
||||||
|
Same silicon family as the Blackpill's F411CEU6 → **firmware v2.3/v3.x runs unchanged**.
|
||||||
|
Only the build target moves: Arduino board = *Generic F411RE* (or a copied Blackpill
|
||||||
|
variant) with `HSE_VALUE = 25 MHz` — a build-config change, not a port.
|
||||||
|
|
||||||
|
| | F411CEU6 (Blackpill chip) | **F411RET6 (chosen)** | G431CBT6 (rejected for now) |
|
||||||
|
|---|---|---|---|
|
||||||
|
| Package | UFQFPN48 (hot-air only) | **LQFP64 — hand-solder/rework OK** | LQFP48 |
|
||||||
|
| JLC price/stock (2026-08-12) | $3.31 · 1,333 (C2054095) | **$2.47 · 5,342 (C94355)** | $2.96 · 13,744 (C529355) |
|
||||||
|
| Extra pins | — | **PC0–PC12, PD2** (+ USART6 on PC6/PC7 = real 3rd UART; more ADC) | FDCAN (future CAN), crystal-less USB |
|
||||||
|
| Firmware | zero change | build-target change only | **full port — wrong timing mid-fleet** |
|
||||||
|
|
||||||
|
The 1.1 brief's "F411 has no third USART" was a **48-pin-package** limitation (USART6 lives
|
||||||
|
on PA11/PA12 there = USB). On LQFP64 it's on PC6/PC7 — reserve them. If vehicle CAN ever
|
||||||
|
becomes a requirement: MCP2518FD on SPI, or a G4 port as its own project.
|
||||||
|
Source **genuine ST via LCSC/JLC only** — the ROM bootloader behavior is the product feature.
|
||||||
|
|
||||||
|
## 2. ⚠ THE BOOT TRAP — read before touching pins
|
||||||
|
|
||||||
|
DFU entry on the F411 requires, at reset: **BOOT0 = 1 AND BOOT1 (PB2) = 0**
|
||||||
|
(BOOT0=1 + PB2=1 boots SRAM = dead end). v4 has **`ETH_INT` (W5500 INTn) on PB2**, per the
|
||||||
|
1.1 note "BOOT1: irrelevant with BOOT0=0; do not strap" — which was true only while the MCU
|
||||||
|
was a removable module. W5500 INTn **idles HIGH** → with the MCU soldered down, DFU would
|
||||||
|
be unreachable. Therefore in v5:
|
||||||
|
|
||||||
|
- **Move `ETH_INT` PB2 → PC0** (EXTI0 is free: PA0/PB0 don't use EXTI).
|
||||||
|
- **Strap PB2 → 10 k → GND.** Nothing else on PB2, ever.
|
||||||
|
- ROM bootloader also listens on **USART1 (PA9/PA10)** = the Modo-B pins. Flash with the
|
||||||
|
RTK stack unpowered (current practice) so F9P TX2 traffic can't capture the bootloader;
|
||||||
|
if field-reflash-with-stack-on is ever needed, add a series jumper on the PA10 tap then.
|
||||||
|
|
||||||
|
DFU bootloader clocking: the F411 has **no HSI48** — the ROM bootloader derives the 48 MHz
|
||||||
|
USB clock from the **external HSE crystal (4–26 MHz, auto-detected)**. Our 25 MHz HSE is
|
||||||
|
therefore **mandatory, not optional** (AN2606; same reason the Blackpill carries one).
|
||||||
|
|
||||||
|
## 3. NEW Block P — on-board MCU (Blackpill absorbed)
|
||||||
|
|
||||||
|
**U14 STM32F411RET6** (LQFP64, JLC C94355). Support circuitry, Blackpill-parity where noted:
|
||||||
|
|
||||||
|
- **HSE:** 25.000 MHz crystal (3225, CL 10–12 pF) + 2× load caps `C = 2(CL − C_stray)`
|
||||||
|
(≈15 pF for CL=10 pF; finalize per chosen crystal). Short symmetric traces, GND guard.
|
||||||
|
- **LSE:** 32.768 kHz (3215/2012, CL 12.5 pF, e.g. Q13FC-class) + caps per CL. Fit it
|
||||||
|
(Blackpill parity; RTC available). Firmware note: F411 LSE wants low drive level.
|
||||||
|
- **VCAP1:** 4.7 µF X5R ≥6.3 V at the pin (DS10314 — confirm value/pin in Phase A).
|
||||||
|
- **Decoupling:** 100 nF at **every** VDD pin + 4.7 µF bulk; **VDDA:** ferrite bead (or
|
||||||
|
10 Ω) from 3V3 + 1 µF + 100 nF (BAT_SENSE/VEH5V/NTC ADC quality — free upgrade vs the
|
||||||
|
module's direct tie). **VBAT → 3V3** + 100 nF.
|
||||||
|
- **BOOT0:** dedicated pin → **10 k pull-down** + tact switch to 3V3 (+ optional 2-pin jig
|
||||||
|
pad). **PB2/BOOT1: 10 k pull-down (§2).**
|
||||||
|
- **NRST:** joins the existing `NRST` net (SW1 on-board + P10 external — already designed)
|
||||||
|
+ 100 nF at the pin.
|
||||||
|
- **LEDs:** `LED_C13` **active-LOW** (3V3 → 1 k → LED → PC13, Blackpill polarity so v2.3+
|
||||||
|
blink code is unchanged) + PWR LED on 3V3.
|
||||||
|
- **USB-C (J11):** 16-pin USB 2.0 receptacle (TYPE-C-31-M-12 class) on a case-reachable
|
||||||
|
edge. CC1/CC2 → 5.1 k to GND (UFP). D+ → PA12, D− → PA11 via **USBLC6-2SC6** ESD array.
|
||||||
|
Shield → GND via RC (1 MΩ ∥ 4.7 nF) or direct — decide Phase A.
|
||||||
|
- **SWD:** 4 pads/test-points (3V3, PA13 SWDIO, PA14 SWCLK, GND) — DNP header. With a
|
||||||
|
soldered MCU this is the brick-recovery + factory path; the 1.1 brief already wanted it.
|
||||||
|
- **PA0 note:** no KEY button (Blackpill's KEY is PA0 = our `BAT_SENSE`). Not a loss.
|
||||||
|
|
||||||
|
## 4. Power — who makes 3V3 now
|
||||||
|
|
||||||
|
The Blackpill's on-module LDO dies with the module, so:
|
||||||
|
|
||||||
|
- **U15 LDO 3V3:** AMS1117-3.3 (SOT-223, JLC Basic C6186) — or equal ≥500 mA. Budget:
|
||||||
|
MCU ~50 mA + SHT40 + TMP102 + PCF8574 + SC16IS752 + MAX3232 + SP3485 TX bursts ≈
|
||||||
|
150–250 mA worst → 1 A part with margin, ~0.3 W dissipation OK in SOT-223.
|
||||||
|
- **Input OR:** `LDO_IN = MAIN5V (via D_or1 SS34) ∥ USB VBUS (via D_or2 SS34)`.
|
||||||
|
**Bench flashing on USB alone powers the 3V3 domain only** (MCU, sensors, expander,
|
||||||
|
serial bridge): W5500 (3V3_ETH from SYS5V) stays dark, K1 stays NC (corrections path
|
||||||
|
untouched), no backfeed into the LTC4040/MAIN5V. This replaces the module's
|
||||||
|
VBUS-to-5V tie with something that can't fight the backed-up rail.
|
||||||
|
- **Phase-A sweep:** every net the module's 3V3 pin used to source (I²C pull-ups, sensor
|
||||||
|
VDD, PCF8574, SC16IS752, IOREF row to MOD1, D5 clamp reference, NTC divider top…) moves
|
||||||
|
to the new LDO output net — keep the net name `3V3`. Verify with a netlist diff.
|
||||||
|
- 3V3_MODEM and 3V3_ETH bucks: **unchanged**.
|
||||||
|
|
||||||
|
## 5. Fan — 2-pin, done
|
||||||
|
|
||||||
|
- Fan connector → **2-pin** (`5V_FAN`, `FAN_RET`). Remove the 1×04 header, `FAN_TACH` /
|
||||||
|
`FAN_TACH_RAW` conditioning (pull-up/divider). Driver chain (PA6 `FAN_PWM` → Q → low-side)
|
||||||
|
and the U2 fan buck stay exactly as-is.
|
||||||
|
- **PB10 freed** (tach DNP provision retired — fleet fans are 2-wire, decided 2026-06-24).
|
||||||
|
- Firmware v3.0 already plans tach-less fan-fault inference (temp climbs while PWM high).
|
||||||
|
|
||||||
|
## 6. NEW Block Q — fixation (mechanical)
|
||||||
|
|
||||||
|
- **Shield bolts:** 4× holes in EinarBoard at **exactly MOD1's UNO-pattern hole coords**
|
||||||
|
(read the NPTH positions out of the `Arduino_UNO_R3` footprint in the v5 PCB — do not
|
||||||
|
re-derive from a drawing). Drill **Ø2.75 mm (M2.5)**; bolts pass shield → standoffs →
|
||||||
|
EinarBoard (→ optionally the mounting plate). **Bench check before freezing drill:**
|
||||||
|
caliper the real simpleRTK2B Pro holes — UNO-pattern boards are usually Ø3.2 (M3); if so
|
||||||
|
either keep M2.5 hardware (washers, slop is fine) or open ours to Ø3.2 and use M3. Keepout
|
||||||
|
annulus top/bottom, NPTH, no copper — and respect the HV24/inner-layer clearance rule.
|
||||||
|
- **XBee heatsink:** **2× M2.5 holes near J7/J8** so a small heatsink/bracket bolts down and
|
||||||
|
indirectly clamps the modem module. Position in Phase B with the case; keep clear of the
|
||||||
|
RF side of the socket and the 24 V copper.
|
||||||
|
- Case/plate: bolt pass-through and heatsink height ride the ASA reprint — coordinate
|
||||||
|
connector-edge plan (USB-C now needs an opening too) **before routing** (Phase B gate,
|
||||||
|
same as 1.1).
|
||||||
|
|
||||||
|
## 7. Pin map delta (v4 → v5)
|
||||||
|
|
||||||
|
| Pin | v4 (EinarBoard 2.0) | v5 (EinarBoard 3.0) |
|
||||||
|
|---|---|---|
|
||||||
|
| PB2 | `ETH_INT` (W5500 INTn) | **BOOT1 strap: 10 k → GND. Nothing else.** |
|
||||||
|
| PC0 *(new pin)* | — (module had no PC0) | **`ETH_INT`** |
|
||||||
|
| PB10 | tach DNP provision | **free** (fan is 2-pin) |
|
||||||
|
| PA13/PA14 | not broken out (module USB only) | **SWD pads** (DNP header) |
|
||||||
|
| PC6/PC7 *(new)* | — | **reserved: USART6** (future 3rd UART) |
|
||||||
|
| PC1–PC5, PC8–PC12, PD2 *(new)* | — | free — do not spend without updating this table |
|
||||||
|
| PA11/PA12 | module USB | **J11 USB-C** D−/D+ |
|
||||||
|
| everything else | per [[watchdog-electrical-design-state]] §2 + 1.1 blocks M/N/O | **unchanged** |
|
||||||
|
|
||||||
|
## 8. Depopulation / cleanup (3.0)
|
||||||
|
|
||||||
|
REMOVE: J1/J2 2×20 sockets + Blackpill-L/R symbols and footprint (→ **errata E-J1 retired
|
||||||
|
by construction** — no module, no mirroring, no "never power a seated module" hazard);
|
||||||
|
1×04 fan header + tach parts; stale Blackpill silkscreen (module outline, header labels).
|
||||||
|
KEEP: SW1 + P10 reset, P11 (jumper plug), P12 NTC, J7/J8 XBee, MOD1 shield sockets, J7 USB
|
||||||
|
modem-config path. SILKSCREEN: USB-C "DFU: hold BOOT0" hint, SWD pad labels, hole callouts
|
||||||
|
(M2.5), fan "2-pin 5V".
|
||||||
|
|
||||||
|
## 9. Risks / open items
|
||||||
|
|
||||||
|
- **PB2 strap is load-bearing** (§2) — make it a Phase-D ERC-notes item like the SC16IS
|
||||||
|
address strap was in 1.1.
|
||||||
|
- LQFP64 symbol/footprint: use KiCad lib `MCU_ST_STM32F4:STM32F411RETx` +
|
||||||
|
`Package_QFP:LQFP-64_10x10mm_P0.5mm`; save copies into the project libs (same policy as
|
||||||
|
the RevNum_EJ1 footprint).
|
||||||
|
- Blackpill variant nuances: confirm `Generic F411RE` Arduino variant boots USB CDC as
|
||||||
|
today's build does (bench item F-1 on first article; SWD pads are the net if it doesn't).
|
||||||
|
- Shield hole diameter verify (§6). · LSE drive/caps verify on first article.
|
||||||
|
- DFU with stack powered = USART1 capture risk (§2) — procedure note, not hardware.
|
||||||
|
- v4 boards at fab: 3.0 starts now as design work; nothing in 3.0 blocks v4 bring-up, and
|
||||||
|
v4 bench findings (modem rail, LTC4040 timer behavior) feed Phase D review.
|
||||||
|
|
||||||
|
## 10. Execution phases (each ends: git commit + parse-verify + snapshot)
|
||||||
|
|
||||||
|
- **A. Schematic** — copy v4 → `hbox-watchdog-v5` (done 2026-08-12 with this brief);
|
||||||
|
Block P + LDO OR (§3/§4); ETH_INT move + PB2 strap (§2); 3V3 net sweep (§4); fan 2-pin
|
||||||
|
(§5); depop §8; ERC = 0.
|
||||||
|
- **B. Outline & placement** — reclaim the Blackpill socket area; USB-C edge + case plan;
|
||||||
|
Block-Q holes (shield coords from MOD1 footprint; XBee heatsink pair); **Gate: Leo
|
||||||
|
approves connector-edge + hole plan before routing.**
|
||||||
|
- **C. Routing** — MCU fanout (crystal + USB first), re-route displaced nets, zones refill;
|
||||||
|
HV24 rules stand.
|
||||||
|
- **D. Verify** — ERC/DRC clean; strap/boot checklist (BOOT0 pull-down, PB2 low, HSE
|
||||||
|
present = DFU truth table); netlist diff v4→v5 reviewed; SVG/PDF review pack for Leo.
|
||||||
|
- **E. Outputs** — gerbers/BOM/CPL, LCSC pass (C94355 + new passives/USB-C/LDO), delta-doc
|
||||||
|
§-update, PINOUT.md rewrite (RET6 + freed pins), errata page (E-J1 retired), firmware
|
||||||
|
ticket: build target Generic F411RE + HSE flag + PC0 EXTI for ETH_INT.
|
||||||
|
|
||||||
|
*Fab gate unchanged: v5 doesn't go out before a v4-lineage bench validates the power path,
|
||||||
|
and first-article v5 must prove **USB DFU enumeration + a full flash cycle** before any
|
||||||
|
fleet quantity.*
|
||||||
BIN
03-Architecture-Hardware/hbox-watchdog-v5-schematic.pdf
Normal file
BIN
03-Architecture-Hardware/hbox-watchdog-v5-schematic.pdf
Normal file
Binary file not shown.
48
03-Architecture-Hardware/kicad/hbox-watchdog-v5.kicad_dru
Normal file
48
03-Architecture-Hardware/kicad/hbox-watchdog-v5.kicad_dru
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
(version 1)
|
||||||
|
|
||||||
|
# hbox-watchdog v4 — design rules
|
||||||
|
#
|
||||||
|
# Why three rules instead of one blanket minimum:
|
||||||
|
#
|
||||||
|
# The old file was a single unconditional (min 0.15mm). A custom rule outranks
|
||||||
|
# the netclass table, and an unconditional rule matches EVERY pair on the board,
|
||||||
|
# so it was silently overriding the HV24 netclass's 0.5 mm clearance everywhere.
|
||||||
|
# The netclass said 0.5; DRC was only ever enforcing 0.15.
|
||||||
|
#
|
||||||
|
# These three are mutually exclusive on the case that matters, so they give the
|
||||||
|
# same answer whether KiCad resolves by rule order or by specificity:
|
||||||
|
#
|
||||||
|
# 1. neither item is HV24 -> 0.15 mm (unchanged)
|
||||||
|
# 2. either item is HV24 -> 0.50 mm
|
||||||
|
# 3. except U2 pad-to-pad, its own land pattern -> 0.15 mm
|
||||||
|
#
|
||||||
|
# Rule 3 exists for exactly one pair. U2 is the MP1584EN buck (SOIC-8-EP):
|
||||||
|
# pad 7 (24V, 1.95 x 0.6) to pad 9 (the 2.29 x 3.0 exposed thermal pad, GND) is
|
||||||
|
# 0.355 mm, and that is the manufacturer's qualified land pattern — it is set by
|
||||||
|
# the package, not by routing, so no amount of rerouting can open it. Scoping
|
||||||
|
# the exception to Pad-to-Pad inside U2 keeps it from relaxing anything else:
|
||||||
|
# measured on this board, U2's courtyard contains 9 pads and all 9 belong to U2,
|
||||||
|
# so this condition cannot match a foreign pad. The tracks and vias that pass
|
||||||
|
# through that courtyard are excluded by the A.Type/B.Type test and stay at the
|
||||||
|
# full 0.5 mm.
|
||||||
|
#
|
||||||
|
# HV24 = /24V_IN, 24V, IGN_IN, Q10_GATE (netclass_patterns in the .kicad_pro)
|
||||||
|
#
|
||||||
|
# Note: raising HV24 to 0.5 mm also widens the copper pour pullback around those
|
||||||
|
# nets, because a zone floods to max(its own clearance, the effective DRC
|
||||||
|
# clearance) — 0.3 mm before, 0.5 mm now. Press B to refill before running DRC.
|
||||||
|
|
||||||
|
(rule "Minimum clearance 1"
|
||||||
|
(constraint clearance (min 0.15mm))
|
||||||
|
(condition "A.NetClass != 'HV24' && B.NetClass != 'HV24'")
|
||||||
|
)
|
||||||
|
|
||||||
|
(rule "HV24 clearance"
|
||||||
|
(constraint clearance (min 0.5mm))
|
||||||
|
(condition "(A.NetClass == 'HV24' || B.NetClass == 'HV24') && !(A.Type == 'Pad' && B.Type == 'Pad' && A.memberOfFootprint('U2') && B.memberOfFootprint('U2'))")
|
||||||
|
)
|
||||||
|
|
||||||
|
(rule "HV24 exception: MP1584EN land pattern"
|
||||||
|
(constraint clearance (min 0.15mm))
|
||||||
|
(condition "A.Type == 'Pad' && B.Type == 'Pad' && A.memberOfFootprint('U2') && B.memberOfFootprint('U2')")
|
||||||
|
)
|
||||||
54380
03-Architecture-Hardware/kicad/hbox-watchdog-v5.kicad_pcb
Normal file
54380
03-Architecture-Hardware/kicad/hbox-watchdog-v5.kicad_pcb
Normal file
File diff suppressed because it is too large
Load Diff
875
03-Architecture-Hardware/kicad/hbox-watchdog-v5.kicad_pro
Normal file
875
03-Architecture-Hardware/kicad/hbox-watchdog-v5.kicad_pro
Normal file
@ -0,0 +1,875 @@
|
|||||||
|
{
|
||||||
|
"board": {
|
||||||
|
"3dviewports": [],
|
||||||
|
"design_settings": {
|
||||||
|
"defaults": {
|
||||||
|
"apply_defaults_to_fp_barcodes": false,
|
||||||
|
"apply_defaults_to_fp_dimensions": false,
|
||||||
|
"apply_defaults_to_fp_fields": false,
|
||||||
|
"apply_defaults_to_fp_shapes": false,
|
||||||
|
"apply_defaults_to_fp_text": false,
|
||||||
|
"board_outline_line_width": 0.05,
|
||||||
|
"copper_line_width": 0.2,
|
||||||
|
"copper_text_italic": false,
|
||||||
|
"copper_text_size_h": 1.5,
|
||||||
|
"copper_text_size_v": 1.5,
|
||||||
|
"copper_text_thickness": 0.3,
|
||||||
|
"copper_text_upright": false,
|
||||||
|
"courtyard_line_width": 0.05,
|
||||||
|
"dimension_precision": 4,
|
||||||
|
"dimension_units": 3,
|
||||||
|
"dimensions": {
|
||||||
|
"arrow_length": 1270000,
|
||||||
|
"extension_offset": 500000,
|
||||||
|
"keep_text_aligned": true,
|
||||||
|
"suppress_zeroes": true,
|
||||||
|
"text_position": 0,
|
||||||
|
"units_format": 0
|
||||||
|
},
|
||||||
|
"fab_line_width": 0.1,
|
||||||
|
"fab_text_italic": false,
|
||||||
|
"fab_text_size_h": 1.0,
|
||||||
|
"fab_text_size_v": 1.0,
|
||||||
|
"fab_text_thickness": 0.15,
|
||||||
|
"fab_text_upright": false,
|
||||||
|
"other_line_width": 0.1,
|
||||||
|
"other_text_italic": false,
|
||||||
|
"other_text_size_h": 1.0,
|
||||||
|
"other_text_size_v": 1.0,
|
||||||
|
"other_text_thickness": 0.15,
|
||||||
|
"other_text_upright": false,
|
||||||
|
"pads": {
|
||||||
|
"drill": 1.0,
|
||||||
|
"height": 1.7,
|
||||||
|
"width": 1.7
|
||||||
|
},
|
||||||
|
"silk_line_width": 0.1,
|
||||||
|
"silk_text_italic": false,
|
||||||
|
"silk_text_size_h": 1.0,
|
||||||
|
"silk_text_size_v": 1.0,
|
||||||
|
"silk_text_thickness": 0.1,
|
||||||
|
"silk_text_upright": false,
|
||||||
|
"zones": {
|
||||||
|
"border_display_style": 2,
|
||||||
|
"border_hatch_pitch": 0.5,
|
||||||
|
"corner_radius": 0.0,
|
||||||
|
"corner_smoothing": 0,
|
||||||
|
"fill_mode": 0,
|
||||||
|
"hatch_gap": 1.5,
|
||||||
|
"hatch_orientation": 0.0,
|
||||||
|
"hatch_smoothing_level": 0,
|
||||||
|
"hatch_smoothing_value": 0.1,
|
||||||
|
"hatch_thickness": 1.0,
|
||||||
|
"min_clearance": 0.3,
|
||||||
|
"min_island_area": 10.0,
|
||||||
|
"min_thickness": 0.2,
|
||||||
|
"pad_connection": 1,
|
||||||
|
"remove_islands": 0,
|
||||||
|
"thermal_relief_gap": 0.5,
|
||||||
|
"thermal_relief_spoke_width": 0.5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"diff_pair_dimensions": [
|
||||||
|
{
|
||||||
|
"gap": 0.0,
|
||||||
|
"via_gap": 0.0,
|
||||||
|
"width": 0.0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"drc_exclusions": [],
|
||||||
|
"meta": {
|
||||||
|
"version": 2
|
||||||
|
},
|
||||||
|
"rule_severities": {
|
||||||
|
"annular_width": "error",
|
||||||
|
"clearance": "error",
|
||||||
|
"connection_width": "warning",
|
||||||
|
"copper_edge_clearance": "error",
|
||||||
|
"copper_sliver": "warning",
|
||||||
|
"courtyards_overlap": "error",
|
||||||
|
"creepage": "error",
|
||||||
|
"diff_pair_gap_out_of_range": "error",
|
||||||
|
"diff_pair_uncoupled_length_too_long": "error",
|
||||||
|
"drill_out_of_range": "error",
|
||||||
|
"duplicate_footprints": "warning",
|
||||||
|
"extra_footprint": "warning",
|
||||||
|
"footprint": "error",
|
||||||
|
"footprint_filters_mismatch": "ignore",
|
||||||
|
"footprint_symbol_field_mismatch": "warning",
|
||||||
|
"footprint_symbol_mismatch": "warning",
|
||||||
|
"footprint_type_mismatch": "ignore",
|
||||||
|
"hole_clearance": "error",
|
||||||
|
"hole_to_hole": "warning",
|
||||||
|
"holes_co_located": "warning",
|
||||||
|
"invalid_outline": "error",
|
||||||
|
"isolated_copper": "warning",
|
||||||
|
"item_on_disabled_layer": "error",
|
||||||
|
"items_not_allowed": "error",
|
||||||
|
"length_out_of_range": "error",
|
||||||
|
"lib_footprint_issues": "warning",
|
||||||
|
"lib_footprint_mismatch": "warning",
|
||||||
|
"malformed_courtyard": "error",
|
||||||
|
"microvia_drill_out_of_range": "error",
|
||||||
|
"mirrored_text_on_front_layer": "warning",
|
||||||
|
"missing_courtyard": "ignore",
|
||||||
|
"missing_footprint": "warning",
|
||||||
|
"missing_tuning_profile": "warning",
|
||||||
|
"net_conflict": "warning",
|
||||||
|
"nonmirrored_text_on_back_layer": "warning",
|
||||||
|
"npth_inside_courtyard": "error",
|
||||||
|
"padstack": "warning",
|
||||||
|
"pth_inside_courtyard": "error",
|
||||||
|
"shorting_items": "error",
|
||||||
|
"silk_edge_clearance": "warning",
|
||||||
|
"silk_over_copper": "warning",
|
||||||
|
"silk_overlap": "warning",
|
||||||
|
"skew_out_of_range": "error",
|
||||||
|
"solder_mask_bridge": "error",
|
||||||
|
"starved_thermal": "error",
|
||||||
|
"text_height": "warning",
|
||||||
|
"text_on_edge_cuts": "error",
|
||||||
|
"text_thickness": "warning",
|
||||||
|
"through_hole_pad_without_hole": "error",
|
||||||
|
"too_many_vias": "error",
|
||||||
|
"track_angle": "error",
|
||||||
|
"track_dangling": "warning",
|
||||||
|
"track_not_centered_on_via": "ignore",
|
||||||
|
"track_on_post_machined_layer": "error",
|
||||||
|
"track_segment_length": "error",
|
||||||
|
"track_width": "error",
|
||||||
|
"tracks_crossing": "error",
|
||||||
|
"tuning_profile_track_geometries": "ignore",
|
||||||
|
"unconnected_items": "error",
|
||||||
|
"unresolved_variable": "error",
|
||||||
|
"via_dangling": "warning",
|
||||||
|
"zones_intersect": "error"
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"max_error": 0.005,
|
||||||
|
"min_clearance": 0.0,
|
||||||
|
"min_connection": 0.0,
|
||||||
|
"min_copper_edge_clearance": 0.5,
|
||||||
|
"min_groove_width": 0.0,
|
||||||
|
"min_hole_clearance": 0.25,
|
||||||
|
"min_hole_to_hole": 0.25,
|
||||||
|
"min_microvia_diameter": 0.2,
|
||||||
|
"min_microvia_drill": 0.1,
|
||||||
|
"min_resolved_spokes": 2,
|
||||||
|
"min_silk_clearance": 0.0,
|
||||||
|
"min_text_height": 0.8,
|
||||||
|
"min_text_thickness": 0.08,
|
||||||
|
"min_through_hole_diameter": 0.3,
|
||||||
|
"min_track_width": 0.2,
|
||||||
|
"min_via_annular_width": 0.1,
|
||||||
|
"min_via_diameter": 0.5,
|
||||||
|
"solder_mask_to_copper_clearance": 0.005,
|
||||||
|
"use_height_for_length_calcs": true
|
||||||
|
},
|
||||||
|
"teardrop_options": [
|
||||||
|
{
|
||||||
|
"td_onpthpad": true,
|
||||||
|
"td_onroundshapesonly": false,
|
||||||
|
"td_onsmdpad": true,
|
||||||
|
"td_ontrackend": false,
|
||||||
|
"td_onvia": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"teardrop_parameters": [
|
||||||
|
{
|
||||||
|
"td_allow_use_two_tracks": true,
|
||||||
|
"td_curve_segcount": 0,
|
||||||
|
"td_height_ratio": 1.0,
|
||||||
|
"td_length_ratio": 0.5,
|
||||||
|
"td_maxheight": 2.0,
|
||||||
|
"td_maxlen": 1.0,
|
||||||
|
"td_on_pad_in_zone": false,
|
||||||
|
"td_target_name": "td_round_shape",
|
||||||
|
"td_width_to_size_filter_ratio": 0.9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"td_allow_use_two_tracks": true,
|
||||||
|
"td_curve_segcount": 0,
|
||||||
|
"td_height_ratio": 1.0,
|
||||||
|
"td_length_ratio": 0.5,
|
||||||
|
"td_maxheight": 2.0,
|
||||||
|
"td_maxlen": 1.0,
|
||||||
|
"td_on_pad_in_zone": false,
|
||||||
|
"td_target_name": "td_rect_shape",
|
||||||
|
"td_width_to_size_filter_ratio": 0.9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"td_allow_use_two_tracks": true,
|
||||||
|
"td_curve_segcount": 0,
|
||||||
|
"td_height_ratio": 1.0,
|
||||||
|
"td_length_ratio": 0.5,
|
||||||
|
"td_maxheight": 2.0,
|
||||||
|
"td_maxlen": 1.0,
|
||||||
|
"td_on_pad_in_zone": false,
|
||||||
|
"td_target_name": "td_track_end",
|
||||||
|
"td_width_to_size_filter_ratio": 0.9
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"track_widths": [
|
||||||
|
0.0,
|
||||||
|
0.01,
|
||||||
|
0.15,
|
||||||
|
0.25,
|
||||||
|
0.3,
|
||||||
|
0.5,
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
"tuning_pattern_settings": {
|
||||||
|
"diff_pair_defaults": {
|
||||||
|
"corner_radius_percentage": 80,
|
||||||
|
"corner_style": 1,
|
||||||
|
"max_amplitude": 1.0,
|
||||||
|
"min_amplitude": 0.2,
|
||||||
|
"single_sided": false,
|
||||||
|
"spacing": 1.0
|
||||||
|
},
|
||||||
|
"diff_pair_skew_defaults": {
|
||||||
|
"corner_radius_percentage": 80,
|
||||||
|
"corner_style": 1,
|
||||||
|
"max_amplitude": 1.0,
|
||||||
|
"min_amplitude": 0.2,
|
||||||
|
"single_sided": false,
|
||||||
|
"spacing": 0.6
|
||||||
|
},
|
||||||
|
"single_track_defaults": {
|
||||||
|
"corner_radius_percentage": 80,
|
||||||
|
"corner_style": 1,
|
||||||
|
"max_amplitude": 1.0,
|
||||||
|
"min_amplitude": 0.2,
|
||||||
|
"single_sided": false,
|
||||||
|
"spacing": 0.6
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"via_dimensions": [
|
||||||
|
{
|
||||||
|
"diameter": 0.0,
|
||||||
|
"drill": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"diameter": 0.3,
|
||||||
|
"drill": 0.15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"diameter": 0.8,
|
||||||
|
"drill": 0.3
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"zones_allow_external_fillets": false
|
||||||
|
},
|
||||||
|
"filename": "hbox-watchdog-v5.kicad_pcb",
|
||||||
|
"ipc2581": {
|
||||||
|
"bom_rev": "",
|
||||||
|
"dist": "",
|
||||||
|
"distpn": "",
|
||||||
|
"internal_id": "",
|
||||||
|
"mfg": "",
|
||||||
|
"mpn": "",
|
||||||
|
"sch_revision": "1.1"
|
||||||
|
},
|
||||||
|
"layer_pairs": [],
|
||||||
|
"layer_presets": [],
|
||||||
|
"viewports": []
|
||||||
|
},
|
||||||
|
"boards": [],
|
||||||
|
"component_class_settings": {
|
||||||
|
"assignments": [],
|
||||||
|
"meta": {
|
||||||
|
"version": 0
|
||||||
|
},
|
||||||
|
"sheet_component_classes": {
|
||||||
|
"enabled": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cvpcb": {
|
||||||
|
"equivalence_files": []
|
||||||
|
},
|
||||||
|
"erc": {
|
||||||
|
"erc_exclusions": [],
|
||||||
|
"meta": {
|
||||||
|
"version": 0
|
||||||
|
},
|
||||||
|
"pin_map": [
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"rule_severities": {
|
||||||
|
"bus_definition_conflict": "error",
|
||||||
|
"bus_entry_needed": "error",
|
||||||
|
"bus_to_bus_conflict": "error",
|
||||||
|
"bus_to_net_conflict": "error",
|
||||||
|
"different_unit_footprint": "error",
|
||||||
|
"different_unit_net": "error",
|
||||||
|
"duplicate_reference": "error",
|
||||||
|
"duplicate_sheet_names": "error",
|
||||||
|
"endpoint_off_grid": "ignore",
|
||||||
|
"extra_units": "error",
|
||||||
|
"field_name_whitespace": "warning",
|
||||||
|
"footprint_filter": "ignore",
|
||||||
|
"footprint_link_issues": "warning",
|
||||||
|
"four_way_junction": "ignore",
|
||||||
|
"ground_pin_not_ground": "warning",
|
||||||
|
"hier_label_mismatch": "error",
|
||||||
|
"isolated_pin_label": "warning",
|
||||||
|
"label_dangling": "error",
|
||||||
|
"label_multiple_wires": "warning",
|
||||||
|
"lib_symbol_issues": "warning",
|
||||||
|
"lib_symbol_mismatch": "warning",
|
||||||
|
"missing_bidi_pin": "warning",
|
||||||
|
"missing_input_pin": "warning",
|
||||||
|
"missing_power_pin": "error",
|
||||||
|
"missing_unit": "warning",
|
||||||
|
"multiple_net_names": "warning",
|
||||||
|
"net_not_bus_member": "warning",
|
||||||
|
"no_connect_connected": "warning",
|
||||||
|
"no_connect_dangling": "warning",
|
||||||
|
"pin_not_connected": "error",
|
||||||
|
"pin_not_driven": "error",
|
||||||
|
"pin_to_pin": "warning",
|
||||||
|
"power_pin_not_driven": "error",
|
||||||
|
"same_local_global_label": "warning",
|
||||||
|
"similar_label_and_power": "warning",
|
||||||
|
"similar_labels": "warning",
|
||||||
|
"similar_power": "warning",
|
||||||
|
"simulation_model_issue": "ignore",
|
||||||
|
"single_global_label": "ignore",
|
||||||
|
"stacked_pin_name": "warning",
|
||||||
|
"unannotated": "error",
|
||||||
|
"unconnected_wire_endpoint": "warning",
|
||||||
|
"undefined_netclass": "error",
|
||||||
|
"unit_value_mismatch": "error",
|
||||||
|
"unresolved_variable": "error",
|
||||||
|
"wire_dangling": "error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"libraries": {
|
||||||
|
"pinned_footprint_libs": [],
|
||||||
|
"pinned_symbol_libs": []
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
"filename": "hbox-watchdog-v5.kicad_pro",
|
||||||
|
"version": 3
|
||||||
|
},
|
||||||
|
"net_settings": {
|
||||||
|
"classes": [
|
||||||
|
{
|
||||||
|
"bus_width": 12,
|
||||||
|
"clearance": 0.2,
|
||||||
|
"diff_pair_gap": 0.25,
|
||||||
|
"diff_pair_via_gap": 0.25,
|
||||||
|
"diff_pair_width": 0.2,
|
||||||
|
"line_style": 0,
|
||||||
|
"microvia_diameter": 0.3,
|
||||||
|
"microvia_drill": 0.1,
|
||||||
|
"name": "Default",
|
||||||
|
"pcb_color": "rgba(0, 0, 0, 0.000)",
|
||||||
|
"priority": 2147483647,
|
||||||
|
"schematic_color": "rgba(0, 0, 0, 0.000)",
|
||||||
|
"track_width": 0.2,
|
||||||
|
"tuning_profile": "",
|
||||||
|
"via_diameter": 0.6,
|
||||||
|
"via_drill": 0.3,
|
||||||
|
"wire_width": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bus_width": 12,
|
||||||
|
"clearance": 0.5,
|
||||||
|
"diff_pair_gap": 0.25,
|
||||||
|
"diff_pair_via_gap": 0.25,
|
||||||
|
"diff_pair_width": 0.2,
|
||||||
|
"line_style": 0,
|
||||||
|
"microvia_diameter": 0.3,
|
||||||
|
"microvia_drill": 0.1,
|
||||||
|
"name": "HV24",
|
||||||
|
"pcb_color": "rgba(0, 0, 0, 0.000)",
|
||||||
|
"priority": 0,
|
||||||
|
"schematic_color": "rgba(0, 0, 0, 0.000)",
|
||||||
|
"track_width": 0.5,
|
||||||
|
"tuning_profile": "",
|
||||||
|
"via_diameter": 0.8,
|
||||||
|
"via_drill": 0.4,
|
||||||
|
"wire_width": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bus_width": 12,
|
||||||
|
"clearance": 0.2,
|
||||||
|
"diff_pair_gap": 0.25,
|
||||||
|
"diff_pair_width": 0.2,
|
||||||
|
"line_style": 0,
|
||||||
|
"microvia_diameter": 0.3,
|
||||||
|
"microvia_drill": 0.1,
|
||||||
|
"name": "PWR_HI",
|
||||||
|
"pcb_color": "rgba(0, 0, 0, 0.000)",
|
||||||
|
"priority": 0,
|
||||||
|
"schematic_color": "rgba(0, 0, 0, 0.000)",
|
||||||
|
"track_width": 1.5,
|
||||||
|
"tuning_profile": "",
|
||||||
|
"via_diameter": 0.8,
|
||||||
|
"via_drill": 0.4,
|
||||||
|
"wire_width": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bus_width": 12,
|
||||||
|
"clearance": 0.2,
|
||||||
|
"diff_pair_gap": 0.25,
|
||||||
|
"diff_pair_width": 0.2,
|
||||||
|
"line_style": 0,
|
||||||
|
"microvia_diameter": 0.3,
|
||||||
|
"microvia_drill": 0.1,
|
||||||
|
"name": "PWR_MID",
|
||||||
|
"pcb_color": "rgba(0, 0, 0, 0.000)",
|
||||||
|
"priority": 1,
|
||||||
|
"schematic_color": "rgba(0, 0, 0, 0.000)",
|
||||||
|
"track_width": 1.0,
|
||||||
|
"tuning_profile": "",
|
||||||
|
"via_diameter": 0.8,
|
||||||
|
"via_drill": 0.4,
|
||||||
|
"wire_width": 6
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"meta": {
|
||||||
|
"version": 5
|
||||||
|
},
|
||||||
|
"net_colors": null,
|
||||||
|
"netclass_assignments": null,
|
||||||
|
"netclass_patterns": [
|
||||||
|
{
|
||||||
|
"netclass": "PWR_HI",
|
||||||
|
"pattern": "BAT_PLUS"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"netclass": "PWR_HI",
|
||||||
|
"pattern": "SW_BAT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"netclass": "PWR_HI",
|
||||||
|
"pattern": "MAIN5V"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"netclass": "PWR_HI",
|
||||||
|
"pattern": "VEH5V"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"netclass": "PWR_HI",
|
||||||
|
"pattern": "SYS5V"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"netclass": "PWR_HI",
|
||||||
|
"pattern": "VIN_SW"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"netclass": "PWR_MID",
|
||||||
|
"pattern": "SW_5V"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"netclass": "PWR_MID",
|
||||||
|
"pattern": "3V3_MODEM"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"netclass": "PWR_MID",
|
||||||
|
"pattern": "5V_FAN"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"netclass": "PWR_MID",
|
||||||
|
"pattern": "SW_FAN"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"netclass": "PWR_MID",
|
||||||
|
"pattern": "SW3_NODE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"netclass": "PWR_MID",
|
||||||
|
"pattern": "FAN_RET"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"netclass": "PWR_MID",
|
||||||
|
"pattern": "SW_IN"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"netclass": "HV24",
|
||||||
|
"pattern": "/24V_IN"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"netclass": "HV24",
|
||||||
|
"pattern": "24V"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"netclass": "HV24",
|
||||||
|
"pattern": "IGN_IN"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"netclass": "HV24",
|
||||||
|
"pattern": "Q10_GATE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"netclass": "PWR_HI",
|
||||||
|
"pattern": "/BAT_PLUS"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"netclass": "PWR_HI",
|
||||||
|
"pattern": "/SW_BAT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"netclass": "PWR_HI",
|
||||||
|
"pattern": "/MAIN5V"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"netclass": "PWR_HI",
|
||||||
|
"pattern": "/VEH5V"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"netclass": "PWR_HI",
|
||||||
|
"pattern": "/SYS5V"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"netclass": "PWR_HI",
|
||||||
|
"pattern": "/VIN_SW"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"netclass": "PWR_MID",
|
||||||
|
"pattern": "/SW_5V"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"netclass": "PWR_MID",
|
||||||
|
"pattern": "/3V3_MODEM"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"netclass": "PWR_MID",
|
||||||
|
"pattern": "/5V_FAN"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"netclass": "PWR_MID",
|
||||||
|
"pattern": "/SW_FAN"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"netclass": "PWR_MID",
|
||||||
|
"pattern": "/SW3_NODE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"netclass": "PWR_MID",
|
||||||
|
"pattern": "/FAN_RET"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"netclass": "PWR_MID",
|
||||||
|
"pattern": "/SW_IN"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"netclass": "PWR_MID",
|
||||||
|
"pattern": "/3V3_ETH"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"pcbnew": {
|
||||||
|
"last_paths": {
|
||||||
|
"idf": "",
|
||||||
|
"netlist": "./",
|
||||||
|
"plot": "",
|
||||||
|
"specctra_dsn": "hbox-watchdog-v5-PROD.dsn",
|
||||||
|
"vrml": ""
|
||||||
|
},
|
||||||
|
"page_layout_descr_file": ""
|
||||||
|
},
|
||||||
|
"schematic": {
|
||||||
|
"annotate_start_num": 0,
|
||||||
|
"annotation": {
|
||||||
|
"method": 0,
|
||||||
|
"sort_order": 0
|
||||||
|
},
|
||||||
|
"bom_export_filename": "${PROJECTNAME}.csv",
|
||||||
|
"bom_fmt_presets": [],
|
||||||
|
"bom_fmt_settings": {
|
||||||
|
"field_delimiter": ",",
|
||||||
|
"keep_line_breaks": false,
|
||||||
|
"keep_tabs": false,
|
||||||
|
"name": "CSV",
|
||||||
|
"ref_delimiter": ",",
|
||||||
|
"ref_range_delimiter": "",
|
||||||
|
"string_delimiter": "\""
|
||||||
|
},
|
||||||
|
"bom_presets": [],
|
||||||
|
"bom_settings": {
|
||||||
|
"exclude_dnp": false,
|
||||||
|
"fields_ordered": [
|
||||||
|
{
|
||||||
|
"group_by": false,
|
||||||
|
"label": "Reference",
|
||||||
|
"name": "Reference",
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group_by": false,
|
||||||
|
"label": "Qty",
|
||||||
|
"name": "${QUANTITY}",
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group_by": true,
|
||||||
|
"label": "Value",
|
||||||
|
"name": "Value",
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group_by": true,
|
||||||
|
"label": "DNP",
|
||||||
|
"name": "${DNP}",
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group_by": true,
|
||||||
|
"label": "Exclude from BOM",
|
||||||
|
"name": "${EXCLUDE_FROM_BOM}",
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group_by": true,
|
||||||
|
"label": "Exclude from Board",
|
||||||
|
"name": "${EXCLUDE_FROM_BOARD}",
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group_by": true,
|
||||||
|
"label": "Footprint",
|
||||||
|
"name": "Footprint",
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group_by": false,
|
||||||
|
"label": "Datasheet",
|
||||||
|
"name": "Datasheet",
|
||||||
|
"show": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"filter_string": "",
|
||||||
|
"group_symbols": true,
|
||||||
|
"include_excluded_from_bom": true,
|
||||||
|
"name": "Default Editing",
|
||||||
|
"sort_asc": true,
|
||||||
|
"sort_field": "Reference"
|
||||||
|
},
|
||||||
|
"bus_aliases": {},
|
||||||
|
"connection_grid_size": 50.0,
|
||||||
|
"drawing": {
|
||||||
|
"dashed_lines_dash_length_ratio": 12.0,
|
||||||
|
"dashed_lines_gap_length_ratio": 3.0,
|
||||||
|
"default_line_thickness": 6.0,
|
||||||
|
"default_text_size": 50.0,
|
||||||
|
"field_names": [],
|
||||||
|
"hop_over_size_choice": 0,
|
||||||
|
"intersheets_ref_own_page": false,
|
||||||
|
"intersheets_ref_prefix": "",
|
||||||
|
"intersheets_ref_short": false,
|
||||||
|
"intersheets_ref_show": false,
|
||||||
|
"intersheets_ref_suffix": "",
|
||||||
|
"junction_size_choice": 3,
|
||||||
|
"label_size_ratio": 0.375,
|
||||||
|
"operating_point_overlay_i_precision": 3,
|
||||||
|
"operating_point_overlay_i_range": "~A",
|
||||||
|
"operating_point_overlay_v_precision": 3,
|
||||||
|
"operating_point_overlay_v_range": "~V",
|
||||||
|
"overbar_offset_ratio": 1.23,
|
||||||
|
"pin_symbol_size": 25.0,
|
||||||
|
"text_offset_ratio": 0.15
|
||||||
|
},
|
||||||
|
"legacy_lib_dir": "",
|
||||||
|
"legacy_lib_list": [],
|
||||||
|
"meta": {
|
||||||
|
"version": 1
|
||||||
|
},
|
||||||
|
"page_layout_descr_file": "",
|
||||||
|
"plot_directory": "",
|
||||||
|
"reuse_designators": true,
|
||||||
|
"subpart_first_id": 65,
|
||||||
|
"subpart_id_separator": 0,
|
||||||
|
"top_level_sheets": [
|
||||||
|
{
|
||||||
|
"filename": "hbox-watchdog-v5.kicad_sch",
|
||||||
|
"name": "hbox-watchdog-v3",
|
||||||
|
"uuid": "561403b3-895e-4153-a7be-3876ae930d43"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"used_designators": "SW4G1,Rmled1,Rcomp1,Dbk1,Rfreq1,Rgs1,Cbst1,Rtp1,Rdfu1,Rled1,D4G1,Rigb1,Rig1,#PWR1-4,Ccomp1,Rrp1,Rg1,Rts1,DzG1",
|
||||||
|
"variants": []
|
||||||
|
},
|
||||||
|
"sheets": [
|
||||||
|
[
|
||||||
|
"561403b3-895e-4153-a7be-3876ae930d43",
|
||||||
|
"hbox-watchdog-v3"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"text_variables": {},
|
||||||
|
"tuning_profiles": {
|
||||||
|
"meta": {
|
||||||
|
"version": 0
|
||||||
|
},
|
||||||
|
"tuning_profiles_impedance_geometric": []
|
||||||
|
}
|
||||||
|
}
|
||||||
43775
03-Architecture-Hardware/kicad/hbox-watchdog-v5.kicad_sch
Normal file
43775
03-Architecture-Hardware/kicad/hbox-watchdog-v5.kicad_sch
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,498 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="405 355 365 220" font-family="monospace">
|
||||||
|
<rect x="405" y="355" width="365" height="220" fill="#fffef7"/>
|
||||||
|
<text x="495.3" y="386.08" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 495.3 386.08)">3V3</text>
|
||||||
|
<text x="482.6" y="449.58" font-size="1.6" fill="#7a1fa2" text-anchor="end">LED_C13</text>
|
||||||
|
<text x="482.6" y="452.12" font-size="1.6" fill="#7a1fa2" text-anchor="end">LSE_IN</text>
|
||||||
|
<text x="482.6" y="454.66" font-size="1.6" fill="#7a1fa2" text-anchor="end">LSE_OUT</text>
|
||||||
|
<text x="482.6" y="403.86" font-size="1.6" fill="#7a1fa2" text-anchor="end">HSE_IN</text>
|
||||||
|
<text x="482.6" y="406.4" font-size="1.6" fill="#7a1fa2" text-anchor="end">HSE_OUT</text>
|
||||||
|
<text x="482.6" y="393.7" font-size="1.6" fill="#7a1fa2" text-anchor="end">NRST</text>
|
||||||
|
<text x="482.6" y="416.56" font-size="1.6" fill="#7a1fa2" text-anchor="end">ETH_INT</text>
|
||||||
|
<text x="502.92" y="480.06" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 502.92 480.06)">GND</text>
|
||||||
|
<text x="508.0" y="386.08" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 508.0 386.08)">VDDA</text>
|
||||||
|
<text x="518.16" y="393.7" font-size="1.6" fill="#7a1fa2" text-anchor="start">BAT_SENSE</text>
|
||||||
|
<text x="518.16" y="396.24" font-size="1.6" fill="#7a1fa2" text-anchor="start">PWR_CTRL</text>
|
||||||
|
<text x="518.16" y="398.78" font-size="1.6" fill="#7a1fa2" text-anchor="start">GNSS_TX</text>
|
||||||
|
<text x="518.16" y="401.32" font-size="1.6" fill="#7a1fa2" text-anchor="start">GNSS_RX</text>
|
||||||
|
<text x="500.38" y="480.06" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 500.38 480.06)">GND</text>
|
||||||
|
<text x="497.84" y="386.08" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 497.84 386.08)">3V3</text>
|
||||||
|
<text x="518.16" y="403.86" font-size="1.6" fill="#7a1fa2" text-anchor="start">5V_SENSE</text>
|
||||||
|
<text x="518.16" y="406.4" font-size="1.6" fill="#7a1fa2" text-anchor="start">IGN_SENSE</text>
|
||||||
|
<text x="518.16" y="408.94" font-size="1.6" fill="#7a1fa2" text-anchor="start">FAN_PWM</text>
|
||||||
|
<text x="518.16" y="436.88" font-size="1.6" fill="#7a1fa2" text-anchor="start">EXT_LED</text>
|
||||||
|
<text x="518.16" y="439.42" font-size="1.6" fill="#7a1fa2" text-anchor="start">NTC_TEMP</text>
|
||||||
|
<text x="518.16" y="441.96" font-size="1.6" fill="#7a1fa2" text-anchor="start">BOOT1_STRAP</text>
|
||||||
|
<text x="482.6" y="459.74" font-size="1.6" fill="#7a1fa2" text-anchor="end">VCAP1</text>
|
||||||
|
<text x="500.38" y="386.08" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 500.38 386.08)">3V3</text>
|
||||||
|
<text x="518.16" y="464.82" font-size="1.6" fill="#7a1fa2" text-anchor="start">ETH_CS</text>
|
||||||
|
<text x="518.16" y="467.36" font-size="1.6" fill="#7a1fa2" text-anchor="start">ETH_SCK</text>
|
||||||
|
<text x="518.16" y="469.9" font-size="1.6" fill="#7a1fa2" text-anchor="start">ETH_MISO</text>
|
||||||
|
<text x="518.16" y="472.44" font-size="1.6" fill="#7a1fa2" text-anchor="start">ETH_MOSI</text>
|
||||||
|
<text x="518.16" y="414.02" font-size="1.6" fill="#7a1fa2" text-anchor="start">CHRG_EN</text>
|
||||||
|
<text x="518.16" y="416.56" font-size="1.6" fill="#7a1fa2" text-anchor="start">USART1_TX</text>
|
||||||
|
<text x="518.16" y="419.1" font-size="1.6" fill="#7a1fa2" text-anchor="start">USART1_RX</text>
|
||||||
|
<text x="518.16" y="421.64" font-size="1.6" fill="#7a1fa2" text-anchor="start">DFU_DM</text>
|
||||||
|
<text x="518.16" y="424.18" font-size="1.6" fill="#7a1fa2" text-anchor="start">DFU_DP</text>
|
||||||
|
<text x="518.16" y="426.72" font-size="1.6" fill="#7a1fa2" text-anchor="start">SWDIO</text>
|
||||||
|
<text x="502.92" y="386.08" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 502.92 386.08)">3V3</text>
|
||||||
|
<text x="518.16" y="429.26" font-size="1.6" fill="#7a1fa2" text-anchor="start">SWCLK</text>
|
||||||
|
<text x="518.16" y="431.8" font-size="1.6" fill="#7a1fa2" text-anchor="start">ETH_RST</text>
|
||||||
|
<text x="518.16" y="444.5" font-size="1.6" fill="#7a1fa2" text-anchor="start">CHRG_STAT</text>
|
||||||
|
<text x="518.16" y="447.04" font-size="1.6" fill="#7a1fa2" text-anchor="start">CHRG_FAULT</text>
|
||||||
|
<text x="518.16" y="449.58" font-size="1.6" fill="#7a1fa2" text-anchor="start">BYP_CTRL</text>
|
||||||
|
<text x="518.16" y="452.12" font-size="1.6" fill="#7a1fa2" text-anchor="start">I2C_SCL</text>
|
||||||
|
<text x="518.16" y="454.66" font-size="1.6" fill="#7a1fa2" text-anchor="start">I2C_SDA</text>
|
||||||
|
<text x="482.6" y="398.78" font-size="1.6" fill="#7a1fa2" text-anchor="end">BOOT0</text>
|
||||||
|
<text x="518.16" y="457.2" font-size="1.6" fill="#7a1fa2" text-anchor="start">SER_IRQ</text>
|
||||||
|
<text x="505.46" y="386.08" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 505.46 386.08)">3V3</text>
|
||||||
|
<text x="431.8" y="502.92" font-size="1.6" fill="#7a1fa2" text-anchor="end">3V3</text>
|
||||||
|
<text x="441.96" y="502.92" font-size="1.6" fill="#7a1fa2" text-anchor="start">BOOT0</text>
|
||||||
|
<text x="449.58" y="499.11" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 449.58 499.11)">BOOT0</text>
|
||||||
|
<text x="449.58" y="506.73" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 449.58 506.73)">GND</text>
|
||||||
|
<text x="462.28" y="499.11" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 462.28 499.11)">BOOT1_STRAP</text>
|
||||||
|
<text x="462.28" y="506.73" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 462.28 506.73)">GND</text>
|
||||||
|
<text x="474.98" y="499.11" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 474.98 499.11)">NRST</text>
|
||||||
|
<text x="474.98" y="506.73" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 474.98 506.73)">GND</text>
|
||||||
|
<text x="487.68" y="499.11" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 487.68 499.11)">3V3</text>
|
||||||
|
<text x="487.68" y="506.73" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 487.68 506.73)">GND</text>
|
||||||
|
<text x="500.38" y="499.11" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 500.38 499.11)">3V3</text>
|
||||||
|
<text x="500.38" y="506.73" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 500.38 506.73)">GND</text>
|
||||||
|
<text x="513.08" y="499.11" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 513.08 499.11)">3V3</text>
|
||||||
|
<text x="513.08" y="506.73" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 513.08 506.73)">GND</text>
|
||||||
|
<text x="525.78" y="499.11" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 525.78 499.11)">3V3</text>
|
||||||
|
<text x="525.78" y="506.73" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 525.78 506.73)">GND</text>
|
||||||
|
<text x="538.48" y="499.11" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 538.48 499.11)">VDDA</text>
|
||||||
|
<text x="538.48" y="506.73" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 538.48 506.73)">GND</text>
|
||||||
|
<text x="551.18" y="499.11" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 551.18 499.11)">3V3</text>
|
||||||
|
<text x="551.18" y="506.73" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 551.18 506.73)">GND</text>
|
||||||
|
<text x="563.88" y="499.11" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 563.88 499.11)">VCAP1</text>
|
||||||
|
<text x="563.88" y="506.73" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 563.88 506.73)">GND</text>
|
||||||
|
<text x="576.58" y="499.11" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 576.58 499.11)">VDDA</text>
|
||||||
|
<text x="576.58" y="506.73" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 576.58 506.73)">GND</text>
|
||||||
|
<text x="589.28" y="499.11" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 589.28 499.11)">3V3</text>
|
||||||
|
<text x="589.28" y="506.73" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 589.28 506.73)">VDDA</text>
|
||||||
|
<text x="433.07" y="530.86" font-size="1.6" fill="#7a1fa2" text-anchor="end">HSE_IN</text>
|
||||||
|
<text x="440.69" y="530.86" font-size="1.6" fill="#7a1fa2" text-anchor="start">HSE_OUT</text>
|
||||||
|
<text x="449.58" y="527.05" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 449.58 527.05)">HSE_IN</text>
|
||||||
|
<text x="449.58" y="534.67" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 449.58 534.67)">GND</text>
|
||||||
|
<text x="462.28" y="527.05" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 462.28 527.05)">HSE_OUT</text>
|
||||||
|
<text x="462.28" y="534.67" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 462.28 534.67)">GND</text>
|
||||||
|
<text x="471.17" y="530.86" font-size="1.6" fill="#7a1fa2" text-anchor="end">LSE_IN</text>
|
||||||
|
<text x="478.79" y="530.86" font-size="1.6" fill="#7a1fa2" text-anchor="start">LSE_OUT</text>
|
||||||
|
<text x="487.68" y="527.05" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 487.68 527.05)">LSE_IN</text>
|
||||||
|
<text x="487.68" y="534.67" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 487.68 534.67)">GND</text>
|
||||||
|
<text x="500.38" y="527.05" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 500.38 527.05)">LSE_OUT</text>
|
||||||
|
<text x="500.38" y="534.67" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 500.38 534.67)">GND</text>
|
||||||
|
<text x="513.08" y="527.05" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 513.08 527.05)">3V3</text>
|
||||||
|
<text x="513.08" y="534.67" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 513.08 534.67)">LED_C13_A</text>
|
||||||
|
<text x="521.97" y="530.86" font-size="1.6" fill="#7a1fa2" text-anchor="end">LED_C13</text>
|
||||||
|
<text x="529.59" y="530.86" font-size="1.6" fill="#7a1fa2" text-anchor="start">LED_C13_A</text>
|
||||||
|
<text x="538.48" y="527.05" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 538.48 527.05)">3V3</text>
|
||||||
|
<text x="538.48" y="534.67" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 538.48 534.67)">LED_PWR_A</text>
|
||||||
|
<text x="547.37" y="530.86" font-size="1.6" fill="#7a1fa2" text-anchor="end">GND</text>
|
||||||
|
<text x="554.99" y="530.86" font-size="1.6" fill="#7a1fa2" text-anchor="start">LED_PWR_A</text>
|
||||||
|
<text x="563.88" y="530.86" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 563.88 530.86)">SWDIO</text>
|
||||||
|
<text x="576.58" y="530.86" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 576.58 530.86)">SWCLK</text>
|
||||||
|
<text x="589.28" y="530.86" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 589.28 530.86)">NRST</text>
|
||||||
|
<text x="601.98" y="530.86" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 601.98 530.86)">GND</text>
|
||||||
|
<text x="614.68" y="530.86" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 614.68 530.86)">3V3</text>
|
||||||
|
<text x="623.57" y="502.92" font-size="1.6" fill="#7a1fa2" text-anchor="end">LDO_IN</text>
|
||||||
|
<text x="631.19" y="502.92" font-size="1.6" fill="#7a1fa2" text-anchor="start">SYS5V</text>
|
||||||
|
<text x="636.27" y="502.92" font-size="1.6" fill="#7a1fa2" text-anchor="end">LDO_IN</text>
|
||||||
|
<text x="643.89" y="502.92" font-size="1.6" fill="#7a1fa2" text-anchor="start">DFU_VBUS</text>
|
||||||
|
<text x="665.48" y="510.54" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 665.48 510.54)">GND</text>
|
||||||
|
<text x="673.1" y="502.92" font-size="1.6" fill="#7a1fa2" text-anchor="start">3V3</text>
|
||||||
|
<text x="657.86" y="502.92" font-size="1.6" fill="#7a1fa2" text-anchor="end">LDO_IN</text>
|
||||||
|
<text x="690.88" y="499.11" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 690.88 499.11)">LDO_IN</text>
|
||||||
|
<text x="690.88" y="506.73" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 690.88 506.73)">GND</text>
|
||||||
|
<text x="703.58" y="499.11" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 703.58 499.11)">3V3</text>
|
||||||
|
<text x="703.58" y="506.73" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 703.58 506.73)">GND</text>
|
||||||
|
<text x="716.28" y="502.92" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 716.28 502.92)">LDO_IN</text>
|
||||||
|
<text x="728.98" y="502.92" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 728.98 502.92)">DFU_VBUS</text>
|
||||||
|
<text x="660.4" y="453.39" font-size="1.6" fill="#7a1fa2" text-anchor="start">GND</text>
|
||||||
|
<text x="675.64" y="415.29" font-size="1.6" fill="#7a1fa2" text-anchor="start">DFU_VBUS</text>
|
||||||
|
<text x="675.64" y="420.37" font-size="1.6" fill="#7a1fa2" text-anchor="start">DFU_CC1</text>
|
||||||
|
<text x="675.64" y="433.07" font-size="1.6" fill="#7a1fa2" text-anchor="start">DFU_DP</text>
|
||||||
|
<text x="675.64" y="427.99" font-size="1.6" fill="#7a1fa2" text-anchor="start">DFU_DM</text>
|
||||||
|
<text x="675.64" y="415.29" font-size="1.6" fill="#7a1fa2" text-anchor="start">DFU_VBUS</text>
|
||||||
|
<text x="660.4" y="453.39" font-size="1.6" fill="#7a1fa2" text-anchor="start">GND</text>
|
||||||
|
<text x="660.4" y="453.39" font-size="1.6" fill="#7a1fa2" text-anchor="start">GND</text>
|
||||||
|
<text x="675.64" y="415.29" font-size="1.6" fill="#7a1fa2" text-anchor="start">DFU_VBUS</text>
|
||||||
|
<text x="675.64" y="422.91" font-size="1.6" fill="#7a1fa2" text-anchor="start">DFU_CC2</text>
|
||||||
|
<text x="675.64" y="435.61" font-size="1.6" fill="#7a1fa2" text-anchor="start">DFU_DP</text>
|
||||||
|
<text x="675.64" y="430.53" font-size="1.6" fill="#7a1fa2" text-anchor="start">DFU_DM</text>
|
||||||
|
<text x="675.64" y="415.29" font-size="1.6" fill="#7a1fa2" text-anchor="start">DFU_VBUS</text>
|
||||||
|
<text x="660.4" y="453.39" font-size="1.6" fill="#7a1fa2" text-anchor="start">GND</text>
|
||||||
|
<text x="652.78" y="453.39" font-size="1.6" fill="#7a1fa2" text-anchor="end">GND</text>
|
||||||
|
<text x="704.85" y="426.72" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 704.85 426.72)">DFU_CC1</text>
|
||||||
|
<text x="704.85" y="434.34" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 704.85 434.34)">GND</text>
|
||||||
|
<text x="717.55" y="426.72" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 717.55 426.72)">DFU_CC2</text>
|
||||||
|
<text x="717.55" y="434.34" font-size="1.6" fill="#7a1fa2" text-anchor="start" transform="rotate(-90 717.55 434.34)">GND</text>
|
||||||
|
<text x="701.04" y="458.47" font-size="1.6" fill="#7a1fa2" text-anchor="end">DFU_DP</text>
|
||||||
|
<text x="708.66" y="458.47" font-size="1.6" fill="#7a1fa2" text-anchor="start">GND</text>
|
||||||
|
<text x="713.74" y="458.47" font-size="1.6" fill="#7a1fa2" text-anchor="end">DFU_DM</text>
|
||||||
|
<text x="721.36" y="458.47" font-size="1.6" fill="#7a1fa2" text-anchor="start">GND</text>
|
||||||
|
<text x="726.44" y="458.47" font-size="1.6" fill="#7a1fa2" text-anchor="end">DFU_VBUS</text>
|
||||||
|
<text x="734.06" y="458.47" font-size="1.6" fill="#7a1fa2" text-anchor="start">GND</text>
|
||||||
|
<path d="M481.8,418.3 L483.40000000000003,419.90000000000003 M481.8,419.90000000000003 L483.40000000000003,418.3" stroke="#0288d1" stroke-width="0.25"/>
|
||||||
|
<path d="M481.8,420.84 L483.40000000000003,422.44 M481.8,422.44 L483.40000000000003,420.84" stroke="#0288d1" stroke-width="0.25"/>
|
||||||
|
<path d="M481.8,423.38 L483.40000000000003,424.98 M481.8,424.98 L483.40000000000003,423.38" stroke="#0288d1" stroke-width="0.25"/>
|
||||||
|
<path d="M517.36,410.68 L518.9599999999999,412.28000000000003 M517.36,412.28000000000003 L518.9599999999999,410.68" stroke="#0288d1" stroke-width="0.25"/>
|
||||||
|
<path d="M481.8,425.92 L483.40000000000003,427.52000000000004 M481.8,427.52000000000004 L483.40000000000003,425.92" stroke="#0288d1" stroke-width="0.25"/>
|
||||||
|
<path d="M481.8,428.46 L483.40000000000003,430.06 M481.8,430.06 L483.40000000000003,428.46" stroke="#0288d1" stroke-width="0.25"/>
|
||||||
|
<path d="M517.36,461.47999999999996 L518.9599999999999,463.08 M517.36,463.08 L518.9599999999999,461.47999999999996" stroke="#0288d1" stroke-width="0.25"/>
|
||||||
|
<path d="M481.8,431.0 L483.40000000000003,432.6 M481.8,432.6 L483.40000000000003,431.0" stroke="#0288d1" stroke-width="0.25"/>
|
||||||
|
<path d="M481.8,433.53999999999996 L483.40000000000003,435.14 M481.8,435.14 L483.40000000000003,433.53999999999996" stroke="#0288d1" stroke-width="0.25"/>
|
||||||
|
<path d="M481.8,436.08 L483.40000000000003,437.68 M481.8,437.68 L483.40000000000003,436.08" stroke="#0288d1" stroke-width="0.25"/>
|
||||||
|
<path d="M481.8,438.62 L483.40000000000003,440.22 M481.8,440.22 L483.40000000000003,438.62" stroke="#0288d1" stroke-width="0.25"/>
|
||||||
|
<path d="M481.8,441.15999999999997 L483.40000000000003,442.76 M481.8,442.76 L483.40000000000003,441.15999999999997" stroke="#0288d1" stroke-width="0.25"/>
|
||||||
|
<path d="M481.8,443.7 L483.40000000000003,445.3 M481.8,445.3 L483.40000000000003,443.7" stroke="#0288d1" stroke-width="0.25"/>
|
||||||
|
<path d="M481.8,446.24 L483.40000000000003,447.84000000000003 M481.8,447.84000000000003 L483.40000000000003,446.24" stroke="#0288d1" stroke-width="0.25"/>
|
||||||
|
<path d="M481.8,410.68 L483.40000000000003,412.28000000000003 M481.8,412.28000000000003 L483.40000000000003,410.68" stroke="#0288d1" stroke-width="0.25"/>
|
||||||
|
<path d="M517.36,458.94 L518.9599999999999,460.54 M517.36,460.54 L518.9599999999999,458.94" stroke="#0288d1" stroke-width="0.25"/>
|
||||||
|
<rect x="480.6" y="385.34999999999997" width="39.56" height="97.97999999999999" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="495.3" cy="386.08" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="495.3" y="386.58" font-size="1.35" fill="#333" text-anchor="middle">VBAT</text>
|
||||||
|
<circle cx="482.6" cy="449.58" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="483.5" y="450.08" font-size="1.35" fill="#333" text-anchor="start">PC13</text>
|
||||||
|
<circle cx="482.6" cy="452.12" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="483.5" y="452.62" font-size="1.35" fill="#333" text-anchor="start">PC14</text>
|
||||||
|
<circle cx="482.6" cy="454.65999999999997" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="483.5" y="455.15999999999997" font-size="1.35" fill="#333" text-anchor="start">PC15</text>
|
||||||
|
<circle cx="482.6" cy="403.85999999999996" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="483.5" y="404.35999999999996" font-size="1.35" fill="#333" text-anchor="start">PH0</text>
|
||||||
|
<circle cx="482.6" cy="406.4" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="483.5" y="406.9" font-size="1.35" fill="#333" text-anchor="start">PH1</text>
|
||||||
|
<circle cx="482.6" cy="393.7" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="483.5" y="394.2" font-size="1.35" fill="#333" text-anchor="start">NRST</text>
|
||||||
|
<circle cx="482.6" cy="416.55999999999995" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="483.5" y="417.05999999999995" font-size="1.35" fill="#333" text-anchor="start">PC0</text>
|
||||||
|
<circle cx="482.6" cy="419.09999999999997" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="483.5" y="419.59999999999997" font-size="1.35" fill="#333" text-anchor="start">PC1</text>
|
||||||
|
<circle cx="482.6" cy="421.64" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="483.5" y="422.14" font-size="1.35" fill="#333" text-anchor="start">PC2</text>
|
||||||
|
<circle cx="482.6" cy="424.17999999999995" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="483.5" y="424.67999999999995" font-size="1.35" fill="#333" text-anchor="start">PC3</text>
|
||||||
|
<circle cx="502.92" cy="480.05999999999995" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="502.92" y="480.55999999999995" font-size="1.35" fill="#333" text-anchor="middle">VSSA</text>
|
||||||
|
<circle cx="508.0" cy="386.08" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="508.0" y="386.58" font-size="1.35" fill="#333" text-anchor="middle">VDDA</text>
|
||||||
|
<circle cx="518.16" cy="393.7" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="517.26" y="394.2" font-size="1.35" fill="#333" text-anchor="end">PA0</text>
|
||||||
|
<circle cx="518.16" cy="396.23999999999995" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="517.26" y="396.73999999999995" font-size="1.35" fill="#333" text-anchor="end">PA1</text>
|
||||||
|
<circle cx="518.16" cy="398.78" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="517.26" y="399.28" font-size="1.35" fill="#333" text-anchor="end">PA2</text>
|
||||||
|
<circle cx="518.16" cy="401.32" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="517.26" y="401.82" font-size="1.35" fill="#333" text-anchor="end">PA3</text>
|
||||||
|
<circle cx="500.38" cy="480.05999999999995" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="500.38" y="480.55999999999995" font-size="1.35" fill="#333" text-anchor="middle">VSS</text>
|
||||||
|
<circle cx="497.84" cy="386.08" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="497.84" y="386.58" font-size="1.35" fill="#333" text-anchor="middle">VDD</text>
|
||||||
|
<circle cx="518.16" cy="403.85999999999996" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="517.26" y="404.35999999999996" font-size="1.35" fill="#333" text-anchor="end">PA4</text>
|
||||||
|
<circle cx="518.16" cy="406.4" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="517.26" y="406.9" font-size="1.35" fill="#333" text-anchor="end">PA5</text>
|
||||||
|
<circle cx="518.16" cy="408.94" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="517.26" y="409.44" font-size="1.35" fill="#333" text-anchor="end">PA6</text>
|
||||||
|
<circle cx="518.16" cy="411.47999999999996" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="517.26" y="411.97999999999996" font-size="1.35" fill="#333" text-anchor="end">PA7</text>
|
||||||
|
<circle cx="482.6" cy="426.71999999999997" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="483.5" y="427.21999999999997" font-size="1.35" fill="#333" text-anchor="start">PC4</text>
|
||||||
|
<circle cx="482.6" cy="429.26" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="483.5" y="429.76" font-size="1.35" fill="#333" text-anchor="start">PC5</text>
|
||||||
|
<circle cx="518.16" cy="436.88" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="517.26" y="437.38" font-size="1.35" fill="#333" text-anchor="end">PB0</text>
|
||||||
|
<circle cx="518.16" cy="439.41999999999996" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="517.26" y="439.91999999999996" font-size="1.35" fill="#333" text-anchor="end">PB1</text>
|
||||||
|
<circle cx="518.16" cy="441.96" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="517.26" y="442.46" font-size="1.35" fill="#333" text-anchor="end">PB2</text>
|
||||||
|
<circle cx="518.16" cy="462.28" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="517.26" y="462.78" font-size="1.35" fill="#333" text-anchor="end">PB10</text>
|
||||||
|
<circle cx="482.6" cy="459.73999999999995" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="483.5" y="460.23999999999995" font-size="1.35" fill="#333" text-anchor="start">VCAP1</text>
|
||||||
|
<circle cx="500.38" cy="480.05999999999995" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="500.38" y="480.55999999999995" font-size="1.35" fill="#333" text-anchor="middle">VSS</text>
|
||||||
|
<circle cx="500.38" cy="386.08" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="500.38" y="386.58" font-size="1.35" fill="#333" text-anchor="middle">VDD</text>
|
||||||
|
<circle cx="518.16" cy="464.82" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="517.26" y="465.32" font-size="1.35" fill="#333" text-anchor="end">PB12</text>
|
||||||
|
<circle cx="518.16" cy="467.35999999999996" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="517.26" y="467.85999999999996" font-size="1.35" fill="#333" text-anchor="end">PB13</text>
|
||||||
|
<circle cx="518.16" cy="469.9" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="517.26" y="470.4" font-size="1.35" fill="#333" text-anchor="end">PB14</text>
|
||||||
|
<circle cx="518.16" cy="472.44" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="517.26" y="472.94" font-size="1.35" fill="#333" text-anchor="end">PB15</text>
|
||||||
|
<circle cx="482.6" cy="431.79999999999995" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="483.5" y="432.29999999999995" font-size="1.35" fill="#333" text-anchor="start">PC6</text>
|
||||||
|
<circle cx="482.6" cy="434.34" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="483.5" y="434.84" font-size="1.35" fill="#333" text-anchor="start">PC7</text>
|
||||||
|
<circle cx="482.6" cy="436.88" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="483.5" y="437.38" font-size="1.35" fill="#333" text-anchor="start">PC8</text>
|
||||||
|
<circle cx="482.6" cy="439.41999999999996" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="483.5" y="439.91999999999996" font-size="1.35" fill="#333" text-anchor="start">PC9</text>
|
||||||
|
<circle cx="518.16" cy="414.02" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="517.26" y="414.52" font-size="1.35" fill="#333" text-anchor="end">PA8</text>
|
||||||
|
<circle cx="518.16" cy="416.55999999999995" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="517.26" y="417.05999999999995" font-size="1.35" fill="#333" text-anchor="end">PA9</text>
|
||||||
|
<circle cx="518.16" cy="419.09999999999997" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="517.26" y="419.59999999999997" font-size="1.35" fill="#333" text-anchor="end">PA10</text>
|
||||||
|
<circle cx="518.16" cy="421.64" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="517.26" y="422.14" font-size="1.35" fill="#333" text-anchor="end">PA11</text>
|
||||||
|
<circle cx="518.16" cy="424.17999999999995" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="517.26" y="424.67999999999995" font-size="1.35" fill="#333" text-anchor="end">PA12</text>
|
||||||
|
<circle cx="518.16" cy="426.71999999999997" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="517.26" y="427.21999999999997" font-size="1.35" fill="#333" text-anchor="end">PA13</text>
|
||||||
|
<circle cx="500.38" cy="480.05999999999995" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="500.38" y="480.55999999999995" font-size="1.35" fill="#333" text-anchor="middle">VSS</text>
|
||||||
|
<circle cx="502.92" cy="386.08" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="502.92" y="386.58" font-size="1.35" fill="#333" text-anchor="middle">VDD</text>
|
||||||
|
<circle cx="518.16" cy="429.26" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="517.26" y="429.76" font-size="1.35" fill="#333" text-anchor="end">PA14</text>
|
||||||
|
<circle cx="518.16" cy="431.79999999999995" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="517.26" y="432.29999999999995" font-size="1.35" fill="#333" text-anchor="end">PA15</text>
|
||||||
|
<circle cx="482.6" cy="441.96" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="483.5" y="442.46" font-size="1.35" fill="#333" text-anchor="start">PC10</text>
|
||||||
|
<circle cx="482.6" cy="444.5" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="483.5" y="445.0" font-size="1.35" fill="#333" text-anchor="start">PC11</text>
|
||||||
|
<circle cx="482.6" cy="447.03999999999996" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="483.5" y="447.53999999999996" font-size="1.35" fill="#333" text-anchor="start">PC12</text>
|
||||||
|
<circle cx="482.6" cy="411.47999999999996" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="483.5" y="411.97999999999996" font-size="1.35" fill="#333" text-anchor="start">PD2</text>
|
||||||
|
<circle cx="518.16" cy="444.5" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="517.26" y="445.0" font-size="1.35" fill="#333" text-anchor="end">PB3</text>
|
||||||
|
<circle cx="518.16" cy="447.03999999999996" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="517.26" y="447.53999999999996" font-size="1.35" fill="#333" text-anchor="end">PB4</text>
|
||||||
|
<circle cx="518.16" cy="449.58" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="517.26" y="450.08" font-size="1.35" fill="#333" text-anchor="end">PB5</text>
|
||||||
|
<circle cx="518.16" cy="452.12" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="517.26" y="452.62" font-size="1.35" fill="#333" text-anchor="end">PB6</text>
|
||||||
|
<circle cx="518.16" cy="454.65999999999997" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="517.26" y="455.15999999999997" font-size="1.35" fill="#333" text-anchor="end">PB7</text>
|
||||||
|
<circle cx="482.6" cy="398.78" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="483.5" y="399.28" font-size="1.35" fill="#333" text-anchor="start">BOOT0</text>
|
||||||
|
<circle cx="518.16" cy="457.2" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="517.26" y="457.7" font-size="1.35" fill="#333" text-anchor="end">PB8</text>
|
||||||
|
<circle cx="518.16" cy="459.73999999999995" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="517.26" y="460.23999999999995" font-size="1.35" fill="#333" text-anchor="end">PB9</text>
|
||||||
|
<circle cx="500.38" cy="480.05999999999995" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="500.38" y="480.55999999999995" font-size="1.35" fill="#333" text-anchor="middle">VSS</text>
|
||||||
|
<circle cx="505.46" cy="386.08" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="505.46" y="386.58" font-size="1.35" fill="#333" text-anchor="middle">VDD</text>
|
||||||
|
<text x="500.38" y="432.34" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">U16</text>
|
||||||
|
<text x="500.38" y="437.73999999999995" font-size="1.3" fill="#555" text-anchor="middle">STM32F411RET6</text>
|
||||||
|
<rect x="429.8" y="498.92" width="14.16" height="8.0" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="431.8" cy="502.92" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="441.96" cy="502.92" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="436.88" y="500.92" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">SW2</text>
|
||||||
|
<text x="436.88" y="506.32" font-size="1.3" fill="#555" text-anchor="middle">BOOT0</text>
|
||||||
|
<rect x="445.58" y="497.11" width="8.0" height="11.620000000000001" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="449.58" cy="499.11" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="449.58" cy="506.73" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="449.58" y="500.92" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">R98</text>
|
||||||
|
<text x="449.58" y="506.32" font-size="1.3" fill="#555" text-anchor="middle">10k</text>
|
||||||
|
<rect x="458.28" y="497.11" width="8.0" height="11.620000000000001" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="462.28" cy="499.11" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="462.28" cy="506.73" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="462.28" y="500.92" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">R99</text>
|
||||||
|
<text x="462.28" y="506.32" font-size="1.3" fill="#555" text-anchor="middle">10k</text>
|
||||||
|
<rect x="470.98" y="497.11" width="8.0" height="11.620000000000001" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="474.98" cy="499.11" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="474.98" cy="506.73" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="474.98" y="500.92" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">C104</text>
|
||||||
|
<text x="474.98" y="506.32" font-size="1.3" fill="#555" text-anchor="middle">100nF</text>
|
||||||
|
<rect x="483.68" y="497.11" width="8.0" height="11.620000000000001" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="487.68" cy="499.11" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="487.68" cy="506.73" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="487.68" y="500.92" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">C105</text>
|
||||||
|
<text x="487.68" y="506.32" font-size="1.3" fill="#555" text-anchor="middle">100nF</text>
|
||||||
|
<rect x="496.38" y="497.11" width="8.0" height="11.620000000000001" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="500.38" cy="499.11" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="500.38" cy="506.73" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="500.38" y="500.92" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">C106</text>
|
||||||
|
<text x="500.38" y="506.32" font-size="1.3" fill="#555" text-anchor="middle">100nF</text>
|
||||||
|
<rect x="509.08000000000004" y="497.11" width="8.0" height="11.620000000000001" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="513.08" cy="499.11" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="513.08" cy="506.73" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="513.08" y="500.92" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">C107</text>
|
||||||
|
<text x="513.08" y="506.32" font-size="1.3" fill="#555" text-anchor="middle">100nF</text>
|
||||||
|
<rect x="521.78" y="497.11" width="8.0" height="11.620000000000001" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="525.78" cy="499.11" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="525.78" cy="506.73" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="525.78" y="500.92" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">C108</text>
|
||||||
|
<text x="525.78" y="506.32" font-size="1.3" fill="#555" text-anchor="middle">100nF</text>
|
||||||
|
<rect x="534.48" y="497.11" width="8.0" height="11.620000000000001" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="538.48" cy="499.11" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="538.48" cy="506.73" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="538.48" y="500.92" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">C109</text>
|
||||||
|
<text x="538.48" y="506.32" font-size="1.3" fill="#555" text-anchor="middle">100nF</text>
|
||||||
|
<rect x="547.18" y="497.11" width="8.0" height="11.620000000000001" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="551.18" cy="499.11" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="551.18" cy="506.73" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="551.18" y="500.92" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">C110</text>
|
||||||
|
<text x="551.18" y="506.32" font-size="1.3" fill="#555" text-anchor="middle">4.7uF</text>
|
||||||
|
<rect x="559.88" y="497.11" width="8.0" height="11.620000000000001" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="563.88" cy="499.11" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="563.88" cy="506.73" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="563.88" y="500.92" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">C111</text>
|
||||||
|
<text x="563.88" y="506.32" font-size="1.3" fill="#555" text-anchor="middle">4.7uF</text>
|
||||||
|
<rect x="572.58" y="497.11" width="8.0" height="11.620000000000001" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="576.58" cy="499.11" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="576.58" cy="506.73" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="576.58" y="500.92" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">C112</text>
|
||||||
|
<text x="576.58" y="506.32" font-size="1.3" fill="#555" text-anchor="middle">1uF</text>
|
||||||
|
<rect x="585.28" y="497.11" width="8.0" height="11.620000000000001" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="589.28" cy="499.11" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="589.28" cy="506.73" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="589.28" y="500.92" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">R104</text>
|
||||||
|
<text x="589.28" y="506.32" font-size="1.3" fill="#555" text-anchor="middle">10R</text>
|
||||||
|
<rect x="431.07" y="526.86" width="11.620000000000001" height="8.0" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="433.07" cy="530.86" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="440.69" cy="530.86" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="436.88" y="528.86" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">Y3</text>
|
||||||
|
<text x="436.88" y="534.26" font-size="1.3" fill="#555" text-anchor="middle">25MHz</text>
|
||||||
|
<rect x="445.58" y="525.0500000000001" width="8.0" height="11.620000000000001" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="449.58" cy="527.0500000000001" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="449.58" cy="534.67" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="449.58" y="528.86" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">C113</text>
|
||||||
|
<text x="449.58" y="534.26" font-size="1.3" fill="#555" text-anchor="middle">15pF</text>
|
||||||
|
<rect x="458.28" y="525.0500000000001" width="8.0" height="11.620000000000001" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="462.28" cy="527.0500000000001" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="462.28" cy="534.67" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="462.28" y="528.86" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">C114</text>
|
||||||
|
<text x="462.28" y="534.26" font-size="1.3" fill="#555" text-anchor="middle">15pF</text>
|
||||||
|
<rect x="469.17" y="526.86" width="11.620000000000001" height="8.0" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="471.17" cy="530.86" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="478.79" cy="530.86" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="474.98" y="528.86" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">Y4</text>
|
||||||
|
<text x="474.98" y="534.26" font-size="1.3" fill="#555" text-anchor="middle">32.768kHz</text>
|
||||||
|
<rect x="483.68" y="525.0500000000001" width="8.0" height="11.620000000000001" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="487.68" cy="527.0500000000001" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="487.68" cy="534.67" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="487.68" y="528.86" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">C115</text>
|
||||||
|
<text x="487.68" y="534.26" font-size="1.3" fill="#555" text-anchor="middle">12pF</text>
|
||||||
|
<rect x="496.38" y="525.0500000000001" width="8.0" height="11.620000000000001" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="500.38" cy="527.0500000000001" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="500.38" cy="534.67" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="500.38" y="528.86" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">C116</text>
|
||||||
|
<text x="500.38" y="534.26" font-size="1.3" fill="#555" text-anchor="middle">12pF</text>
|
||||||
|
<rect x="509.08000000000004" y="525.0500000000001" width="8.0" height="11.620000000000001" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="513.08" cy="527.0500000000001" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="513.08" cy="534.67" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="513.08" y="528.86" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">R102</text>
|
||||||
|
<text x="513.08" y="534.26" font-size="1.3" fill="#555" text-anchor="middle">1k</text>
|
||||||
|
<rect x="519.97" y="526.86" width="11.620000000000001" height="8.0" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="521.97" cy="530.86" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="529.5899999999999" cy="530.86" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="525.78" y="528.86" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">D17</text>
|
||||||
|
<text x="525.78" y="534.26" font-size="1.3" fill="#555" text-anchor="middle">LED C13 (blue)</text>
|
||||||
|
<rect x="534.48" y="525.0500000000001" width="8.0" height="11.620000000000001" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="538.48" cy="527.0500000000001" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="538.48" cy="534.67" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="538.48" y="528.86" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">R103</text>
|
||||||
|
<text x="538.48" y="534.26" font-size="1.3" fill="#555" text-anchor="middle">1k</text>
|
||||||
|
<rect x="545.37" y="526.86" width="11.620000000000001" height="8.0" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="547.37" cy="530.86" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="554.9899999999999" cy="530.86" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="551.18" y="528.86" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">D18</text>
|
||||||
|
<text x="551.18" y="534.26" font-size="1.3" fill="#555" text-anchor="middle">LED PWR (green)</text>
|
||||||
|
<rect x="559.88" y="526.86" width="8.0" height="8.0" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="563.88" cy="530.86" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="563.88" y="528.86" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">TP3</text>
|
||||||
|
<text x="563.88" y="534.26" font-size="1.3" fill="#555" text-anchor="middle">SWDIO</text>
|
||||||
|
<rect x="572.58" y="526.86" width="8.0" height="8.0" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="576.58" cy="530.86" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="576.58" y="528.86" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">TP4</text>
|
||||||
|
<text x="576.58" y="534.26" font-size="1.3" fill="#555" text-anchor="middle">SWCLK</text>
|
||||||
|
<rect x="585.28" y="526.86" width="8.0" height="8.0" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="589.28" cy="530.86" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="589.28" y="528.86" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">TP5</text>
|
||||||
|
<text x="589.28" y="534.26" font-size="1.3" fill="#555" text-anchor="middle">NRST</text>
|
||||||
|
<rect x="597.98" y="526.86" width="8.0" height="8.0" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="601.98" cy="530.86" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="601.98" y="528.86" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">TP6</text>
|
||||||
|
<text x="601.98" y="534.26" font-size="1.3" fill="#555" text-anchor="middle">GND</text>
|
||||||
|
<rect x="610.68" y="526.86" width="8.0" height="8.0" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="614.68" cy="530.86" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="614.68" y="528.86" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">TP7</text>
|
||||||
|
<text x="614.68" y="534.26" font-size="1.3" fill="#555" text-anchor="middle">3V3</text>
|
||||||
|
<rect x="621.57" y="498.92" width="11.620000000000001" height="8.0" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="623.57" cy="502.92" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="631.1899999999999" cy="502.92" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="627.38" y="500.92" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">D12</text>
|
||||||
|
<text x="627.38" y="506.32" font-size="1.3" fill="#555" text-anchor="middle">SS34</text>
|
||||||
|
<rect x="634.2700000000001" y="498.92" width="11.620000000000001" height="8.0" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="636.2700000000001" cy="502.92" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="643.89" cy="502.92" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="640.08" y="500.92" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">D13</text>
|
||||||
|
<text x="640.08" y="506.32" font-size="1.3" fill="#555" text-anchor="middle">SS34</text>
|
||||||
|
<rect x="655.86" y="497.11" width="19.240000000000002" height="11.620000000000001" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="665.48" cy="510.54" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="673.1" cy="502.92" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="657.86" cy="502.92" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="665.48" y="500.92" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">U17</text>
|
||||||
|
<text x="665.48" y="506.32" font-size="1.3" fill="#555" text-anchor="middle">AMS1117-3.3</text>
|
||||||
|
<rect x="686.88" y="497.11" width="8.0" height="11.620000000000001" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="690.88" cy="499.11" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="690.88" cy="506.73" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="690.88" y="500.92" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">C117</text>
|
||||||
|
<text x="690.88" y="506.32" font-size="1.3" fill="#555" text-anchor="middle">10uF</text>
|
||||||
|
<rect x="699.58" y="497.11" width="8.0" height="11.620000000000001" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="703.58" cy="499.11" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="703.58" cy="506.73" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="703.58" y="500.92" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">C118</text>
|
||||||
|
<text x="703.58" y="506.32" font-size="1.3" fill="#555" text-anchor="middle">22uF/16V</text>
|
||||||
|
<rect x="712.28" y="498.92" width="8.0" height="8.0" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="716.28" cy="502.92" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="716.28" y="500.92" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">PF12</text>
|
||||||
|
<text x="716.28" y="506.32" font-size="1.3" fill="#555" text-anchor="middle">PWR_FLAG</text>
|
||||||
|
<rect x="724.98" y="498.92" width="8.0" height="8.0" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="728.98" cy="502.92" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="728.98" y="500.92" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">PF13</text>
|
||||||
|
<text x="728.98" y="506.32" font-size="1.3" fill="#555" text-anchor="middle">PWR_FLAG</text>
|
||||||
|
<rect x="646.966" y="409.478" width="26.86" height="42.1" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="660.396" cy="453.38800000000003" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="675.636" cy="415.288" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="675.636" cy="420.368" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="675.636" cy="433.06800000000004" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="675.636" cy="427.988" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="675.636" cy="415.288" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="660.396" cy="453.38800000000003" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="660.396" cy="453.38800000000003" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="675.636" cy="415.288" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="675.636" cy="422.908" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="675.636" cy="435.608" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="675.636" cy="430.528" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="675.636" cy="415.288" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="660.396" cy="453.38800000000003" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="652.776" cy="453.38800000000003" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="660.396" y="428.528" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">J11</text>
|
||||||
|
<text x="660.396" y="433.928" font-size="1.3" fill="#555" text-anchor="middle">USB-C DFU</text>
|
||||||
|
<rect x="700.85" y="424.71999999999997" width="8.0" height="11.620000000000001" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="704.85" cy="426.71999999999997" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="704.85" cy="434.34" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="704.85" y="428.53" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">R100</text>
|
||||||
|
<text x="704.85" y="433.92999999999995" font-size="1.3" fill="#555" text-anchor="middle">5.1k</text>
|
||||||
|
<rect x="713.55" y="424.71999999999997" width="8.0" height="11.620000000000001" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="717.55" cy="426.71999999999997" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="717.55" cy="434.34" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="717.55" y="428.53" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">R101</text>
|
||||||
|
<text x="717.55" y="433.92999999999995" font-size="1.3" fill="#555" text-anchor="middle">5.1k</text>
|
||||||
|
<rect x="699.0400000000001" y="454.47" width="11.620000000000001" height="8.0" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="701.0400000000001" cy="458.47" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="708.66" cy="458.47" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="704.85" y="456.47" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">D14</text>
|
||||||
|
<text x="704.85" y="461.87" font-size="1.3" fill="#555" text-anchor="middle">PESD5V0S1BA</text>
|
||||||
|
<rect x="711.74" y="454.47" width="11.620000000000001" height="8.0" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="713.74" cy="458.47" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="721.3599999999999" cy="458.47" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="717.55" y="456.47" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">D15</text>
|
||||||
|
<text x="717.55" y="461.87" font-size="1.3" fill="#555" text-anchor="middle">PESD5V0S1BA</text>
|
||||||
|
<rect x="724.44" y="454.47" width="11.620000000000001" height="8.0" fill="#fff3d6" stroke="#8a2b2b" stroke-width="0.3" opacity="0.85"/>
|
||||||
|
<circle cx="726.44" cy="458.47" r="0.45" fill="#c62828"/>
|
||||||
|
<circle cx="734.06" cy="458.47" r="0.45" fill="#c62828"/>
|
||||||
|
<text x="730.25" y="456.47" font-size="1.8" font-weight="bold" fill="#1a1a1a" text-anchor="middle">D16</text>
|
||||||
|
<text x="730.25" y="461.87" font-size="1.3" fill="#555" text-anchor="middle">PESD5V0S1BA</text>
|
||||||
|
<text x="420.0" y="372.0" font-size="1.5" fill="#00600f">BLOCK P - ON-BOARD MCU (EinarBoard 3.0). STM32F411RET6 LQFP64 replaces Blackpill+J1/J2. DFU: hold BOOT0, tap NRST -> USB. HSE 25MHz REQUIRED for ROM-b</text>
|
||||||
|
<text x="420.0" y="377.0" font-size="1.5" fill="#00600f">PC6/PC7 reserved: USART6 (3rd UART, future). Free: PA7, PB9, PB10, PC1-PC5, PC8-PC12, PD2. LED_C13 active-LOW (Blackpill parity). SWD: TP3-TP7 (SWDIO/</text>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 46 KiB |
@ -0,0 +1,34 @@
|
|||||||
|
# EinarBoard 3.0 — Phase A ERC pass: 17 errors → root causes & fixes (2026-08-12)
|
||||||
|
|
||||||
|
Leo's KiCad 10 ERC (`v5-ERC.rpt`, 19:41): **17 errors / 369 warnings**. All 17 errors traced
|
||||||
|
to 3 root causes in the Phase A generator output; fixed file-level the same day.
|
||||||
|
|
||||||
|
## Root causes
|
||||||
|
|
||||||
|
1. **J11 origin 4 µm off-grid (15 of the 17 errors).** The USB-C DFU port was cloned from J9
|
||||||
|
by coordinate-shifting. J9's origin is `(446.786, 278.638)` — a 3-decimal position — and the
|
||||||
|
clone placed labels at 2-decimal-rounded pin positions while the instance origin stayed at
|
||||||
|
`(660.396, 430.528)`. Every cloned label/NC missed its pin by a uniform **(+0.004, +0.002) mm**.
|
||||||
|
KiCad connectivity is exact (nanometer ints); the ERC report rounds to mils, so pin and label
|
||||||
|
*print* identical coordinates while not touching — 9 `pin_not_connected` + 6 `label_dangling`.
|
||||||
|
**Fix:** nudge J11's instance origin `(660.396 430.528)` → `(660.4 430.53)` — one edit aligns
|
||||||
|
every cloned label and NC exactly. **Lesson for future file-level work: never round coordinates
|
||||||
|
independently on both sides of a connection; verify with exact arithmetic, not 2-decimal floats.**
|
||||||
|
2. **PF3 vs U17 (1 error).** The 3V3 net carried a PWR_FLAG (PF3) from the socket era, when the
|
||||||
|
Blackpill's passive socket pin was the only "source". U17 (AMS1117) VO is a real Power-Output →
|
||||||
|
two power outputs on one net. **Fix:** PF3 + its stub wire + its 3V3 label deleted.
|
||||||
|
3. **VDDA undriven (1 error).** VDDA is fed through R104 (10 R, passive) so no power output reaches
|
||||||
|
U16's VDDA power-in pin. **Fix:** PF14 (PWR_FLAG) added on VDDA next to PF12/PF13.
|
||||||
|
|
||||||
|
Bonus (warning-level): new P6's footprint was auto-derived as `JST_XH_B4B-XH-A_1x02…` — the JST
|
||||||
|
2-pin housing is **B2B**, not B4B → set `Connector_JST:JST_XH_B2B-XH-A_1x02_P2.50mm_Vertical`.
|
||||||
|
|
||||||
|
## Verification (container, exact Decimal arithmetic — no rounding)
|
||||||
|
|
||||||
|
- Unconnected pins whole-sheet: **0** · J11 pins unattached: **0** · sexp balance ✓
|
||||||
|
- Expected next ERC: **0 errors**. Remaining warnings are baseline/pre-existing, notably:
|
||||||
|
212× `lib_symbol_issues` — KiCad can't find the `power` library at
|
||||||
|
`/Applications/KiCad/KiCad.app/…/symbols//power.kicad_sym` (Mac lib-table config, worth fixing
|
||||||
|
once in KiCad prefs); ~148× `endpoint_off_grid` (v4 heritage); J10 RJ45 lib mismatch (known);
|
||||||
|
3× `no_connect_connected` + 1 `unconnected_wire_endpoint` (pre-existing v4 items at
|
||||||
|
SW4G1/J9-hidden-pins area — candidates for a later cleanup pass, not introduced in 3.0).
|
||||||
File diff suppressed because it is too large
Load Diff
|
After Width: | Height: | Size: 1.8 MiB |
File diff suppressed because it is too large
Load Diff
|
After Width: | Height: | Size: 1.8 MiB |
File diff suppressed because it is too large
Load Diff
|
After Width: | Height: | Size: 1.9 MiB |
534
03-Architecture-Hardware/kicad/v5-ERC.rpt
Normal file
534
03-Architecture-Hardware/kicad/v5-ERC.rpt
Normal file
@ -0,0 +1,534 @@
|
|||||||
|
ERC report (2026-08-11T19:57:12, Encoding UTF8)
|
||||||
|
Report includes: Errors, Warnings
|
||||||
|
|
||||||
|
***** Sheet /
|
||||||
|
[lib_symbol_mismatch]: Symbol 'SW_Push' doesn't match copy in library 'Switch'
|
||||||
|
; warning
|
||||||
|
@(1300 mils, 10900 mils): Symbol SW4G1 [SW_Push]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(2480 mils, 8910 mils): Wire, length 51 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(2481 mils, 8559 mils): Symbol Rcc1 Pin 1 [Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(3250 mils, 12358 mils): Symbol R60 Pin 1 [Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(3250 mils, 12658 mils): Vertical Wire, length 172 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(3250 mils, 12830 mils): Symbol R61 Pin 1 [Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(3250 mils, 13260 mils): Vertical Wire, length 130 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(3253 mils, 12218 mils): Wire, length 139 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(3362 mils, 11239 mils): Symbol C41 Pin 1 [Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(3362 mils, 11712 mils): Symbol C43 Pin 1 [Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(4000 mils, 8730 mils): Vertical Wire, length 80 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(4910 mils, 8190 mils): Symbol Dbk1 Pin 1 [K, Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(4958 mils, 10370 mils): Symbol JP2 Pin 1 [A, Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(5158 mils, 10700 mils): Vertical Wire, length 180 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(5160 mils, 10700 mils): Horizontal Wire, length 2 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(5160 mils, 10720 mils): Vertical Wire, length 20 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(5509 mils, 10370 mils): Horizontal Wire, length 151 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(5509 mils, 10370 mils): Symbol JP3 Pin 1 [A, Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(5710 mils, 10710 mils): Wire, length 190 mils
|
||||||
|
[lib_symbol_mismatch]: Symbol 'L' doesn't match copy in library 'Device'
|
||||||
|
; warning
|
||||||
|
@(6000 mils, 9000 mils): Symbol L2 [L]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(6060 mils, 10370 mils): Symbol JP4 Pin 1 [A, Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(6060 mils, 10370 mils): Horizontal Wire, length 151 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(6260 mils, 10740 mils): Vertical Wire, length 220 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(7000 mils, 8210 mils): Vertical Wire, length 30 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(7000 mils, 8240 mils): Symbol R20 Pin 1 [Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(7000 mils, 8540 mils): Vertical Wire, length 710 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(7540 mils, 9250 mils): Symbol JP1 Pin 1 [A, Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(7940 mils, 7750 mils): Wire, length 7 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(7940 mils, 7750 mils): Symbol R51 Pin 1 [Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(7940 mils, 8050 mils): Vertical Wire, length 170 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(7940 mils, 8220 mils): Symbol R52 Pin 1 [Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(7940 mils, 8520 mils): Vertical Wire, length 130 mils
|
||||||
|
[unconnected_wire_endpoint]: Unconnected wire endpoint
|
||||||
|
; warning
|
||||||
|
@(7940 mils, 8520 mils): Vertical Wire, length 130 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(8604 mils, 10300 mils): Symbol R57 Pin 1 [Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(8600 mils, 10650 mils): Wire, length 50 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(8900 mils, 7550 mils): Wire, length 78 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(8976 mils, 7567 mils): Symbol C30 Pin 1 [Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(8950 mils, 7900 mils): Wire, length 43 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(9076 mils, 10300 mils): Symbol R58 Pin 1 [Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(9050 mils, 10800 mils): Wire, length 202 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(9249 mils, 984 mils): Symbol P11 Pin 1 [Pin_1, Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(9370 mils, 7567 mils): Symbol C31 Pin 1 [Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(9350 mils, 7900 mils): Wire, length 39 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(9449 mils, 8118 mils): Symbol R55 Pin 1 [Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(9400 mils, 8500 mils): Wire, length 96 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(9449 mils, 8590 mils): Symbol R50 Pin 1 [Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(9450 mils, 9000 mils): Wire, length 110 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(9548 mils, 10450 mils): Symbol TP1 Pin 1 [1, Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(9600 mils, 10750 mils): Wire, length 304 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(9830 mils, 8460 mils): Wire, length 159 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(9921 mils, 8590 mils): Symbol R56 Pin 1 [Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(9900 mils, 9050 mils): Wire, length 161 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(10050 mils, 10750 mils): Wire, length 319 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(9942 mils, 10450 mils): Symbol TP2 Pin 1 [1, Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(10450 mils, 10700 mils): Wire, length 252 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(10415 mils, 10450 mils): Symbol PF8 Pin 1 [Power output, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(9750 mils, 1300 mils): Horizontal Wire, length 730 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(10480 mils, 1300 mils): Symbol P8 Pin 1 [Pin_1, Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(10480 mils, 1400 mils): Horizontal Wire, length 80 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(10900 mils, 10700 mils): Wire, length 266 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(10808 mils, 10450 mils): Symbol PF9 Pin 1 [Power output, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(11449 mils, 2913 mils): Wire, length 73 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(11449 mils, 3494 mils): Wire, length 84 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(11450 mils, 2540 mils): Vertical Wire, length 20 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(11450 mils, 2540 mils): Symbol RB3 Pin 1 [Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(11450 mils, 3110 mils): Symbol RB4 Pin 1 [Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(11480 mils, 2050 mils): Symbol RB2 Pin 1 [Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(11480 mils, 2390 mils): Vertical Wire, length 40 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(11590 mils, 1380 mils): Symbol RB1 Pin 1 [Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(11590 mils, 1730 mils): Vertical Wire, length 50 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(11611 mils, 4331 mils): Symbol SW1 Pin 1 [1, Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(11611 mils, 5039 mils): Symbol P10 Pin 1 [Pin_1, Passive, Line]
|
||||||
|
[lib_symbol_mismatch]: Symbol 'SW_Push' doesn't match copy in library 'Switch'
|
||||||
|
; warning
|
||||||
|
@(11811 mils, 4331 mils): Symbol SW1 [SW_Push]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(11940 mils, 6428 mils): Symbol R53 Pin 1 [Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(11940 mils, 6900 mils): Vertical Wire, length 172 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(11940 mils, 6900 mils): Symbol R54 Pin 1 [Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(11940 mils, 7298 mils): Vertical Wire, length 98 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(12200 mils, 3350 mils): Wire, length 63 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(12552 mils, 1260 mils): Symbol DB1 Pin 1 [K, Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(12552 mils, 1969 mils): Symbol DB2 Pin 1 [K, Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(12552 mils, 2677 mils): Symbol DB3 Pin 1 [K, Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(12552 mils, 3386 mils): Symbol DB4 Pin 1 [K, Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(12740 mils, 6540 mils): Horizontal Wire, length 110 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(12770 mils, 5590 mils): Symbol Rcomp2 Pin 1 [Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(12770 mils, 5590 mils): Wire, length 18 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(12770 mils, 5990 mils): Vertical Wire, length 100 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(12770 mils, 5990 mils): Symbol Ccomp2 Pin 1 [Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(12770 mils, 6290 mils): Wire, length 9 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(12850 mils, 4990 mils): Symbol Rfreq2 Pin 1 [Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(12850 mils, 5370 mils): Vertical Wire, length 80 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(12850 mils, 6540 mils): Symbol L6 Pin 1 [1, Passive, Line]
|
||||||
|
[lib_symbol_mismatch]: Symbol 'L' doesn't match copy in library 'Device'
|
||||||
|
; warning
|
||||||
|
@(13000 mils, 6540 mils): Symbol L6 [L]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(13150 mils, 7567 mils): Symbol C32 Pin 1 [Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(13150 mils, 8039 mils): Symbol C34 Pin 1 [Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(13150 mils, 6540 mils): Horizontal Wire, length 20 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(13150 mils, 7910 mils): Wire, length 43 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(13230 mils, 6890 mils): Wire, length 32 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(13230 mils, 6890 mils): Symbol C35 Pin 1 [Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(13230 mils, 7190 mils): Vertical Wire, length 40 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(13260 mils, 3930 mils): Symbol Cbst2 Pin 1 [Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(13260 mils, 4230 mils): Vertical Wire, length 70 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(13543 mils, 7567 mils): Symbol C33 Pin 1 [Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(13600 mils, 8028 mils): Symbol R40 Pin 1 [Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(13600 mils, 7950 mils): Vertical Wire, length 78 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(13600 mils, 8328 mils): Vertical Wire, length 172 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(13701 mils, 5992 mils): Symbol C40 Pin 1 [Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(14010 mils, 9080 mils): Vertical Wire, length 30 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(14010 mils, 9080 mils): Symbol R42 Pin 1 [Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(14010 mils, 9380 mils): Vertical Wire, length 260 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(14010 mils, 9640 mils): Symbol C24 Pin 1 [Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(14010 mils, 10060 mils): Vertical Wire, length 120 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(14910 mils, 9550 mils): Wire, length 8 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(14918 mils, 9449 mils): Symbol P12 Pin 1 [Pin_1, Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(14920 mils, 9450 mils): Wire, length 2 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(15680 mils, 1540 mils): Symbol J7 Pin 1 [Pin_1, Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(16543 mils, 2257 mils): Wire, length 27 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(16570 mils, 1560 mils): Symbol J8 Pin 1 [Pin_1, Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(17150 mils, 8440 mils): Horizontal Wire, length 650 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(17150 mils, 8540 mils): Horizontal Wire, length 550 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(17150 mils, 8690 mils): Horizontal Wire, length 450 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(17150 mils, 8790 mils): Horizontal Wire, length 350 mils
|
||||||
|
[lib_symbol_mismatch]: Symbol 'SW_Push' doesn't match copy in library 'Switch'
|
||||||
|
; warning
|
||||||
|
@(17200 mils, 19800 mils): Symbol SW2 [SW_Push]
|
||||||
|
[lib_symbol_mismatch]: Symbol 'Crystal' doesn't match copy in library 'Device'
|
||||||
|
; warning
|
||||||
|
@(17200 mils, 20900 mils): Symbol Y3 [Crystal]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(17290 mils, 11990 mils): Vertical Wire, length 120 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(17500 mils, 9390 mils): Symbol Q7 Pin 1 [S, Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(17500 mils, 9540 mils): Vertical Wire, length 150 mils
|
||||||
|
[lib_symbol_issues]: The current configuration does not include the symbol library 'Drogheda-sym'
|
||||||
|
; warning
|
||||||
|
@(17560 mils, 7660 mils): Symbol U7 [MP1584EN]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(17590 mils, 11870 mils): Symbol J9 Pin A1 [GND, Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(17590 mils, 12000 mils): Vertical Wire, length 130 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(17600 mils, 8690 mils): Vertical Wire, length 100 mils
|
||||||
|
[lib_symbol_issues]: The current configuration does not include the symbol library 'Drogheda-sym'
|
||||||
|
; warning
|
||||||
|
@(17600 mils, 9090 mils): Symbol Q7 [AO4406A]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(17600 mils, 9640 mils): Vertical Wire, length 250 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(17700 mils, 8540 mils): Vertical Wire, length 250 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(17700 mils, 9740 mils): Vertical Wire, length 350 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(17800 mils, 8440 mils): Vertical Wire, length 350 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(17860 mils, 7560 mils): Symbol U7 Pin 1 [SW, Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(18040 mils, 7345 mils): Symbol L7 Pin 1 [1, Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(18040 mils, 7345 mils): Wire, length 280 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(18040 mils, 7817 mils): Symbol Dbk2 Pin 1 [K, Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(18040 mils, 7817 mils): Wire, length 314 mils
|
||||||
|
[lib_symbol_mismatch]: Symbol 'L' doesn't match copy in library 'Device'
|
||||||
|
; warning
|
||||||
|
@(18190 mils, 7345 mils): Symbol L7 [L]
|
||||||
|
[lib_symbol_issues]: The current configuration does not include the symbol library 'Drogheda-sym'
|
||||||
|
; warning
|
||||||
|
@(18460 mils, 2050 mils): Symbol U6 [LTC4040EUFD]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(18460 mils, 3040 mils): Vertical Wire, length 90 mils
|
||||||
|
[lib_symbol_issues]: The current configuration does not include the symbol library 'Drogheda-sym'
|
||||||
|
; warning
|
||||||
|
@(18470 mils, 4220 mils): Symbol MOD1 [SimpleRTK2B_Pro_Socket]
|
||||||
|
[lib_symbol_mismatch]: Symbol 'Crystal' doesn't match copy in library 'Device'
|
||||||
|
; warning
|
||||||
|
@(18700 mils, 20900 mils): Symbol Y4 [Crystal]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(19070 mils, 4720 mils): Symbol MOD1 Pin 14 [A5, Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(19160 mils, 1750 mils): Symbol U6 Pin 24 [VSYS, Passive, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(19420 mils, 8170 mils): Wire, length 27 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(19420 mils, 8170 mils): Symbol Q6 Pin 1 [B, Input, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(19440 mils, 9390 mils): Symbol U4 Pin 1 [SCL, Input, Line]
|
||||||
|
[lib_symbol_mismatch]: Symbol 'STM32F411RETx' doesn't match copy in library 'MCU_ST_STM32F4'
|
||||||
|
; warning
|
||||||
|
@(19700 mils, 17100 mils): Symbol U16 [STM32F411RETx]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(19720 mils, 7970 mils): Vertical Wire, length 190 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(19720 mils, 8380 mils): Vertical Wire, length 10 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(19720 mils, 8380 mils): Horizontal Wire, length 3 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(19723 mils, 8380 mils): Vertical Wire, length 117 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(19840 mils, 9940 mils): Vertical Wire, length 50 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(20020 mils, 7020 mils): Vertical Wire, length 160 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(20020 mils, 7180 mils): Symbol K1 Pin 1 [Passive, Line]
|
||||||
|
[lib_symbol_issues]: The current configuration does not include the symbol library 'Drogheda-sym'
|
||||||
|
; warning
|
||||||
|
@(20060 mils, 10900 mils): Symbol U2 [MP1584EN]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(20060 mils, 11300 mils): Symbol U2 Pin 5 [GND, Power input, Line]
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(20060 mils, 11400 mils): Vertical Wire, length 100 mils
|
||||||
|
[endpoint_off_grid]: Symbol pin or wire end off connection grid
|
||||||
|
; warning
|
||||||
|
@(20321 mils, 7992 mils): Symbol D6 Pin 1 [K, Passive, Line]
|
||||||
|
[lib_symbol_mismatch]: Symbol 'D' doesn't match copy in library 'Device'
|
||||||
|
; warning
|
||||||
|
@(20471 mils, 7992 mils): Symbol D6 [D]
|
||||||
|
[lib_symbol_mismatch]: Symbol 'Crystal' doesn't match copy in library 'Device'
|
||||||
|
; warning
|
||||||
|
@(21250 mils, 6600 mils): Symbol Y2 [Crystal]
|
||||||
|
[lib_symbol_issues]: Symbol 'PCF8574' not found in symbol library 'Interface_Expansion'
|
||||||
|
; warning
|
||||||
|
@(22250 mils, 2350 mils): Symbol U13 [PCF8574]
|
||||||
|
[lib_symbol_mismatch]: Symbol 'SP3485EN' doesn't match copy in library 'Interface_UART'
|
||||||
|
; warning
|
||||||
|
@(24000 mils, 5500 mils): Symbol U14 [SP3485EN]
|
||||||
|
[footprint_link_issues]: Footprint 'PhoenixContact_MC_1,5_3-G-3.5_1x03_P3.50mm_Vertical' not found in library 'Connector_Phoenix_MC'
|
||||||
|
; warning
|
||||||
|
@(25600 mils, 5500 mils): Symbol P15 [Conn_01x03]
|
||||||
|
[footprint_link_issues]: Footprint 'PhoenixContact_MC_1,5_3-G-3.5_1x03_P3.50mm_Vertical' not found in library 'Connector_Phoenix_MC'
|
||||||
|
; warning
|
||||||
|
@(25600 mils, 8050 mils): Symbol P16 [Conn_01x03]
|
||||||
|
[lib_symbol_mismatch]: Symbol 'AMS1117-3.3' doesn't match copy in library 'Regulator_Linear'
|
||||||
|
; warning
|
||||||
|
@(26200 mils, 19800 mils): Symbol U17 [AMS1117-3.3]
|
||||||
|
[lib_symbol_mismatch]: Symbol 'Crystal' doesn't match copy in library 'Device'
|
||||||
|
; warning
|
||||||
|
@(27350 mils, 6900 mils): Symbol Y1 [Crystal]
|
||||||
|
[lib_symbol_issues]: The current configuration does not include the symbol library 'Drogheda-sym'
|
||||||
|
; warning
|
||||||
|
@(27550 mils, 9050 mils): Symbol U12 [MP1584EN]
|
||||||
|
[lib_symbol_mismatch]: Symbol 'L' doesn't match copy in library 'Device'
|
||||||
|
; warning
|
||||||
|
@(28450 mils, 8750 mils): Symbol L8 [L]
|
||||||
|
[footprint_link_issues]: The current configuration does not include the footprint library 'Connector_RJ45'
|
||||||
|
; warning
|
||||||
|
@(31500 mils, 3550 mils): Symbol J10 [RJ45_Hanrun_HR911105A_Horizontal]
|
||||||
|
[lib_symbol_mismatch]: Symbol 'RJ45_Hanrun_HR911105A_Horizontal' doesn't match copy in library 'Connector'
|
||||||
|
; warning
|
||||||
|
@(31500 mils, 3550 mils): Symbol J10 [RJ45_Hanrun_HR911105A_Horizontal]
|
||||||
|
|
||||||
|
** ERC messages: 174 Errors 0 Warnings 174
|
||||||
|
|
||||||
|
** Ignored checks:
|
||||||
|
- Global label only appears once in the schematic
|
||||||
|
- Four connection points are joined together
|
||||||
|
- SPICE model issue
|
||||||
|
- Assigned footprint doesn't match footprint filters
|
||||||
630
scripts/2026-08-12_einarboard30_phaseA_gen_blockP.py
Normal file
630
scripts/2026-08-12_einarboard30_phaseA_gen_blockP.py
Normal file
@ -0,0 +1,630 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
EinarBoard 3.0 — Phase A generator: Block P (on-board STM32F411RET6) into hbox-watchdog-v5.kicad_sch
|
||||||
|
File-level edit per project standing rule (no KiCad MCP backend writes).
|
||||||
|
Surgical text splice: deletions by byte-span, insertions at anchors. Independent re-parse + netlist diff after.
|
||||||
|
Run: python3 gen_blockP.py <schematic path>
|
||||||
|
"""
|
||||||
|
import re, sys, math, uuid, collections, json
|
||||||
|
|
||||||
|
FN = sys.argv[1] if len(sys.argv) > 1 else 'hbox-watchdog-v5.kicad_sch'
|
||||||
|
src = open(FN, encoding='utf-8').read()
|
||||||
|
if 'STM32F411RETx' in src:
|
||||||
|
print('ABORT: U16/STM32F411RETx already present — idempotence guard'); sys.exit(1)
|
||||||
|
|
||||||
|
# ---------------- sexp parser with byte spans ----------------
|
||||||
|
def tokenize(s):
|
||||||
|
toks = []; i = 0; n = len(s)
|
||||||
|
while i < n:
|
||||||
|
c = s[i]
|
||||||
|
if c in ' \t\r\n': i += 1; continue
|
||||||
|
if c in '()': toks.append((c, i, i+1)); i += 1; continue
|
||||||
|
if c == '"':
|
||||||
|
j = i+1; buf = []
|
||||||
|
while j < n:
|
||||||
|
if s[j] == '\\' and j+1 < n: buf.append(s[j:j+2]); j += 2; continue
|
||||||
|
if s[j] == '"': break
|
||||||
|
buf.append(s[j]); j += 1
|
||||||
|
toks.append((('STR', ''.join(buf)), i, j+1)); i = j+1; continue
|
||||||
|
j = i
|
||||||
|
while j < n and s[j] not in ' \t\r\n()"': j += 1
|
||||||
|
toks.append((('ATOM', s[i:j]), i, j)); i = j
|
||||||
|
return toks
|
||||||
|
|
||||||
|
def parse(toks):
|
||||||
|
pos = [0]
|
||||||
|
def rd():
|
||||||
|
t, a, b = toks[pos[0]]
|
||||||
|
if t == '(':
|
||||||
|
pos[0] += 1; lst = []
|
||||||
|
while toks[pos[0]][0] != ')': lst.append(rd())
|
||||||
|
_, _, e = toks[pos[0]]; pos[0] += 1
|
||||||
|
return ('L', lst, a, e)
|
||||||
|
pos[0] += 1
|
||||||
|
return ('T', t, a, b)
|
||||||
|
out = []
|
||||||
|
while pos[0] < len(toks): out.append(rd())
|
||||||
|
return out
|
||||||
|
|
||||||
|
toks = tokenize(src)
|
||||||
|
doc = parse(toks)[0]
|
||||||
|
assert doc[0] == 'L'
|
||||||
|
def kids(e): return e[1] if e[0] == 'L' else []
|
||||||
|
def tag(e):
|
||||||
|
k = kids(e)
|
||||||
|
if k and k[0][0] == 'T': return k[0][1][1]
|
||||||
|
return None
|
||||||
|
def sval(e): return e[1][1] if e[0] == 'T' else None
|
||||||
|
def span(e): return (e[2], e[3])
|
||||||
|
def find_all(e, t): return [c for c in kids(e) if c[0] == 'L' and tag(c) == t]
|
||||||
|
def find1(e, t):
|
||||||
|
r = find_all(e, t); return r[0] if r else None
|
||||||
|
def fnum(e):
|
||||||
|
try: return float(sval(e))
|
||||||
|
except: return None
|
||||||
|
|
||||||
|
top = kids(doc)
|
||||||
|
root_uuid = sval(kids(find1(doc, 'uuid'))[1])
|
||||||
|
libsym_el = find1(doc, 'lib_symbols')
|
||||||
|
|
||||||
|
# ---------------- lib pin tables ----------------
|
||||||
|
def lib_pins(libname):
|
||||||
|
for s in find_all(libsym_el, 'symbol'):
|
||||||
|
if sval(kids(s)[1]) == libname:
|
||||||
|
pins = []
|
||||||
|
def walk(e):
|
||||||
|
for c in kids(e):
|
||||||
|
if c[0] == 'L':
|
||||||
|
if tag(c) == 'pin':
|
||||||
|
at = find1(c, 'at'); num = find1(c, 'number'); nm = find1(c, 'name')
|
||||||
|
pins.append(dict(x=fnum(kids(at)[1]), y=fnum(kids(at)[2]),
|
||||||
|
num=sval(kids(num)[1]), name=sval(kids(nm)[1]) if nm else ''))
|
||||||
|
else: walk(c)
|
||||||
|
walk(s)
|
||||||
|
return pins
|
||||||
|
raise KeyError(libname)
|
||||||
|
|
||||||
|
# ---------------- collect elements ----------------
|
||||||
|
symbols = find_all(doc, 'symbol')
|
||||||
|
wires = find_all(doc, 'wire')
|
||||||
|
labels = find_all(doc, 'label')
|
||||||
|
ncs = find_all(doc, 'no_connect')
|
||||||
|
juncs = find_all(doc, 'junction')
|
||||||
|
texts = find_all(doc, 'text')
|
||||||
|
|
||||||
|
def sym_info(s):
|
||||||
|
lid = sval(kids(find1(s, 'lib_id'))[1]); at = kids(find1(s, 'at'))
|
||||||
|
ref = value = fp = None
|
||||||
|
for p in find_all(s, 'property'):
|
||||||
|
pk = kids(p)
|
||||||
|
if sval(pk[1]) == 'Reference': ref = sval(pk[2])
|
||||||
|
elif sval(pk[1]) == 'Value': value = sval(pk[2])
|
||||||
|
elif sval(pk[1]) == 'Footprint': fp = sval(pk[2])
|
||||||
|
mir = find1(s, 'mirror')
|
||||||
|
return dict(lib_id=lid, ref=ref, value=value, fp=fp, x=fnum(at[1]), y=fnum(at[2]),
|
||||||
|
rot=(fnum(at[3]) if len(at) > 3 else 0) or 0,
|
||||||
|
mirror=sval(kids(mir)[1]) if mir else None, el=s)
|
||||||
|
SYMS = [sym_info(s) for s in symbols]
|
||||||
|
def by_ref(r):
|
||||||
|
m = [s for s in SYMS if s['ref'] == r]
|
||||||
|
assert len(m) == 1, f'ref {r}: {len(m)} matches'
|
||||||
|
return m[0]
|
||||||
|
|
||||||
|
def R2(v): return round(v, 2)
|
||||||
|
def pin_world(inst, pins=None):
|
||||||
|
pins = pins or lib_pins(inst['lib_id'])
|
||||||
|
out = {}
|
||||||
|
for p in pins:
|
||||||
|
x, y = p['x'], -p['y']
|
||||||
|
if inst['mirror'] == 'y': x = -x
|
||||||
|
if inst['mirror'] == 'x': y = -y
|
||||||
|
r = math.radians(inst['rot'])
|
||||||
|
out[p['num']] = (R2(inst['x'] + x*math.cos(r) + y*math.sin(r)),
|
||||||
|
R2(inst['y'] - x*math.sin(r) + y*math.cos(r)))
|
||||||
|
return out
|
||||||
|
|
||||||
|
adj = collections.defaultdict(set)
|
||||||
|
wire_pts = {}
|
||||||
|
for w in wires:
|
||||||
|
pts = [(R2(fnum(kids(xy)[1])), R2(fnum(kids(xy)[2]))) for xy in find_all(find1(w, 'pts'), 'xy')]
|
||||||
|
wire_pts[id(w)] = pts
|
||||||
|
for a, b in zip(pts, pts[1:]): adj[a].add(b); adj[b].add(a)
|
||||||
|
lab_at = collections.defaultdict(list) # pos -> [(name, element)]
|
||||||
|
for L in labels:
|
||||||
|
at = kids(find1(L, 'at'))
|
||||||
|
lab_at[(R2(fnum(at[1])), R2(fnum(at[2])))].append((sval(kids(L)[1]), L))
|
||||||
|
nc_at = {}
|
||||||
|
for n in ncs:
|
||||||
|
at = kids(find1(n, 'at')); nc_at[(R2(fnum(at[1])), R2(fnum(at[2])))] = n
|
||||||
|
junc_at = {}
|
||||||
|
for jn in juncs:
|
||||||
|
at = kids(find1(jn, 'at')); junc_at[(R2(fnum(at[1])), R2(fnum(at[2])))] = jn
|
||||||
|
|
||||||
|
# all pin positions of every symbol (for safety asserts + netlist)
|
||||||
|
ALLPINS = [] # (ref, pinnum, pos)
|
||||||
|
for s in SYMS:
|
||||||
|
try:
|
||||||
|
for num, p in pin_world(s).items(): ALLPINS.append((s['ref'], num, p))
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
pin_pos_map = collections.defaultdict(list)
|
||||||
|
for ref, num, p in ALLPINS: pin_pos_map[p].append((ref, num))
|
||||||
|
|
||||||
|
# ---------------- netlist (union-find over positions + label names) ----------------
|
||||||
|
def build_netlist(adjacency, labels_at, pinlist):
|
||||||
|
parent = {}
|
||||||
|
def find(a):
|
||||||
|
while parent.setdefault(a, a) != a:
|
||||||
|
parent[a] = parent[parent[a]]; a = parent[a]
|
||||||
|
return a
|
||||||
|
def union(a, b): parent[find(a)] = find(b)
|
||||||
|
for a, nbrs in adjacency.items():
|
||||||
|
for b in nbrs: union(('P', a), ('P', b))
|
||||||
|
for pos, lst in labels_at.items():
|
||||||
|
for nm, _ in lst: union(('P', pos), ('N', nm))
|
||||||
|
for ref, num, p in pinlist: union(('P', p), ('PIN', ref, num))
|
||||||
|
groups = collections.defaultdict(lambda: dict(names=set(), pins=set()))
|
||||||
|
for a in list(parent):
|
||||||
|
r = find(a); g = groups[r]
|
||||||
|
if a[0] == 'N': g['names'].add(a[1])
|
||||||
|
elif a[0] == 'PIN': g['pins'].add((a[1], a[2]))
|
||||||
|
nets = {}
|
||||||
|
for g in groups.values():
|
||||||
|
if not g['names'] and not g['pins']: continue
|
||||||
|
nm = '/'.join(sorted(g['names'])) if g['names'] else None
|
||||||
|
if nm: nets.setdefault(nm, set()).update(g['pins'])
|
||||||
|
return nets
|
||||||
|
NET_BEFORE = build_netlist(adj, lab_at, ALLPINS)
|
||||||
|
|
||||||
|
# ---------------- deletion set ----------------
|
||||||
|
J1 = by_ref('J1'); J2 = by_ref('J2'); P6 = by_ref('P6'); Rts1 = by_ref('Rts1'); Rtp1 = by_ref('Rtp1')
|
||||||
|
assert J1['value'] == 'Blackpill-L' and J2['value'] == 'Blackpill-R'
|
||||||
|
assert P6['lib_id'].endswith('Conn_01x04') and P6['value'] == 'FAN'
|
||||||
|
del_syms = [J1, J2, P6, Rts1, Rtp1]
|
||||||
|
del_sym_ids = {id(s['el']) for s in del_syms}
|
||||||
|
seed_pins = []
|
||||||
|
for s in del_syms: seed_pins += list(pin_world(s).values())
|
||||||
|
seed_set = set(seed_pins)
|
||||||
|
|
||||||
|
kept_pin_pos = {p for ref, num, p in ALLPINS if not any(by is s for s in [] )}
|
||||||
|
kept_pin_pos = set()
|
||||||
|
for s in SYMS:
|
||||||
|
if id(s['el']) in del_sym_ids: continue
|
||||||
|
try: kept_pin_pos.update(pin_world(s).values())
|
||||||
|
except KeyError: pass
|
||||||
|
|
||||||
|
# graph walk from seeds
|
||||||
|
gnodes = set()
|
||||||
|
stack = [p for p in seed_pins if p in adj]
|
||||||
|
while stack:
|
||||||
|
p = stack.pop()
|
||||||
|
if p in gnodes: continue
|
||||||
|
gnodes.add(p)
|
||||||
|
for q in adj[p]:
|
||||||
|
if q not in gnodes: stack.append(q)
|
||||||
|
# safety: deletion graph must not touch kept pins
|
||||||
|
touch = gnodes & kept_pin_pos
|
||||||
|
assert not touch, f'deletion graph touches kept pins at {sorted(touch)[:5]}'
|
||||||
|
|
||||||
|
del_spans = []
|
||||||
|
report = collections.defaultdict(list)
|
||||||
|
for s in del_syms:
|
||||||
|
del_spans.append(span(s['el'])); report['symbols_deleted'].append(f"{s['ref']} ({s['value']})")
|
||||||
|
for w in wires:
|
||||||
|
pts = wire_pts[id(w)]
|
||||||
|
if pts and all(p in gnodes for p in pts):
|
||||||
|
del_spans.append(span(w)); report['wires_deleted'].append(pts)
|
||||||
|
node_del = gnodes | seed_set
|
||||||
|
for pos, lst in lab_at.items():
|
||||||
|
if pos in node_del:
|
||||||
|
for nm, el in lst:
|
||||||
|
del_spans.append(span(el)); report['labels_deleted'].append((nm, pos))
|
||||||
|
# any FAN_TACH-family label anywhere (retired nets)
|
||||||
|
for pos, lst in lab_at.items():
|
||||||
|
if pos not in node_del:
|
||||||
|
for nm, el in lst:
|
||||||
|
if nm in ('FAN_TACH', 'FAN_TACH_RAW'):
|
||||||
|
del_spans.append(span(el)); report['labels_deleted'].append((nm, pos, 'tach-sweep'))
|
||||||
|
for pos, el in nc_at.items():
|
||||||
|
if pos in node_del:
|
||||||
|
del_spans.append(span(el)); report['nc_deleted'].append(pos)
|
||||||
|
for pos, el in junc_at.items():
|
||||||
|
if pos in node_del:
|
||||||
|
del_spans.append(span(el)); report['junctions_deleted'].append(pos)
|
||||||
|
|
||||||
|
# text patch: BLOCK N note (ETH_INT moved)
|
||||||
|
text_patches = []
|
||||||
|
for t in texts:
|
||||||
|
tv = sval(kids(t)[1])
|
||||||
|
if tv and 'INT PB2' in tv:
|
||||||
|
a, b = span(t)
|
||||||
|
text_patches.append((a, b, src[a:b].replace('INT PB2', 'INT PC0 (3.0: PB2 = BOOT1 strap — never repurpose)')))
|
||||||
|
report['texts_patched'].append('BLOCK N note: INT PB2 -> INT PC0')
|
||||||
|
|
||||||
|
# ---------------- templates from live file ----------------
|
||||||
|
def label_template(pos):
|
||||||
|
for nm, el in lab_at[pos]:
|
||||||
|
a, b = span(el); return src[a:b], nm
|
||||||
|
return None, None
|
||||||
|
# LEFT-side sample: label on J1 pin15 (NTC_TEMP); RIGHT-side: label on J2 pin1 (ETH_CS)
|
||||||
|
J1p = pin_world(J1); J2p = pin_world(J2)
|
||||||
|
tmplL, _ = label_template(J1p['15'])
|
||||||
|
tmplR, _ = label_template(J2p['1'])
|
||||||
|
assert tmplL and tmplR
|
||||||
|
|
||||||
|
def NU(): return str(uuid.uuid4())
|
||||||
|
def mk_label(name, x, y, side):
|
||||||
|
"""side: 'L' extends left, 'R' extends right, 'U' vertical up, 'D' vertical down"""
|
||||||
|
t = tmplL if side == 'L' else tmplR
|
||||||
|
# replace name, position, uuid in template
|
||||||
|
def rep(m):
|
||||||
|
return f'(at {x:g} {y:g} {ANG})'
|
||||||
|
ANG = {'L': 180, 'R': 0, 'U': 90, 'D': 270}[side]
|
||||||
|
out = re.sub(r'\(label "[^"]*"', f'(label "{name}"', t, count=1)
|
||||||
|
out = re.sub(r'\(at [^)]*\)', f'(at {x:g} {y:g} {ANG})', out, count=1)
|
||||||
|
out = re.sub(r'\(uuid "[^"]*"\)', f'(uuid "{NU()}")', out, count=1)
|
||||||
|
if side in ('R',):
|
||||||
|
out = re.sub(r'\(justify [^)]*\)', '(justify left bottom)', out, count=1)
|
||||||
|
elif side in ('L',):
|
||||||
|
out = re.sub(r'\(justify [^)]*\)', '(justify right bottom)', out, count=1)
|
||||||
|
else:
|
||||||
|
out = re.sub(r'\(justify [^)]*\)', '(justify left bottom)', out, count=1)
|
||||||
|
return out
|
||||||
|
def mk_nc(x, y):
|
||||||
|
return f'(no_connect\n\t\t(at {x:g} {y:g})\n\t\t(uuid "{NU()}")\n\t)'
|
||||||
|
def mk_text(txt, x, y):
|
||||||
|
e = texts[0]; a, b = span(e); t = src[a:b]
|
||||||
|
t = re.sub(r'^\(text "[^"]*(?:\\.[^"]*)*"', '(text ' + json.dumps(txt), t, count=1)
|
||||||
|
t = re.sub(r'\(at [^)]*\)', f'(at {x:g} {y:g} 0)', t, count=1)
|
||||||
|
t = re.sub(r'\(uuid "[^"]*"\)', f'(uuid "{NU()}")', t, count=1)
|
||||||
|
return t
|
||||||
|
|
||||||
|
# generic instance factory from template R20
|
||||||
|
R20 = by_ref('R20'); a, b = span(R20['el']); INST_TMPL = src[a:b]
|
||||||
|
def mk_instance(lib_id, ref, value, footprint, x, y, rot=0, pin_nums=None, extra_props=None):
|
||||||
|
t = INST_TMPL
|
||||||
|
t = re.sub(r'\(lib_id "[^"]*"\)', f'(lib_id "{lib_id}")', t, count=1)
|
||||||
|
t = re.sub(r'\(at [^)]*\)', f'(at {x:g} {y:g} {rot:g})', t, count=1) # first (at = instance
|
||||||
|
t = re.sub(r'\(property "Reference" "[^"]*"', f'(property "Reference" "{ref}"', t, count=1)
|
||||||
|
t = re.sub(r'\(property "Value" "[^"]*"', f'(property "Value" {json.dumps(value)}', t, count=1)
|
||||||
|
t = re.sub(r'\(property "Footprint" "[^"]*"', f'(property "Footprint" {json.dumps(footprint)}', t, count=1)
|
||||||
|
# property positions: drop to instance pos (KiCad re-autoplaces visually; positions cosmetic)
|
||||||
|
# fix property (at ...) occurrences AFTER the first: leave — cosmetic only.
|
||||||
|
# pins: template has pins "1","2" — rebuild pin uuid list for pin_nums
|
||||||
|
pin_nums = pin_nums or ['1', '2']
|
||||||
|
pin_block = '\n'.join(f'\t\t(pin "{p}"\n\t\t\t(uuid "{NU()}")\n\t\t)' for p in pin_nums)
|
||||||
|
t = re.sub(r'(\t\t\(pin "1".*?\)\n)+.*?\t\t\(pin "2"\n\t\t\t\(uuid "[^"]*"\)\n\t\t\)',
|
||||||
|
pin_block, t, count=1, flags=re.S)
|
||||||
|
t = re.sub(r'\(reference "[^"]*"\)', f'(reference "{ref}")', t, count=1)
|
||||||
|
t = re.sub(r'\(uuid "a2b3658d[^"]*"\)', f'(uuid "{NU()}")', t, count=1)
|
||||||
|
return t
|
||||||
|
|
||||||
|
# ---------------- MCU lib symbol (built from official pin map) ----------------
|
||||||
|
MCU_PINS = [
|
||||||
|
(1,'VBAT','power_in',-5.08,48.26,270),(2,'PC13','bidirectional',-17.78,-15.24,0),
|
||||||
|
(3,'PC14','bidirectional',-17.78,-17.78,0),(4,'PC15','bidirectional',-17.78,-20.32,0),
|
||||||
|
(5,'PH0','bidirectional',-17.78,30.48,0),(6,'PH1','bidirectional',-17.78,27.94,0),
|
||||||
|
(7,'NRST','input',-17.78,40.64,0),(8,'PC0','bidirectional',-17.78,17.78,0),
|
||||||
|
(9,'PC1','bidirectional',-17.78,15.24,0),(10,'PC2','bidirectional',-17.78,12.7,0),
|
||||||
|
(11,'PC3','bidirectional',-17.78,10.16,0),(12,'VSSA','power_in',2.54,-45.72,90),
|
||||||
|
(13,'VDDA','power_in',7.62,48.26,270),(14,'PA0','bidirectional',17.78,40.64,180),
|
||||||
|
(15,'PA1','bidirectional',17.78,38.1,180),(16,'PA2','bidirectional',17.78,35.56,180),
|
||||||
|
(17,'PA3','bidirectional',17.78,33.02,180),(18,'VSS','power_in',0,-45.72,90),
|
||||||
|
(19,'VDD','power_in',-2.54,48.26,270),(20,'PA4','bidirectional',17.78,30.48,180),
|
||||||
|
(21,'PA5','bidirectional',17.78,27.94,180),(22,'PA6','bidirectional',17.78,25.4,180),
|
||||||
|
(23,'PA7','bidirectional',17.78,22.86,180),(24,'PC4','bidirectional',-17.78,7.62,0),
|
||||||
|
(25,'PC5','bidirectional',-17.78,5.08,0),(26,'PB0','bidirectional',17.78,-2.54,180),
|
||||||
|
(27,'PB1','bidirectional',17.78,-5.08,180),(28,'PB2','bidirectional',17.78,-7.62,180),
|
||||||
|
(29,'PB10','bidirectional',17.78,-27.94,180),(30,'VCAP1','power_out',-17.78,-25.4,0),
|
||||||
|
(31,'VSS','passive',0,-45.72,90),(32,'VDD','power_in',0,48.26,270),
|
||||||
|
(33,'PB12','bidirectional',17.78,-30.48,180),(34,'PB13','bidirectional',17.78,-33.02,180),
|
||||||
|
(35,'PB14','bidirectional',17.78,-35.56,180),(36,'PB15','bidirectional',17.78,-38.1,180),
|
||||||
|
(37,'PC6','bidirectional',-17.78,2.54,0),(38,'PC7','bidirectional',-17.78,0,0),
|
||||||
|
(39,'PC8','bidirectional',-17.78,-2.54,0),(40,'PC9','bidirectional',-17.78,-5.08,0),
|
||||||
|
(41,'PA8','bidirectional',17.78,20.32,180),(42,'PA9','bidirectional',17.78,17.78,180),
|
||||||
|
(43,'PA10','bidirectional',17.78,15.24,180),(44,'PA11','bidirectional',17.78,12.7,180),
|
||||||
|
(45,'PA12','bidirectional',17.78,10.16,180),(46,'PA13','bidirectional',17.78,7.62,180),
|
||||||
|
(47,'VSS','passive',0,-45.72,90),(48,'VDD','power_in',2.54,48.26,270),
|
||||||
|
(49,'PA14','bidirectional',17.78,5.08,180),(50,'PA15','bidirectional',17.78,2.54,180),
|
||||||
|
(51,'PC10','bidirectional',-17.78,-7.62,0),(52,'PC11','bidirectional',-17.78,-10.16,0),
|
||||||
|
(53,'PC12','bidirectional',-17.78,-12.7,0),(54,'PD2','bidirectional',-17.78,22.86,0),
|
||||||
|
(55,'PB3','bidirectional',17.78,-10.16,180),(56,'PB4','bidirectional',17.78,-12.7,180),
|
||||||
|
(57,'PB5','bidirectional',17.78,-15.24,180),(58,'PB6','bidirectional',17.78,-17.78,180),
|
||||||
|
(59,'PB7','bidirectional',17.78,-20.32,180),(60,'BOOT0','input',-17.78,35.56,0),
|
||||||
|
(61,'PB8','bidirectional',17.78,-22.86,180),(62,'PB9','bidirectional',17.78,-25.4,180),
|
||||||
|
(63,'VSS','passive',0,-45.72,90),(64,'VDD','power_in',5.08,48.26,270),
|
||||||
|
]
|
||||||
|
def mcu_libsym():
|
||||||
|
pins_txt = []
|
||||||
|
for num, name, etype, x, y, ang in MCU_PINS:
|
||||||
|
hide = '\n\t\t\t\t\t(hide yes)' if etype == 'passive' and name == 'VSS' and num != 18 else ''
|
||||||
|
pins_txt.append(f'''\t\t\t\t(pin {etype} line
|
||||||
|
\t\t\t\t\t(at {x:g} {y:g} {ang}){hide}
|
||||||
|
\t\t\t\t\t(length 2.54)
|
||||||
|
\t\t\t\t\t(name "{name}"
|
||||||
|
\t\t\t\t\t\t(effects
|
||||||
|
\t\t\t\t\t\t\t(font
|
||||||
|
\t\t\t\t\t\t\t\t(size 1.27 1.27)
|
||||||
|
\t\t\t\t\t\t\t)
|
||||||
|
\t\t\t\t\t\t)
|
||||||
|
\t\t\t\t\t)
|
||||||
|
\t\t\t\t\t(number "{num}"
|
||||||
|
\t\t\t\t\t\t(effects
|
||||||
|
\t\t\t\t\t\t\t(font
|
||||||
|
\t\t\t\t\t\t\t\t(size 1.27 1.27)
|
||||||
|
\t\t\t\t\t\t\t)
|
||||||
|
\t\t\t\t\t\t)
|
||||||
|
\t\t\t\t\t)
|
||||||
|
\t\t\t\t)''')
|
||||||
|
pins = '\n'.join(pins_txt)
|
||||||
|
return f'''\t\t(symbol "MCU_ST_STM32F4:STM32F411RETx"
|
||||||
|
\t\t\t(pin_names
|
||||||
|
\t\t\t\t(offset 1.016)
|
||||||
|
\t\t\t)
|
||||||
|
\t\t\t(exclude_from_sim no)
|
||||||
|
\t\t\t(in_bom yes)
|
||||||
|
\t\t\t(on_board yes)
|
||||||
|
\t\t\t(property "Reference" "U"
|
||||||
|
\t\t\t\t(at -15.24 49.53 0)
|
||||||
|
\t\t\t\t(effects
|
||||||
|
\t\t\t\t\t(font
|
||||||
|
\t\t\t\t\t\t(size 1.27 1.27)
|
||||||
|
\t\t\t\t\t)
|
||||||
|
\t\t\t\t\t(justify left)
|
||||||
|
\t\t\t\t)
|
||||||
|
\t\t\t)
|
||||||
|
\t\t\t(property "Value" "STM32F411RETx"
|
||||||
|
\t\t\t\t(at -15.24 -46.99 0)
|
||||||
|
\t\t\t\t(effects
|
||||||
|
\t\t\t\t\t(font
|
||||||
|
\t\t\t\t\t\t(size 1.27 1.27)
|
||||||
|
\t\t\t\t\t)
|
||||||
|
\t\t\t\t\t(justify left)
|
||||||
|
\t\t\t\t)
|
||||||
|
\t\t\t)
|
||||||
|
\t\t\t(property "Footprint" "Package_QFP:LQFP-64_10x10mm_P0.5mm"
|
||||||
|
\t\t\t\t(at 0 0 0)
|
||||||
|
\t\t\t\t(effects
|
||||||
|
\t\t\t\t\t(font
|
||||||
|
\t\t\t\t\t\t(size 1.27 1.27)
|
||||||
|
\t\t\t\t\t)
|
||||||
|
\t\t\t\t\t(hide yes)
|
||||||
|
\t\t\t\t)
|
||||||
|
\t\t\t)
|
||||||
|
\t\t\t(property "Datasheet" "https://www.st.com/resource/en/datasheet/stm32f411re.pdf"
|
||||||
|
\t\t\t\t(at 0 0 0)
|
||||||
|
\t\t\t\t(effects
|
||||||
|
\t\t\t\t\t(font
|
||||||
|
\t\t\t\t\t\t(size 1.27 1.27)
|
||||||
|
\t\t\t\t\t)
|
||||||
|
\t\t\t\t\t(hide yes)
|
||||||
|
\t\t\t\t)
|
||||||
|
\t\t\t)
|
||||||
|
\t\t\t(symbol "STM32F411RETx_0_1"
|
||||||
|
\t\t\t\t(rectangle
|
||||||
|
\t\t\t\t\t(start -15.24 45.72)
|
||||||
|
\t\t\t\t\t(end 15.24 -43.18)
|
||||||
|
\t\t\t\t\t(stroke
|
||||||
|
\t\t\t\t\t\t(width 0.254)
|
||||||
|
\t\t\t\t\t\t(type default)
|
||||||
|
\t\t\t\t\t)
|
||||||
|
\t\t\t\t\t(fill
|
||||||
|
\t\t\t\t\t\t(type background)
|
||||||
|
\t\t\t\t\t)
|
||||||
|
\t\t\t\t)
|
||||||
|
\t\t\t)
|
||||||
|
\t\t\t(symbol "STM32F411RETx_1_1"
|
||||||
|
{pins}
|
||||||
|
\t\t\t)
|
||||||
|
\t\t)'''
|
||||||
|
|
||||||
|
# ---------------- Block P content ----------------
|
||||||
|
INS = [] # element text blocks to append at end of doc
|
||||||
|
def add(t): INS.append(t)
|
||||||
|
|
||||||
|
# U16 at grid
|
||||||
|
U16X, U16Y = 500.38, 434.34
|
||||||
|
mcu_world = {}
|
||||||
|
for num, name, etype, x, y, ang in MCU_PINS:
|
||||||
|
mcu_world[num] = (R2(U16X + x), R2(U16Y - y))
|
||||||
|
MCU_NETS = {1:'3V3',2:'LED_C13',3:'LSE_IN',4:'LSE_OUT',5:'HSE_IN',6:'HSE_OUT',7:'NRST',8:'ETH_INT',
|
||||||
|
12:'GND',13:'VDDA',14:'BAT_SENSE',15:'PWR_CTRL',16:'GNSS_TX',17:'GNSS_RX',18:'GND',19:'3V3',
|
||||||
|
20:'5V_SENSE',21:'IGN_SENSE',22:'FAN_PWM',26:'EXT_LED',27:'NTC_TEMP',28:'BOOT1_STRAP',30:'VCAP1',
|
||||||
|
32:'3V3',33:'ETH_CS',34:'ETH_SCK',35:'ETH_MISO',36:'ETH_MOSI',41:'CHRG_EN',42:'USART1_TX',
|
||||||
|
43:'USART1_RX',44:'DFU_DM',45:'DFU_DP',46:'SWDIO',48:'3V3',49:'SWCLK',50:'ETH_RST',
|
||||||
|
55:'CHRG_STAT',56:'CHRG_FAULT',57:'BYP_CTRL',58:'I2C_SCL',59:'I2C_SDA',60:'BOOT0',
|
||||||
|
61:'SER_IRQ',62:None,64:'3V3'}
|
||||||
|
MCU_NC = [9,10,11,23,24,25,29,37,38,39,40,51,52,53,54,62]
|
||||||
|
add(mk_instance('MCU_ST_STM32F4:STM32F411RETx', 'U16', 'STM32F411RET6',
|
||||||
|
'Package_QFP:LQFP-64_10x10mm_P0.5mm', U16X, U16Y, 0,
|
||||||
|
[str(n) for n, *_ in MCU_PINS]))
|
||||||
|
for num, name, etype, x, y, ang in MCU_PINS:
|
||||||
|
wx, wy = mcu_world[num]
|
||||||
|
net = MCU_NETS.get(num)
|
||||||
|
if num in MCU_NC:
|
||||||
|
add(mk_nc(wx, wy)); continue
|
||||||
|
if net is None: continue
|
||||||
|
side = {0: 'L', 180: 'R', 270: 'U', 90: 'D'}[ang]
|
||||||
|
if num in (31, 47, 63): continue # stacked VSS share pin18's point/label
|
||||||
|
add(mk_label(net, wx, wy, side))
|
||||||
|
|
||||||
|
# passives / support parts: label-on-pin style (v4 house pattern)
|
||||||
|
PART_LIBS = {}
|
||||||
|
def two_pin(lib_id, ref, value, fp, x, y, net1, net2, rot=0):
|
||||||
|
pins = lib_pins(lib_id)
|
||||||
|
inst = dict(lib_id=lib_id, x=x, y=y, rot=rot, mirror=None)
|
||||||
|
pw = pin_world(inst, pins)
|
||||||
|
nums = sorted(pw, key=lambda n: int(re.sub(r'\D', '', n) or 0))
|
||||||
|
add(mk_instance(lib_id, ref, value, fp, x, y, rot, nums))
|
||||||
|
for num, net in zip(nums, (net1, net2)):
|
||||||
|
px, py = pw[num]
|
||||||
|
side = 'R' if px > x else ('L' if px < x else ('U' if py < y else 'D'))
|
||||||
|
if net: add(mk_label(net, px, py, side))
|
||||||
|
|
||||||
|
FP_R = 'Resistor_SMD:R_0603_1608Metric'
|
||||||
|
FP_C = 'Capacitor_SMD:C_0603_1608Metric'
|
||||||
|
FP_C0805 = 'Capacitor_SMD:C_0805_2012Metric'
|
||||||
|
FP_LED = 'LED_SMD:LED_0603_1608Metric'
|
||||||
|
FP_TVS = 'Diode_SMD:D_SOD-323'
|
||||||
|
D2fp = by_ref('D2')['fp'] # SS34 footprint in use
|
||||||
|
Y1fp = by_ref('Y1')['fp'] # 25MHz crystal footprint in use
|
||||||
|
SW1fp = by_ref('SW1')['fp']
|
||||||
|
TP1fp = by_ref('TP1')['fp']
|
||||||
|
J9 = by_ref('J9')
|
||||||
|
C23fp = by_ref('C23')['fp']
|
||||||
|
P6fp_old = P6['fp'] or ''
|
||||||
|
P6fp_new = P6fp_old.replace('1x04', '1x02') if '1x04' in P6fp_old else P6fp_old
|
||||||
|
|
||||||
|
ROWA, ROWB = 502.92, 530.86
|
||||||
|
two_pin('Switch:SW_Push', 'SW2', 'BOOT0', SW1fp, 436.88, ROWA, '3V3', 'BOOT0')
|
||||||
|
two_pin('Device:R', 'R98', '10k', FP_R, 449.58, ROWA, 'BOOT0', 'GND')
|
||||||
|
two_pin('Device:R', 'R99', '10k', FP_R, 462.28, ROWA, 'BOOT1_STRAP', 'GND')
|
||||||
|
two_pin('Device:C', 'C104', '100nF', FP_C, 474.98, ROWA, 'NRST', 'GND')
|
||||||
|
for i, xx in enumerate([487.68, 500.38, 513.08, 525.78]):
|
||||||
|
two_pin('Device:C', f'C{105+i}', '100nF', FP_C, xx, ROWA, '3V3', 'GND')
|
||||||
|
two_pin('Device:C', 'C109', '100nF', FP_C, 538.48, ROWA, 'VDDA', 'GND')
|
||||||
|
two_pin('Device:C', 'C110', '4.7uF', FP_C, 551.18, ROWA, '3V3', 'GND')
|
||||||
|
two_pin('Device:C', 'C111', '4.7uF', FP_C, 563.88, ROWA, 'VCAP1', 'GND')
|
||||||
|
two_pin('Device:C', 'C112', '1uF', FP_C, 576.58, ROWA, 'VDDA', 'GND')
|
||||||
|
two_pin('Device:R', 'R104', '10R', FP_R, 589.28, ROWA, '3V3', 'VDDA')
|
||||||
|
|
||||||
|
two_pin('Device:Crystal', 'Y3', '25MHz', Y1fp, 436.88, ROWB, 'HSE_IN', 'HSE_OUT')
|
||||||
|
two_pin('Device:C', 'C113', '15pF', FP_C, 449.58, ROWB, 'HSE_IN', 'GND')
|
||||||
|
two_pin('Device:C', 'C114', '15pF', FP_C, 462.28, ROWB, 'HSE_OUT', 'GND')
|
||||||
|
two_pin('Device:Crystal', 'Y4', '32.768kHz', 'Crystal:Crystal_SMD_3215-2Pin_3.2x1.5mm',
|
||||||
|
474.98, ROWB, 'LSE_IN', 'LSE_OUT')
|
||||||
|
two_pin('Device:C', 'C115', '12pF', FP_C, 487.68, ROWB, 'LSE_IN', 'GND')
|
||||||
|
two_pin('Device:C', 'C116', '12pF', FP_C, 500.38, ROWB, 'LSE_OUT', 'GND')
|
||||||
|
# LEDs: Device:LED pin1=K pin2=A
|
||||||
|
two_pin('Device:R', 'R102', '1k', FP_R, 513.08, ROWB, '3V3', 'LED_C13_A')
|
||||||
|
two_pin('Device:LED', 'D17', 'LED C13 (blue)', FP_LED, 525.78, ROWB, 'LED_C13', 'LED_C13_A')
|
||||||
|
two_pin('Device:R', 'R103', '1k', FP_R, 538.48, ROWB, '3V3', 'LED_PWR_A')
|
||||||
|
two_pin('Device:LED', 'D18', 'LED PWR (green)', FP_LED, 551.18, ROWB, 'GND', 'LED_PWR_A')
|
||||||
|
for ref, net, xx in [('TP3', 'SWDIO', 563.88), ('TP4', 'SWCLK', 576.58), ('TP5', 'NRST', 589.28),
|
||||||
|
('TP6', 'GND', 601.98), ('TP7', '3V3', 614.68)]:
|
||||||
|
pins = lib_pins('Connector:TestPoint')
|
||||||
|
inst = dict(lib_id='Connector:TestPoint', x=xx, y=ROWB, rot=0, mirror=None)
|
||||||
|
pw = pin_world(inst, pins)
|
||||||
|
add(mk_instance('Connector:TestPoint', ref, net, TP1fp, xx, ROWB, 0, list(pw)))
|
||||||
|
(px, py) = list(pw.values())[0]
|
||||||
|
add(mk_label(net, px, py, 'D' if py > ROWB else 'U'))
|
||||||
|
|
||||||
|
# LDO block
|
||||||
|
two_pin('Device:D_Schottky', 'D12', 'SS34', D2fp, 627.38, ROWA, 'LDO_IN', 'SYS5V') # pin1=K pin2=A
|
||||||
|
two_pin('Device:D_Schottky', 'D13', 'SS34', D2fp, 640.08, ROWA, 'LDO_IN', 'DFU_VBUS')
|
||||||
|
u17pins = lib_pins('Regulator_Linear:AMS1117-3.3')
|
||||||
|
U17X, U17Y = 665.48, ROWA
|
||||||
|
inst = dict(lib_id='Regulator_Linear:AMS1117-3.3', x=U17X, y=U17Y, rot=0, mirror=None)
|
||||||
|
pw = pin_world(inst, u17pins)
|
||||||
|
add(mk_instance('Regulator_Linear:AMS1117-3.3', 'U17', 'AMS1117-3.3',
|
||||||
|
'Package_TO_SOT_SMD:SOT-223-3_TabPin2', U17X, U17Y, 0, [p['num'] for p in u17pins]))
|
||||||
|
name_by_num = {p['num']: p['name'].upper() for p in u17pins}
|
||||||
|
for num, (px, py) in pw.items():
|
||||||
|
nm = name_by_num[num]
|
||||||
|
net = 'LDO_IN' if nm in ('VI', 'VIN', 'IN') else ('3V3' if nm in ('VO', 'VOUT', 'OUT') else 'GND')
|
||||||
|
side = 'R' if px > U17X else ('L' if px < U17X else ('U' if py < U17Y else 'D'))
|
||||||
|
add(mk_label(net, px, py, side))
|
||||||
|
two_pin('Device:C', 'C117', '10uF', FP_C0805, 690.88, ROWA, 'LDO_IN', 'GND')
|
||||||
|
two_pin('Device:C', 'C118', '22uF/16V', C23fp or FP_C0805, 703.58, ROWA, '3V3', 'GND')
|
||||||
|
for ref, net, xx in [('PF12', 'LDO_IN', 716.28), ('PF13', 'DFU_VBUS', 728.98)]:
|
||||||
|
pins = lib_pins('power:PWR_FLAG')
|
||||||
|
inst = dict(lib_id='power:PWR_FLAG', x=xx, y=ROWA, rot=0, mirror=None)
|
||||||
|
pw = pin_world(inst, pins)
|
||||||
|
add(mk_instance('power:PWR_FLAG', ref, 'PWR_FLAG', '', xx, ROWA, 0, list(pw)))
|
||||||
|
(px, py) = list(pw.values())[0]
|
||||||
|
add(mk_label(net, px, py, 'D' if py > ROWA else 'U'))
|
||||||
|
|
||||||
|
# USB-C DFU port: clone J9 geometry+pattern with DFU_* nets
|
||||||
|
J9pins = pin_world(J9)
|
||||||
|
J11X, J11Y = 660.4, 430.53
|
||||||
|
NETMAP = {'USB_VBUS': 'DFU_VBUS', 'USB_DP': 'DFU_DP', 'USB_DM': 'DFU_DM',
|
||||||
|
'USB_CC1': 'DFU_CC1', 'USB_CC2': 'DFU_CC2'}
|
||||||
|
# what J9 has per pin: label at pin OR nc
|
||||||
|
a9, b9 = span(J9['el']); j9txt = src[a9:b9]
|
||||||
|
j9txt = re.sub(r'\(property "Reference" "J9"', '(property "Reference" "J11"', j9txt, count=1)
|
||||||
|
j9txt = re.sub(r'\(property "Value" "[^"]*"', '(property "Value" "USB-C DFU"', j9txt, count=1)
|
||||||
|
j9txt = re.sub(r'\(at ([\-0-9.]+) ([\-0-9.]+)( [\-0-9.]+)?\)',
|
||||||
|
lambda m, base=[0]: m.group(0), j9txt) # keep; we shift below numerically
|
||||||
|
# shift all coordinates by delta
|
||||||
|
DX, DY = R2(J11X - J9['x']), R2(J11Y - J9['y'])
|
||||||
|
def shift_coords(txt, dx, dy):
|
||||||
|
def r(m):
|
||||||
|
vals = m.group(1).split()
|
||||||
|
x = float(vals[0]) + dx; y = float(vals[1]) + dy
|
||||||
|
rest = (' ' + ' '.join(vals[2:])) if len(vals) > 2 else ''
|
||||||
|
return f'(at {x:g} {y:g}{rest})'
|
||||||
|
return re.sub(r'\(at ([^)]*)\)', r, txt)
|
||||||
|
j9txt = shift_coords(j9txt, DX, DY)
|
||||||
|
j9txt = re.sub(r'\(uuid "[^"]*"\)', lambda m: f'(uuid "{NU()}")', j9txt)
|
||||||
|
j9txt = re.sub(r'\(reference "J9"\)', '(reference "J11")', j9txt)
|
||||||
|
add(j9txt)
|
||||||
|
# labels/nc for J11 pins mirroring J9's connection style
|
||||||
|
for num, pos in J9pins.items():
|
||||||
|
npos = (R2(pos[0] + DX), R2(pos[1] + DY))
|
||||||
|
if pos in nc_at:
|
||||||
|
add(mk_nc(*npos)); continue
|
||||||
|
here = [nm for nm, _ in lab_at.get(pos, [])]
|
||||||
|
if not here and pos in adj:
|
||||||
|
# pin connected via a wire run in the original (e.g. SH -> wire -> GND label):
|
||||||
|
# resolve the net name by graph walk and label the cloned pin directly.
|
||||||
|
seen = {pos}; st = [pos]; found = None
|
||||||
|
while st and not found:
|
||||||
|
q = st.pop()
|
||||||
|
lbls = [nm for nm, _ in lab_at.get(q, [])]
|
||||||
|
if lbls: found = lbls[0]; break
|
||||||
|
for r_ in adj[q]:
|
||||||
|
if r_ not in seen: seen.add(r_); st.append(r_)
|
||||||
|
if found: here = [found]
|
||||||
|
if here:
|
||||||
|
nm = here[0]
|
||||||
|
newnm = NETMAP.get(nm, nm)
|
||||||
|
side = 'R' if pos[0] > J9['x'] else 'L'
|
||||||
|
add(mk_label(newnm, npos[0], npos[1], side))
|
||||||
|
# CC pulldowns + TVS
|
||||||
|
two_pin('Device:R', 'R100', '5.1k', FP_R, 704.85, 430.53, 'DFU_CC1', 'GND')
|
||||||
|
two_pin('Device:R', 'R101', '5.1k', FP_R, 717.55, 430.53, 'DFU_CC2', 'GND')
|
||||||
|
two_pin('Device:D_TVS', 'D14', 'PESD5V0S1BA', FP_TVS, 704.85, 458.47, 'DFU_DP', 'GND')
|
||||||
|
two_pin('Device:D_TVS', 'D15', 'PESD5V0S1BA', FP_TVS, 717.55, 458.47, 'DFU_DM', 'GND')
|
||||||
|
two_pin('Device:D_TVS', 'D16', 'PESD5V0S1BA', FP_TVS, 730.25, 458.47, 'DFU_VBUS', 'GND')
|
||||||
|
|
||||||
|
# 2-pin fan connector at old P6 site (reuse ref P6)
|
||||||
|
oldp = pin_world(P6)
|
||||||
|
np6x, np6y = P6['x'], P6['y']
|
||||||
|
two_pin('Connector_Generic:Conn_01x02', 'P6', 'FAN 2-pin', P6fp_new, np6x, np6y,
|
||||||
|
'5V_FAN', 'FAN_RET', rot=P6['rot'])
|
||||||
|
|
||||||
|
# notes
|
||||||
|
add(mk_text('BLOCK P - ON-BOARD MCU (EinarBoard 3.0). STM32F411RET6 LQFP64 replaces Blackpill+J1/J2. DFU: hold BOOT0, tap NRST -> USB. HSE 25MHz REQUIRED for ROM-bootloader USB clock (AN2606). PB2=BOOT1 strapped LOW via R99 - NEVER repurpose PB2. Bench flash: USB powers 3V3 domain only via D13 (SYS5V dark, K1 stays NC).', 420, 372))
|
||||||
|
add(mk_text('PC6/PC7 reserved: USART6 (3rd UART, future). Free: PA7, PB9, PB10, PC1-PC5, PC8-PC12, PD2. LED_C13 active-LOW (Blackpill parity). SWD: TP3-TP7 (SWDIO/SWCLK/NRST/GND/3V3).', 420, 377))
|
||||||
|
|
||||||
|
# ---------------- splice ----------------
|
||||||
|
new_src = src
|
||||||
|
# apply text patches + deletions together, sorted desc by start
|
||||||
|
ops = [(a, b, '') for (a, b) in del_spans] + [(a, b, t) for (a, b, t) in text_patches]
|
||||||
|
ops.sort(key=lambda o: -o[0])
|
||||||
|
spans_sorted = sorted([(a, b) for a, b, _ in ops])
|
||||||
|
for (a1, b1), (a2, b2) in zip(spans_sorted, spans_sorted[1:]):
|
||||||
|
assert b1 <= a2, f'overlapping spans {a1,b1} {a2,b2}'
|
||||||
|
for a, b, t in ops:
|
||||||
|
# widen deletion to swallow leading whitespace
|
||||||
|
a0 = a
|
||||||
|
while a0 > 0 and new_src[a0-1] in ' \t\n': a0 -= 1
|
||||||
|
if t == '':
|
||||||
|
new_src = new_src[:a0] + '\n\t' + new_src[b:]
|
||||||
|
else:
|
||||||
|
new_src = new_src[:a] + t + new_src[b:]
|
||||||
|
# insert lib symbol before lib_symbols closing paren
|
||||||
|
ls_a, ls_b = span(libsym_el)
|
||||||
|
# recompute shift: all deletions were AFTER lib_symbols? assert to be safe
|
||||||
|
assert all(a > ls_b for a, b, _ in ops), 'a deletion overlaps lib_symbols - unhandled'
|
||||||
|
new_src = new_src[:ls_b-1] + '\n' + mcu_libsym() + '\n\t' + new_src[ls_b-1:]
|
||||||
|
# append new elements before final closing paren
|
||||||
|
end = new_src.rfind(')')
|
||||||
|
body = '\n\t' + '\n\t'.join(INS) + '\n'
|
||||||
|
new_src = new_src[:end] + body + new_src[end:]
|
||||||
|
|
||||||
|
open(FN, 'w', encoding='utf-8').write(new_src)
|
||||||
|
print('WROTE', FN, len(new_src), 'bytes (was', len(src), ')')
|
||||||
|
for k, v in report.items():
|
||||||
|
print(f'-- {k}: {len(v)}')
|
||||||
|
for item in v[:40]: print(' ', item)
|
||||||
198
scripts/2026-08-12_einarboard30_phaseB2_revision.py
Normal file
198
scripts/2026-08-12_einarboard30_phaseB2_revision.py
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
EinarBoard 3.0 — Phase B.2: placement revision per Leo's review (12-Ago).
|
||||||
|
- Rip ALL tracks/vias of the 24 old socket nets + /NRST (reroute in C)
|
||||||
|
- Endpoint-rip stubs at old pad sites of every moved footprint (this + last round)
|
||||||
|
- Delete Blackpill bay silk (labels row + title + outline gfx)
|
||||||
|
- Pack R85/R86/R87/R88/D11 east beside Q1/Q5; buck cluster U12+L8+C100+C101 below C43
|
||||||
|
- U16 + full support ring -> freed bay (~119,63.5); LDO cluster -> tight block; J11 north;
|
||||||
|
LEDs south of J11; SW2 -> beside H4; TPs -> north strip
|
||||||
|
- MH7-12 reference text -> 1.0mm; version silk 2.0->3.0, HBOX v4->v5
|
||||||
|
"""
|
||||||
|
import re, sys, math, uuid, collections
|
||||||
|
|
||||||
|
CUR = 'hbox-watchdog-v5.kicad_pcb'
|
||||||
|
ORIG = 'pcb.orig'
|
||||||
|
src = open(CUR, encoding='utf-8').read()
|
||||||
|
orig = open(ORIG, encoding='utf-8').read()
|
||||||
|
assert '"U16"' in src, 'phase B output expected'
|
||||||
|
if 'STM32F411 BLACKPILL' not in src:
|
||||||
|
print('ABORT: bay silk already gone (B.2 already ran?)'); sys.exit(1)
|
||||||
|
|
||||||
|
def NU(): return str(uuid.uuid4())
|
||||||
|
def endof(s, start):
|
||||||
|
d=0; ins=False; esc=False
|
||||||
|
for k in range(start, len(s)):
|
||||||
|
c=s[k]
|
||||||
|
if esc: esc=False; continue
|
||||||
|
if c=='\\': esc=True; continue
|
||||||
|
if c=='"': ins=not ins; continue
|
||||||
|
if not ins:
|
||||||
|
if c=='(': d+=1
|
||||||
|
elif c==')':
|
||||||
|
d-=1
|
||||||
|
if d==0: return k+1
|
||||||
|
return -1
|
||||||
|
def rotpt(lx, ly, deg):
|
||||||
|
r = math.radians((-deg) % 360) # ROTSGN=-1 convention baked in
|
||||||
|
return (lx*math.cos(r) - ly*math.sin(r), lx*math.sin(r) + ly*math.cos(r))
|
||||||
|
|
||||||
|
def parse_fps(s):
|
||||||
|
out={}
|
||||||
|
for m in re.finditer(r'\(footprint\s+"([^"]+)"', s):
|
||||||
|
a=m.start(); e=endof(s,a); blk=s[a:e]
|
||||||
|
rm=re.search(r'\(property "Reference"\s+"([^"]+)"', blk)
|
||||||
|
am=re.search(r'\(at ([\-0-9.]+) ([\-0-9.]+)( [\-0-9.]+)?\)', blk)
|
||||||
|
if rm and am and rm.group(1) not in out:
|
||||||
|
out[rm.group(1)]=dict(ref=rm.group(1), lib=m.group(1), x=float(am.group(1)),
|
||||||
|
y=float(am.group(2)), rot=float((am.group(3) or '0')),
|
||||||
|
span=(a,e), blk=blk)
|
||||||
|
return out
|
||||||
|
def pads_of(blk):
|
||||||
|
out=[]
|
||||||
|
for m in re.finditer(r'\(pad\s+"([^"]*)"\s+(np_thru_hole|thru_hole|smd)\s+(\w+)', blk):
|
||||||
|
a=m.start(); e=endof(blk,a); p=blk[a:e]
|
||||||
|
am=re.search(r'\(at ([\-0-9.]+) ([\-0-9.]+)( [\-0-9.]+)?\)', p)
|
||||||
|
nm=re.search(r'\(net "((?:[^"\\]|\\.)*)"\)', p)
|
||||||
|
sm=re.search(r'\(size ([\-0-9.]+) ([\-0-9.]+)\)', p)
|
||||||
|
out.append(dict(num=m.group(1), lx=float(am.group(1)), ly=float(am.group(2)),
|
||||||
|
net=nm.group(1) if nm else None,
|
||||||
|
sx=float(sm.group(1)) if sm else 1, sy=float(sm.group(2)) if sm else 1))
|
||||||
|
return out
|
||||||
|
def pad_world(f, p):
|
||||||
|
dx,dy = rotpt(p['lx'], p['ly'], f['rot'])
|
||||||
|
return (f['x']+dx, f['y']+dy)
|
||||||
|
|
||||||
|
FP = parse_fps(src); FPO = parse_fps(orig)
|
||||||
|
|
||||||
|
# ---------------- 1) net rip: socket nets + /NRST ----------------
|
||||||
|
RIP_NETS = {'/BAT_SENSE','/PWR_CTRL','/GNSS_TX','/GNSS_RX','/5V_SENSE','/IGN_SENSE','/FAN_PWM',
|
||||||
|
'/EXT_LED','/NTC_TEMP','/ETH_INT','/ETH_CS','/ETH_SCK','/ETH_MISO','/ETH_MOSI','/ETH_RST',
|
||||||
|
'/CHRG_EN','/CHRG_STAT','/CHRG_FAULT','/BYP_CTRL','/USART1_TX','/USART1_RX','/I2C_SCL',
|
||||||
|
'/I2C_SDA','/SER_IRQ','/NRST'}
|
||||||
|
del_spans=[]; stats=collections.Counter()
|
||||||
|
for m in re.finditer(r'\(segment\b|\(via\b|\(arc\b', src):
|
||||||
|
a=m.start(); e=endof(src,a); blk=src[a:e]
|
||||||
|
nm=re.search(r'\(net "((?:[^"\\]|\\.)*)"\)', blk)
|
||||||
|
if nm and nm.group(1) in RIP_NETS:
|
||||||
|
del_spans.append((a,e)); stats['net-rip '+m.group(0)[1:]]+=1
|
||||||
|
|
||||||
|
# ---------------- 2) endpoint rip at old pad sites ----------------
|
||||||
|
old_sites=[]
|
||||||
|
for ref in ('J1','J2','P6','Y1','Y2','C83','C90','C91','C96','C102','R96','R97'):
|
||||||
|
f=FPO.get(ref)
|
||||||
|
if f:
|
||||||
|
for p in pads_of(f['blk']): old_sites.append(pad_world(f,p))
|
||||||
|
for ref in ('R85','R86','R87','R88','D11','L8','U12','C100','C101'):
|
||||||
|
f=FP.get(ref)
|
||||||
|
if f:
|
||||||
|
for p in pads_of(f['blk']): old_sites.append(pad_world(f,p))
|
||||||
|
def near_site(x,y,tol=0.15):
|
||||||
|
return any(abs(x-sx)<=tol and abs(y-sy)<=tol for sx,sy in old_sites)
|
||||||
|
ripped=set(a for a,e in del_spans)
|
||||||
|
for m in re.finditer(r'\(segment\b|\(via\b', src):
|
||||||
|
a=m.start()
|
||||||
|
if a in ripped: continue
|
||||||
|
e=endof(src,a); blk=src[a:e]
|
||||||
|
if m.group(0)=='(via':
|
||||||
|
am=re.search(r'\(at ([\-0-9.]+) ([\-0-9.]+)\)', blk)
|
||||||
|
pts=[(float(am.group(1)),float(am.group(2)))]
|
||||||
|
else:
|
||||||
|
pts=[]
|
||||||
|
sm=re.search(r'\(start ([\-0-9.]+) ([\-0-9.]+)\)', blk); em=re.search(r'\(end ([\-0-9.]+) ([\-0-9.]+)\)', blk)
|
||||||
|
if sm: pts.append((float(sm.group(1)),float(sm.group(2))))
|
||||||
|
if em: pts.append((float(em.group(1)),float(em.group(2))))
|
||||||
|
if any(near_site(x,y) for x,y in pts):
|
||||||
|
del_spans.append((a,e)); stats['endpoint-rip']+=1
|
||||||
|
|
||||||
|
# ---------------- 3) bay silk deletion + version text patches ----------------
|
||||||
|
text_patches=[]
|
||||||
|
BAY=(98,49,162,79)
|
||||||
|
for m in re.finditer(r'\(gr_(text|rect|line|poly|circle)\b', src):
|
||||||
|
a=m.start(); e=endof(src,a); blk=src[a:e]
|
||||||
|
if 'Silk' not in blk: continue
|
||||||
|
coords=[(float(mm.group(1)),float(mm.group(2))) for mm in
|
||||||
|
re.finditer(r'\((?:at|start|end|xy|center) ([\-0-9.]+) ([\-0-9.]+)', blk)]
|
||||||
|
if not coords: continue
|
||||||
|
inside=all(BAY[0]<x<BAY[2] and BAY[1]<y<BAY[3] for x,y in coords)
|
||||||
|
if m.group(1)=='text':
|
||||||
|
tm=re.match(r'\(gr_text\s+"((?:[^"\\]|\\.)*)"', blk)
|
||||||
|
if inside or (tm and 'BLACKPILL' in tm.group(1).upper()):
|
||||||
|
del_spans.append((a,e)); stats['silk-del']+=1
|
||||||
|
elif inside:
|
||||||
|
del_spans.append((a,e)); stats['silk-gfx-del']+=1
|
||||||
|
for old,new in [('EINARBoard 2.0','EINARBoard 3.0'), ('HBOX v4 - 2026-07','HBOX v5 - 2026-08')]:
|
||||||
|
i=src.find(f'"{old}')
|
||||||
|
if i>=0: text_patches.append((i+1, i+1+len(old), new))
|
||||||
|
|
||||||
|
# ---------------- 4) footprint moves ----------------
|
||||||
|
MOVES = {} # ref -> (x, y) new position (rot preserved)
|
||||||
|
# packed east row beside Q1/Q5 at y 63.9 (all rot preserved: R's are rot90, D11 rot90)
|
||||||
|
MOVES.update({'R88':(140.0,63.9), 'R87':(142.5,63.9), 'D11':(145.6,63.9),
|
||||||
|
'R85':(148.7,63.9), 'R86':(151.2,63.9)})
|
||||||
|
# buck cluster below C43 (C43 at 146.95,109.31; keep loop tight)
|
||||||
|
MOVES.update({'U12':(144.0,116.5), 'L8':(145.0,123.5), 'C100':(139.2,116.5), 'C101':(139.2,120.0)})
|
||||||
|
# J11 4.5mm north
|
||||||
|
MOVES['J11']=(71.11,87.5)
|
||||||
|
# LEDs + resistors south of J11
|
||||||
|
MOVES.update({'D17':(64.5,97.6), 'D18':(64.5,100.2), 'R102':(67.94,97.6), 'R103':(67.94,100.2)})
|
||||||
|
# SW2 beside H4 (bottom edge service row)
|
||||||
|
MOVES['SW2']=(84.0,134.3)
|
||||||
|
# U16 into freed bay + support ring
|
||||||
|
UX,UY=119.0,63.5
|
||||||
|
MOVES['U16']=(UX,UY)
|
||||||
|
MOVES.update({
|
||||||
|
'C105':(111.4,56.6), 'C106':(126.6,56.6), 'C107':(111.4,70.4), 'C108':(126.6,70.4),
|
||||||
|
'C110':(114.5,56.0), 'C111':(119.0,71.9), 'C104':(110.6,66.5), 'R99':(110.6,60.5),
|
||||||
|
'R104':(114.5,71.9), 'C109':(123.5,71.9), 'C112':(126.0,73.9), 'R98':(127.4,60.5),
|
||||||
|
'Y3':(133.0,66.8), 'C113':(129.4,70.2), 'C114':(133.0,70.2),
|
||||||
|
'Y4':(133.0,58.4), 'C115':(129.4,61.4), 'C116':(133.0,61.9),
|
||||||
|
'TP3':(108.0,52.0), 'TP4':(110.8,52.0), 'TP5':(113.6,52.0), 'TP6':(116.4,52.0), 'TP7':(119.2,52.0),
|
||||||
|
})
|
||||||
|
# LDO tight block in freed old-U16 zone (between J11 and new U16)
|
||||||
|
MOVES.update({'U17':(90.5,69.5), 'D12':(96.3,67.0), 'D13':(96.3,70.5),
|
||||||
|
'C117':(87.0,74.5), 'C118':(90.5,74.5)})
|
||||||
|
|
||||||
|
for ref,(nx,ny) in MOVES.items():
|
||||||
|
f=FP[ref]
|
||||||
|
del_spans.append(f['span'])
|
||||||
|
nb=re.sub(r'\(at [\-0-9. ]+\)',
|
||||||
|
f'(at {nx:g} {ny:g}{(" %g"%f["rot"]) if f["rot"] else ""})', f['blk'], count=1)
|
||||||
|
MOVES[ref]=(nx,ny,nb)
|
||||||
|
stats['moved']+=1
|
||||||
|
|
||||||
|
# ---------------- 5) MH7-12 reference text size ----------------
|
||||||
|
mh_patches=[]
|
||||||
|
for ref in ('MH7','MH8','MH9','MH10','MH11','MH12'):
|
||||||
|
f=FP[ref]
|
||||||
|
a,e=f['span']
|
||||||
|
blk=f['blk']
|
||||||
|
pm=re.search(r'\(property "Reference"\s+"'+ref+r'"', blk)
|
||||||
|
pe=endof(blk, pm.start())
|
||||||
|
ptxt=blk[pm.start():pe]
|
||||||
|
ptxt2=re.sub(r'\(size [0-9.]+ [0-9.]+\)', '(size 1 1)', ptxt)
|
||||||
|
if '(thickness' in ptxt2: ptxt2=re.sub(r'\(thickness [0-9.]+\)', '(thickness 0.15)', ptxt2)
|
||||||
|
else: ptxt2=ptxt2.replace('(size 1 1)', '(size 1 1)\n\t\t\t\t\t(thickness 0.15)')
|
||||||
|
nb=blk[:pm.start()]+ptxt2+blk[pe:]
|
||||||
|
del_spans.append(f['span']); MOVES[ref]=(f['x'],f['y'],nb); stats['mh-text']+=1
|
||||||
|
|
||||||
|
# ---------------- splice ----------------
|
||||||
|
new=src
|
||||||
|
ops=[(a,b,'') for a,b in del_spans]+[(a,b,t) for a,b,t in text_patches]
|
||||||
|
ops.sort(key=lambda o:-o[0])
|
||||||
|
ss=sorted([(a,b) for a,b,_ in ops])
|
||||||
|
for (a1,b1),(a2,b2) in zip(ss,ss[1:]):
|
||||||
|
assert b1<=a2, f'overlap {a1,b1} {a2,b2}'
|
||||||
|
for a,b,t in ops:
|
||||||
|
if t=='':
|
||||||
|
a0=a
|
||||||
|
while a0>0 and new[a0-1] in ' \t\n': a0-=1
|
||||||
|
new=new[:a0]+'\n\t'+new[b:]
|
||||||
|
else:
|
||||||
|
new=new[:a]+t+new[b:]
|
||||||
|
end=new.rfind(')')
|
||||||
|
blocks=[v[2] for v in MOVES.values()]
|
||||||
|
new=new[:end]+'\t'+'\n\t'.join(blocks)+'\n'+new[end:]
|
||||||
|
open(CUR,'w',encoding='utf-8').write(new)
|
||||||
|
print(f'WROTE {CUR}: {len(src)} -> {len(new)}; balance={new.count("(")==new.count(")")}')
|
||||||
|
for k,v in sorted(stats.items()): print(f' {k}: {v}')
|
||||||
597
scripts/2026-08-12_einarboard30_phaseB_gen_placement.py
Normal file
597
scripts/2026-08-12_einarboard30_phaseB_gen_placement.py
Normal file
@ -0,0 +1,597 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
EinarBoard 3.0 — Phase B generator: PCB placement for hbox-watchdog-v5.kicad_pcb
|
||||||
|
File-level edits per standing rule. Removes Blackpill sockets + tach parts, swaps P6 to
|
||||||
|
JST B2B 1x02, fabricates+places all Phase-A footprints (dims from KiCad v7 lib files,
|
||||||
|
syntax from same-board templates), moves Y1/Y2, adds Block-Q mounting holes, updates
|
||||||
|
net table + title date. Verifies: courtyard overlaps, pad-net consistency, board bounds.
|
||||||
|
"""
|
||||||
|
import re, sys, math, uuid, collections
|
||||||
|
from decimal import Decimal as D
|
||||||
|
|
||||||
|
PCB = sys.argv[1] if len(sys.argv) > 1 else 'hbox-watchdog-v5.kicad_pcb'
|
||||||
|
SCH = sys.argv[2] if len(sys.argv) > 2 else 'hbox-watchdog-v5.kicad_sch'
|
||||||
|
LIB = '/usr/share/kicad/footprints'
|
||||||
|
src = open(PCB, encoding='utf-8').read()
|
||||||
|
if '"U16"' in src:
|
||||||
|
print('ABORT: U16 already on board'); sys.exit(1)
|
||||||
|
|
||||||
|
def NU(): return str(uuid.uuid4())
|
||||||
|
def endof(s, start):
|
||||||
|
d = 0; ins = False; esc = False
|
||||||
|
for k in range(start, len(s)):
|
||||||
|
c = s[k]
|
||||||
|
if esc: esc = False; continue
|
||||||
|
if c == '\\': esc = True; continue
|
||||||
|
if c == '"': ins = not ins; continue
|
||||||
|
if not ins:
|
||||||
|
if c == '(': d += 1
|
||||||
|
elif c == ')':
|
||||||
|
d -= 1
|
||||||
|
if d == 0: return k + 1
|
||||||
|
return -1
|
||||||
|
|
||||||
|
# ---------------- board facts ----------------
|
||||||
|
X0, X1, Y0, Y1 = 60.19165, 215.19165, 40.3231, 140.3231
|
||||||
|
|
||||||
|
# ---------------- net table ----------------
|
||||||
|
nets = set()
|
||||||
|
for m in re.finditer(r'\(net "((?:[^"\\]|\\.)*)"\)', src):
|
||||||
|
nets.add(m.group(1))
|
||||||
|
NEW_NETS = ['DFU_VBUS','DFU_DP','DFU_DM','DFU_CC1','DFU_CC2','LDO_IN','BOOT0','BOOT1_STRAP',
|
||||||
|
'VCAP1','VDDA','HSE_IN','HSE_OUT','LSE_IN','LSE_OUT','SWDIO','SWCLK',
|
||||||
|
'LED_C13','LED_C13_A','LED_PWR_A']
|
||||||
|
def resolve(name):
|
||||||
|
if name in nets: return name
|
||||||
|
if '/'+name in nets: return '/'+name
|
||||||
|
return None
|
||||||
|
def N(name):
|
||||||
|
r = resolve(name)
|
||||||
|
return f'(net "{r if r else "/"+name}")' # new nets follow the local-label "/" convention
|
||||||
|
addnets = [n for n in NEW_NETS if resolve(n) is None]
|
||||||
|
for req in ['NRST','3V3','SYS5V','GND','ETH_INT','5V_FAN','FAN_RET']:
|
||||||
|
assert resolve(req), f'expected existing net {req}'
|
||||||
|
|
||||||
|
# ---------------- footprint blocks ----------------
|
||||||
|
fp_blocks = [] # (ref, at(x,y,rot), span, block)
|
||||||
|
for m in re.finditer(r'\(footprint\s+"([^"]+)"', src):
|
||||||
|
a = m.start(); e = endof(src, a); blk = src[a:e]
|
||||||
|
rm = re.search(r'\(property "Reference"\s+"([^"]+)"', blk)
|
||||||
|
am = re.search(r'\(at ([\-0-9.]+) ([\-0-9.]+)( [\-0-9.]+)?\)', blk)
|
||||||
|
if rm and am:
|
||||||
|
fp_blocks.append(dict(ref=rm.group(1), lib=m.group(1),
|
||||||
|
x=float(am.group(1)), y=float(am.group(2)),
|
||||||
|
rot=float((am.group(3) or '0')), span=(a, e), blk=blk))
|
||||||
|
def by_ref(r):
|
||||||
|
c = [f for f in fp_blocks if f['ref'] == r]
|
||||||
|
assert len(c) == 1, f'{r}: {len(c)}'
|
||||||
|
return c[0]
|
||||||
|
|
||||||
|
def pads_of(blk):
|
||||||
|
out = []
|
||||||
|
for m in re.finditer(r'\(pad\s+"([^"]*)"\s+(np_thru_hole|thru_hole|smd)\s+(\w+)', blk):
|
||||||
|
a = m.start(); e = endof(blk, a); p = blk[a:e]
|
||||||
|
am = re.search(r'\(at ([\-0-9.]+) ([\-0-9.]+)( [\-0-9.]+)?\)', p)
|
||||||
|
nm = re.search(r'\(net "((?:[^"\\]|\\.)*)"\)', p)
|
||||||
|
sm = re.search(r'\(size ([\-0-9.]+) ([\-0-9.]+)\)', p)
|
||||||
|
out.append(dict(num=m.group(1), kind=m.group(2), shape=m.group(3),
|
||||||
|
lx=float(am.group(1)), ly=float(am.group(2)),
|
||||||
|
rot=float((am.group(3) or '0')),
|
||||||
|
net=nm.group(1) if nm else None,
|
||||||
|
sx=float(sm.group(1)) if sm else 1, sy=float(sm.group(2)) if sm else 1,
|
||||||
|
span=(a, e), txt=p))
|
||||||
|
return out
|
||||||
|
|
||||||
|
def rotpt(lx, ly, deg):
|
||||||
|
r = math.radians(deg % 360)
|
||||||
|
return (lx*math.cos(r) - ly*math.sin(r), lx*math.sin(r) + ly*math.cos(r))
|
||||||
|
|
||||||
|
# validate rotation convention with P12 (rot 90 B2B) vs its connected tracks
|
||||||
|
P12 = by_ref('P12')
|
||||||
|
p12p = pads_of(P12['blk'])
|
||||||
|
cands = {}
|
||||||
|
for sgn in (1, -1):
|
||||||
|
pts = []
|
||||||
|
for p in p12p:
|
||||||
|
dx, dy = rotpt(p['lx'], p['ly'], sgn*P12['rot'])
|
||||||
|
pts.append((round(P12['x']+dx, 3), round(P12['y']+dy, 3)))
|
||||||
|
cands[sgn] = pts
|
||||||
|
seg_pts = set()
|
||||||
|
for m in re.finditer(r'\(segment\s*\(start ([\-0-9.]+) ([\-0-9.]+)\)\s*\(end ([\-0-9.]+) ([\-0-9.]+)\)', src):
|
||||||
|
seg_pts.add((round(float(m.group(1)), 3), round(float(m.group(2)), 3)))
|
||||||
|
seg_pts.add((round(float(m.group(3)), 3), round(float(m.group(4)), 3)))
|
||||||
|
score = {1: 0, -1: 0}
|
||||||
|
segnet = collections.defaultdict(set)
|
||||||
|
for m in re.finditer(r'\(segment\s*\(start ([\-0-9.]+) ([\-0-9.]+)\)\s*\(end ([\-0-9.]+) ([\-0-9.]+)\)(.*?)\(net "((?:[^"\\]|\\.)*)"\)', src, re.S):
|
||||||
|
nn = m.group(6)
|
||||||
|
segnet[nn].add((round(float(m.group(1)), 2), round(float(m.group(2)), 2)))
|
||||||
|
segnet[nn].add((round(float(m.group(3)), 2), round(float(m.group(4)), 2)))
|
||||||
|
for f in fp_blocks:
|
||||||
|
if not f['rot'] % 360: continue
|
||||||
|
for p in pads_of(f['blk']):
|
||||||
|
if not p['net'] or p['net'] not in segnet: continue
|
||||||
|
for sgn in (1, -1):
|
||||||
|
dx, dy = rotpt(p['lx'], p['ly'], sgn*f['rot'])
|
||||||
|
pt = (round(f['x']+dx, 2), round(f['y']+dy, 2))
|
||||||
|
if pt in segnet[p['net']]: score[sgn] += 1
|
||||||
|
ROTSGN = 1 if score[1] >= score[-1] else -1
|
||||||
|
print(f'rotation convention: sign={ROTSGN} (net-aware pad-track hits {score})')
|
||||||
|
def pad_world(f, p):
|
||||||
|
dx, dy = rotpt(p['lx'], p['ly'], ROTSGN*f['rot'])
|
||||||
|
return (f['x']+dx, f['y']+dy)
|
||||||
|
|
||||||
|
# ---------------- courtyard/occupancy map (AABB per footprint from pads + courtyard rects) ----------------
|
||||||
|
def fp_bbox(f):
|
||||||
|
xs = []; ys = []
|
||||||
|
for p in pads_of(f['blk']):
|
||||||
|
wx, wy = pad_world(f, p)
|
||||||
|
xs += [wx - p['sx']/2, wx + p['sx']/2]; ys += [wy - p['sy']/2, wy + p['sy']/2]
|
||||||
|
for m in re.finditer(r'\(fp_(?:rect|line|circle|poly)\b', f['blk']):
|
||||||
|
e = endof(f['blk'], m.start()); g = f['blk'][m.start():e]
|
||||||
|
if '"F.CrtYd"' not in g and '"B.CrtYd"' not in g: continue
|
||||||
|
for mm in re.finditer(r'\((?:start|end|center|xy) ([\-0-9.]+) ([\-0-9.]+)\)', g):
|
||||||
|
dx, dy = rotpt(float(mm.group(1)), float(mm.group(2)), ROTSGN*f['rot'])
|
||||||
|
xs.append(f['x']+dx); ys.append(f['y']+dy)
|
||||||
|
if not xs: return None
|
||||||
|
return (min(xs), min(ys), max(xs), max(ys))
|
||||||
|
|
||||||
|
REMOVE = {'J1', 'J2', 'Rts1', 'Rtp1', 'P6'}
|
||||||
|
occ = []
|
||||||
|
for f in fp_blocks:
|
||||||
|
if f['ref'] in REMOVE or f['ref'] in ('Y1', 'Y2'): continue
|
||||||
|
if f['ref'] == 'MOD1':
|
||||||
|
# header rows + USB/barrel-corner overhang keepout only; under-shield SMD is allowed
|
||||||
|
pws = [pad_world(f, p) for p in pads_of(f['blk'])]
|
||||||
|
ys = sorted({round(w[1], 1) for w in pws})
|
||||||
|
xs = [w[0] for w in pws]
|
||||||
|
rowA, rowB = min(ys), max(ys)
|
||||||
|
occ.append(('MOD1-rowA', (min(xs)-1, rowA-1, max(xs)+1, rowA+1)))
|
||||||
|
occ.append(('MOD1-rowB', (min(xs)-1, rowB-1, max(xs)+1, rowB+1)))
|
||||||
|
occ.append(('MOD1-ovh', (min(xs)-10, rowB-18.5, min(xs)-0.5, rowB-4.5)))
|
||||||
|
continue
|
||||||
|
bb = fp_bbox(f)
|
||||||
|
if bb: occ.append((f['ref'], bb))
|
||||||
|
def colliders(bb, margin=0.3):
|
||||||
|
x0, y0, x1, y1 = bb
|
||||||
|
hits = []
|
||||||
|
if x0 < X0+0.8 or y0 < Y0+0.8 or x1 > X1-0.8 or y1 > Y1-0.8: hits.append('BOARD-EDGE')
|
||||||
|
for ref, (a0, b0, a1, b1) in occ:
|
||||||
|
if not (x1+margin < a0 or a1+margin < x0 or y1+margin < b0 or b1+margin < y0):
|
||||||
|
hits.append(ref)
|
||||||
|
return hits
|
||||||
|
def clear(bb, margin=0.3):
|
||||||
|
return not colliders(bb, margin)
|
||||||
|
def place(w, h, ax, ay, fixed=False, label=''):
|
||||||
|
"""find position for a w×h courtyard near anchor; returns center"""
|
||||||
|
if fixed:
|
||||||
|
bb = (ax-w/2, ay-h/2, ax+w/2, ay+h/2)
|
||||||
|
assert clear(bb), f'FIXED position blocked: {label} at {ax},{ay}'
|
||||||
|
occ.append((label, bb)); return (ax, ay)
|
||||||
|
step = 0.635
|
||||||
|
for ring in range(0, 40):
|
||||||
|
for dx in range(-ring, ring+1):
|
||||||
|
for dy in range(-ring, ring+1):
|
||||||
|
if max(abs(dx), abs(dy)) != ring: continue
|
||||||
|
cx, cy = ax + dx*step, ay + dy*step
|
||||||
|
bb = (cx-w/2, cy-h/2, cx+w/2, cy+h/2)
|
||||||
|
if clear(bb):
|
||||||
|
occ.append((label, bb)); return (round(cx, 2), round(cy, 2))
|
||||||
|
raise RuntimeError(f'no space for {label} near {ax},{ay}')
|
||||||
|
|
||||||
|
# ---------------- sch symbol uuid map (for footprint path linkage) ----------------
|
||||||
|
schsrc = open(SCH, encoding='utf-8').read()
|
||||||
|
sch_uuid = {}
|
||||||
|
for m in re.finditer(r'\(symbol\b', schsrc):
|
||||||
|
e = endof(schsrc, m.start()); b = schsrc[m.start():e]
|
||||||
|
um = re.search(r'\(uuid "([^"]+)"\)', b)
|
||||||
|
rm = re.search(r'\(property "Reference"\s+"([^"]+)"', b)
|
||||||
|
if um and rm and rm.group(1) not in sch_uuid:
|
||||||
|
sch_uuid[rm.group(1)] = um.group(1)
|
||||||
|
|
||||||
|
# ---------------- v7 lib dims ----------------
|
||||||
|
def lib_dims(path):
|
||||||
|
s = open(path).read()
|
||||||
|
pads = []
|
||||||
|
for m in re.finditer(r'\(pad\s+"?([^"\s]*)"?\s+(np_thru_hole|thru_hole|smd)\s+(\w+)', s):
|
||||||
|
e = endof(s, m.start()); p = s[m.start():e]
|
||||||
|
am = re.search(r'\(at ([\-0-9.]+) ([\-0-9.]+)( [\-0-9.]+)?\)', p)
|
||||||
|
sm = re.search(r'\(size ([\-0-9.]+) ([\-0-9.]+)\)', p)
|
||||||
|
dm = re.search(r'\(drill ([\-0-9.]+)', p)
|
||||||
|
rr = re.search(r'\(roundrect_rratio ([\-0-9.]+)\)', p)
|
||||||
|
lay = re.search(r'\(layers ([^)]+)\)', p)
|
||||||
|
pads.append(dict(num=m.group(1).strip('"'), kind=m.group(2), shape=m.group(3),
|
||||||
|
x=float(am.group(1)), y=float(am.group(2)), rot=float((am.group(3) or '0')),
|
||||||
|
sx=float(sm.group(1)), sy=float(sm.group(2)),
|
||||||
|
drill=float(dm.group(1)) if dm else None,
|
||||||
|
rratio=rr.group(1) if rr else None, layers=lay.group(1)))
|
||||||
|
cxs = []; cys = []
|
||||||
|
for m in re.finditer(r'\(fp_(?:rect|line|circle)\b', s):
|
||||||
|
e = endof(s, m.start()); g = s[m.start():e]
|
||||||
|
if 'CrtYd' not in g: continue
|
||||||
|
for mm in re.finditer(r'\((?:start|end|center) ([\-0-9.]+) ([\-0-9.]+)\)', g):
|
||||||
|
cxs.append(float(mm.group(1))); cys.append(float(mm.group(2)))
|
||||||
|
crt = (min(cxs), min(cys), max(cxs), max(cys)) if cxs else None
|
||||||
|
return dict(pads=pads, crt=crt)
|
||||||
|
|
||||||
|
LQFP64 = lib_dims(f'{LIB}/Package_QFP.pretty/LQFP-64_10x10mm_P0.5mm.kicad_mod')
|
||||||
|
SOT223 = lib_dims(f'{LIB}/Package_TO_SOT_SMD.pretty/SOT-223-3_TabPin2.kicad_mod')
|
||||||
|
SOD323 = lib_dims(f'{LIB}/Diode_SMD.pretty/D_SOD-323.kicad_mod')
|
||||||
|
X3215 = lib_dims(f'{LIB}/Crystal.pretty/Crystal_SMD_3215-2Pin_3.2x1.5mm.kicad_mod')
|
||||||
|
LED063 = lib_dims(f'{LIB}/LED_SMD.pretty/LED_0603_1608Metric.kicad_mod')
|
||||||
|
UNOH = lib_dims(f'{LIB}/Module.pretty/Arduino_UNO_R3_WithMountingHoles.kicad_mod')
|
||||||
|
HOLES_LOCAL = [(p['x'], p['y']) for p in UNOH['pads'] if p['kind'] == 'np_thru_hole']
|
||||||
|
assert len(HOLES_LOCAL) == 4
|
||||||
|
|
||||||
|
# MOD1 transform fit: board pad locals vs library pad locals (plain UNO, pad1..32)
|
||||||
|
UNO = lib_dims(f'{LIB}/Module.pretty/Arduino_UNO_R3.kicad_mod')
|
||||||
|
MOD1 = by_ref('MOD1')
|
||||||
|
bp = {p['num']: (p['lx'], p['ly']) for p in pads_of(MOD1['blk'])}
|
||||||
|
lp = {p['num']: (p['x'], p['y']) for p in UNO['pads']}
|
||||||
|
common = [k for k in ('1', '2', '11', '20', '32') if k in bp and k in lp]
|
||||||
|
assert len(common) >= 3, f'MOD1 pads for fit: {common}'
|
||||||
|
# solve: board_local = (sx * lib_x, sy * lib_y) with sx,sy in {+1,-1} + offset
|
||||||
|
fits = []
|
||||||
|
for sx in (1, -1):
|
||||||
|
for sy in (1, -1):
|
||||||
|
offs = {(round(bp[k][0]-sx*lp[k][0], 3), round(bp[k][1]-sy*lp[k][1], 3)) for k in common}
|
||||||
|
if len(offs) == 1: fits.append((sx, sy, offs.pop()))
|
||||||
|
assert len(fits) == 1, f'MOD1 fit ambiguous: {fits}'
|
||||||
|
MSX, MSY, (MOX, MOY) = fits[0]
|
||||||
|
print(f'MOD1 mirror fit: sx={MSX} sy={MSY} off=({MOX},{MOY})')
|
||||||
|
shield_holes = []
|
||||||
|
for hx, hy in HOLES_LOCAL:
|
||||||
|
blx, bly = MSX*hx + MOX, MSY*hy + MOY
|
||||||
|
dx, dy = rotpt(blx, bly, ROTSGN*MOD1['rot'])
|
||||||
|
shield_holes.append((round(MOD1['x']+dx, 3), round(MOD1['y']+dy, 3)))
|
||||||
|
print('shield bolt holes (world):', shield_holes)
|
||||||
|
|
||||||
|
# ---------------- templates from board ----------------
|
||||||
|
T_R = by_ref('R20'); T_C = None; T_C0805 = None
|
||||||
|
for f in fp_blocks:
|
||||||
|
if 'C_0603' in f['lib'] and T_C is None: T_C = f
|
||||||
|
if 'C_0805' in f['lib'] and T_C0805 is None: T_C0805 = f
|
||||||
|
assert T_C, 'no 0603 C template'
|
||||||
|
T_SMA = by_ref('D2'); T_TP = by_ref('TP1'); T_SW = by_ref('SW1'); T_MH = by_ref('MH2')
|
||||||
|
T_B2B = by_ref('P12'); T_USB = by_ref('J9'); T_LQFP = by_ref('U11'); T_HC49 = by_ref('Y1')
|
||||||
|
P6old = by_ref('P6')
|
||||||
|
|
||||||
|
def path_of(blk):
|
||||||
|
m = re.search(r'\(path "([^"]+)"\)', blk)
|
||||||
|
return m.group(1) if m else None
|
||||||
|
|
||||||
|
def retarget(tmpl_f, ref, value, libname, x, y, rot, padnets, fpname=None):
|
||||||
|
"""clone a board template block: new ref/value/lib/at/uuids/nets/path"""
|
||||||
|
t = tmpl_f['blk']
|
||||||
|
t = re.sub(r'\(footprint\s+"[^"]+"', f'(footprint "{libname}"', t, count=1)
|
||||||
|
t = re.sub(r'\(at [\-0-9. ]+\)', f'(at {x:g} {y:g}{(" %g"%rot) if rot else ""})', t, count=1)
|
||||||
|
t = re.sub(r'\(property "Reference"\s+"[^"]+"', f'(property "Reference" "{ref}"', t, count=1)
|
||||||
|
t = re.sub(r'\(property "Value"\s+"[^"]*"', f'(property "Value" "{value}"', t, count=1)
|
||||||
|
t = re.sub(r'\(property "Footprint"\s+"[^"]*"', f'(property "Footprint" "{libname}"', t, count=1)
|
||||||
|
t = re.sub(r'\(uuid "[^"]*"\)', lambda m: f'(uuid "{NU()}")', t)
|
||||||
|
su = sch_uuid.get(ref)
|
||||||
|
if su: t = re.sub(r'\(path "[^"]*"\)', f'(path "/{su}")', t, count=1)
|
||||||
|
# pad rotation update: template rot -> new rot on every pad angle token + nets
|
||||||
|
dr = rot - tmpl_f['rot']
|
||||||
|
def fixpad(m):
|
||||||
|
a = m.start(); e = endof(t, a); p = t[a:e]
|
||||||
|
num = re.match(r'\(pad\s+"([^"]*)"', p).group(1)
|
||||||
|
if dr:
|
||||||
|
def bump(mm):
|
||||||
|
ang = (float(mm.group(3) or 0) + dr) % 360
|
||||||
|
return f'(at {mm.group(1)} {mm.group(2)}{(" %g"%ang) if ang else ""})'
|
||||||
|
p2 = re.sub(r'\(at ([\-0-9.]+) ([\-0-9.]+)(?: ([\-0-9.]+))?\)', bump, p, count=1)
|
||||||
|
else: p2 = p
|
||||||
|
if num in padnets:
|
||||||
|
if '(net ' in p2: p2 = re.sub(r'\(net "(?:[^"\\]|\\.)*"\)', N(padnets[num]), p2)
|
||||||
|
else: p2 = p2[:-1] + '\n\t\t' + N(padnets[num]) + '\n\t)'
|
||||||
|
else:
|
||||||
|
p2 = re.sub(r'\s*\(net "(?:[^"\\]|\\.)*"\)', '', p2)
|
||||||
|
return p2
|
||||||
|
out = []; i = 0
|
||||||
|
for m in list(re.finditer(r'\(pad\s+"[^"]*"', t)):
|
||||||
|
a = m.start()
|
||||||
|
if a < i: continue
|
||||||
|
e = endof(t, a)
|
||||||
|
out.append(t[i:a]);
|
||||||
|
# rebuild pad via fixpad logic inline
|
||||||
|
p = t[a:e]
|
||||||
|
num = re.match(r'\(pad\s+"([^"]*)"', p).group(1)
|
||||||
|
if dr:
|
||||||
|
def bump(mm):
|
||||||
|
ang = (float(mm.group(3) or 0) + dr) % 360
|
||||||
|
return f'(at {mm.group(1)} {mm.group(2)}{(" %g"%ang) if ang else ""})'
|
||||||
|
p = re.sub(r'\(at ([\-0-9.]+) ([\-0-9.]+)(?: ([\-0-9.]+))?\)', bump, p, count=1)
|
||||||
|
if num in padnets:
|
||||||
|
if '(net ' in p: p = re.sub(r'\(net "(?:[^"\\]|\\.)*"\)', N(padnets[num]), p)
|
||||||
|
else: p = p[:-1] + '\n\t\t\t' + N(padnets[num]) + '\n\t\t)'
|
||||||
|
else:
|
||||||
|
p = re.sub(r'\s*\(net "(?:[^"\\]|\\.)*"\)', '', p)
|
||||||
|
out.append(p); i = e
|
||||||
|
out.append(t[i:])
|
||||||
|
return ''.join(out)
|
||||||
|
|
||||||
|
def build_generic(ref, value, libname, x, y, rot, dims, padnets, attr='smd', tmpl=None):
|
||||||
|
"""fabricate a footprint from v7 dims using a same-class board template for syntax"""
|
||||||
|
tmpl = tmpl or (T_C if attr == 'smd' else T_B2B)
|
||||||
|
t = tmpl['blk']
|
||||||
|
head = re.match(r'(\(footprint\s+"[^"]+"\s*(?:\(version[^)]*\))?\s*(?:\(generator[^)]*\))?\s*(?:\(generator_version[^)]*\))?\s*\(layer "F\.Cu"\))', t)
|
||||||
|
# properties section: reuse template's property blocks (Reference/Value/Footprint/Datasheet/Description) + attr + path
|
||||||
|
props = []
|
||||||
|
for pm in re.finditer(r'\(property "([^"]+)"\s+"[^"]*"', t):
|
||||||
|
a = pm.start(); e = endof(t, a); props.append((pm.group(1), t[a:e]))
|
||||||
|
prop_txt = []
|
||||||
|
for name, ptxt in props:
|
||||||
|
if name == 'Reference': ptxt = re.sub(r'"Reference"\s+"[^"]+"', f'"Reference" "{ref}"', ptxt, count=1)
|
||||||
|
elif name == 'Value': ptxt = re.sub(r'"Value"\s+"[^"]*"', f'"Value" "{value}"', ptxt, count=1)
|
||||||
|
elif name == 'Footprint': ptxt = re.sub(r'"Footprint"\s+"[^"]*"', f'"Footprint" "{libname}"', ptxt, count=1)
|
||||||
|
ptxt = re.sub(r'\(uuid "[^"]*"\)', lambda m: f'(uuid "{NU()}")', ptxt)
|
||||||
|
prop_txt.append(ptxt)
|
||||||
|
attrm = re.search(r'\(attr [^)]*\)', t)
|
||||||
|
attr_txt = attrm.group(0) if attrm else f'(attr {attr})'
|
||||||
|
if attr == 'smd' and 'smd' not in attr_txt: attr_txt = '(attr smd)'
|
||||||
|
su = sch_uuid.get(ref)
|
||||||
|
path_txt = f'(path "/{su}")' if su else ''
|
||||||
|
sheet = re.search(r'\(sheetfile "[^"]*"\)', t)
|
||||||
|
sheet_txt = (re.search(r'\(sheetname "[^"]*"\)', t).group(0) + '\n\t\t' + sheet.group(0)) if sheet else ''
|
||||||
|
pads = []
|
||||||
|
for p in dims['pads']:
|
||||||
|
ang = (p['rot'] + rot) % 360
|
||||||
|
angtxt = f' {ang:g}' if ang else ''
|
||||||
|
drill = f'\n\t\t\t(drill {p["drill"]:g})' if p['drill'] else ''
|
||||||
|
rr = f'\n\t\t\t(roundrect_rratio {p["rratio"]})' if p['rratio'] else ''
|
||||||
|
nettxt = f'\n\t\t\t{N(padnets[p["num"]])}' if p['num'] in padnets else ''
|
||||||
|
layers = p['layers'].replace('*.Cu *.Mask', '"*.Cu" "*.Mask"') if '"' not in p['layers'] else p['layers']
|
||||||
|
pads.append(f'''\t\t(pad "{p['num']}" {p['kind']} {p['shape']}
|
||||||
|
\t\t\t(at {p['x']:g} {p['y']:g}{angtxt})
|
||||||
|
\t\t\t(size {p['sx']:g} {p['sy']:g}){drill}
|
||||||
|
\t\t\t(layers {layers}){rr}{nettxt}
|
||||||
|
\t\t\t(uuid "{NU()}")
|
||||||
|
\t\t)''')
|
||||||
|
crt = dims['crt']
|
||||||
|
crt_txt = ''
|
||||||
|
if crt:
|
||||||
|
crt_txt = f'''\t\t(fp_rect
|
||||||
|
\t\t\t(start {crt[0]:g} {crt[1]:g})
|
||||||
|
\t\t\t(end {crt[2]:g} {crt[3]:g})
|
||||||
|
\t\t\t(stroke
|
||||||
|
\t\t\t\t(width 0.05)
|
||||||
|
\t\t\t\t(type default)
|
||||||
|
\t\t\t)
|
||||||
|
\t\t\t(fill no)
|
||||||
|
\t\t\t(layer "F.CrtYd")
|
||||||
|
\t\t\t(uuid "{NU()}")
|
||||||
|
\t\t)'''
|
||||||
|
nl = '\n\t'
|
||||||
|
return f'''(footprint "{libname}"
|
||||||
|
\t\t(layer "F.Cu")
|
||||||
|
\t\t(uuid "{NU()}")
|
||||||
|
\t\t(at {x:g} {y:g}{(" %g"%rot) if rot else ""})
|
||||||
|
\t\t{nl.join(prop_txt)}
|
||||||
|
\t\t{path_txt}
|
||||||
|
\t\t{sheet_txt}
|
||||||
|
\t\t{attr_txt}
|
||||||
|
{crt_txt}
|
||||||
|
{chr(10).join(pads)}
|
||||||
|
\t)'''
|
||||||
|
|
||||||
|
INS = []
|
||||||
|
report = collections.defaultdict(list)
|
||||||
|
|
||||||
|
# ---------------- deletions ----------------
|
||||||
|
del_spans = [by_ref(r)['span'] for r in ('J1', 'J2', 'Rts1', 'Rtp1', 'P6')]
|
||||||
|
report['removed'] = ['J1', 'J2', 'Rts1', 'Rtp1', 'P6(1x04)']
|
||||||
|
|
||||||
|
# ---------------- P6 swap (B2B clone at old position) ----------------
|
||||||
|
p6nets = {p['num']: p['net'] for p in pads_of(P6old['blk']) if p['net']}
|
||||||
|
INS.append(retarget(T_B2B, 'P6', 'FAN 2-pin', 'Connector_JST:JST_XH_B2B-XH-A_1x02_P2.50mm_Vertical',
|
||||||
|
P6old['x'], P6old['y'], P6old['rot'],
|
||||||
|
{'1': p6nets.get('1', '5V_FAN'), '2': p6nets.get('2', 'FAN_RET')}))
|
||||||
|
b = fp_bbox(dict(blk=INS[-1], x=P6old['x'], y=P6old['y'], rot=P6old['rot']))
|
||||||
|
occ.append(('P6new', b))
|
||||||
|
report['placed'].append(('P6', P6old['x'], P6old['y'], 'B2B swap in place'))
|
||||||
|
|
||||||
|
# ---------------- relocate W5500-era passives out of the U16 zone ----------------
|
||||||
|
RELOC = ['C102', 'C90', 'C91', 'C96', 'R96', 'R97']
|
||||||
|
occ[:] = [(r, bb) for r, bb in occ if r not in RELOC]
|
||||||
|
# ---------------- U16 ----------------
|
||||||
|
w = LQFP64['crt'][2]-LQFP64['crt'][0]; h = LQFP64['crt'][3]-LQFP64['crt'][1]
|
||||||
|
ux, uy = place(w+0.4, h+0.4, 94.0, 71.0, fixed=True, label='U16')
|
||||||
|
for rref in RELOC:
|
||||||
|
rf = by_ref(rref)
|
||||||
|
rbb = fp_bbox(rf); rw, rh = rbb[2]-rbb[0], rbb[3]-rbb[1]
|
||||||
|
nx, ny = place(rw+0.2, rh+0.2, 96.0, 57.0, label=rref)
|
||||||
|
del_spans.append(rf['span'])
|
||||||
|
INS.append(re.sub(r'\(at [\-0-9. ]+\)', f'(at {nx:g} {ny:g}{(" %g"%rf["rot"]) if rf["rot"] else ""})', rf['blk'], count=1))
|
||||||
|
report['placed'].append((rref, nx, ny, 'relocated (was in U16 zone)'))
|
||||||
|
MCU_NETS = {'1':'3V3','2':'LED_C13','3':'LSE_IN','4':'LSE_OUT','5':'HSE_IN','6':'HSE_OUT',
|
||||||
|
'7':'NRST','8':'ETH_INT','12':'GND','13':'VDDA','14':'BAT_SENSE','15':'PWR_CTRL','16':'GNSS_TX',
|
||||||
|
'17':'GNSS_RX','18':'GND','19':'3V3','20':'5V_SENSE','21':'IGN_SENSE','22':'FAN_PWM','26':'EXT_LED',
|
||||||
|
'27':'NTC_TEMP','28':'BOOT1_STRAP','30':'VCAP1','31':'GND','32':'3V3','33':'ETH_CS','34':'ETH_SCK',
|
||||||
|
'35':'ETH_MISO','36':'ETH_MOSI','41':'CHRG_EN','42':'USART1_TX','43':'USART1_RX','44':'DFU_DM',
|
||||||
|
'45':'DFU_DP','46':'SWDIO','47':'GND','48':'3V3','49':'SWCLK','50':'ETH_RST','55':'CHRG_STAT',
|
||||||
|
'56':'CHRG_FAULT','57':'BYP_CTRL','58':'I2C_SCL','59':'I2C_SDA','60':'BOOT0','61':'SER_IRQ',
|
||||||
|
'63':'GND','64':'3V3'}
|
||||||
|
for extra in ['BAT_SENSE','PWR_CTRL','GNSS_TX','GNSS_RX','5V_SENSE','IGN_SENSE','FAN_PWM','EXT_LED',
|
||||||
|
'NTC_TEMP','ETH_CS','ETH_SCK','ETH_MISO','ETH_MOSI','CHRG_EN','USART1_TX','USART1_RX',
|
||||||
|
'SER_IRQ','CHRG_STAT','CHRG_FAULT','BYP_CTRL','I2C_SCL','I2C_SDA','ETH_RST']:
|
||||||
|
assert resolve(extra), f'net {extra} not in pcb'
|
||||||
|
INS.append(build_generic('U16', 'STM32F411RET6', 'Package_QFP:LQFP-64_10x10mm_P0.5mm',
|
||||||
|
ux, uy, 180, LQFP64, MCU_NETS, tmpl=T_LQFP))
|
||||||
|
report['placed'].append(('U16', ux, uy, 'rot180'))
|
||||||
|
|
||||||
|
def small(ref, value, lib, dims, n1, n2, ax, ay, tmpl=None, rot=0):
|
||||||
|
if dims and dims['crt']:
|
||||||
|
ww = dims['crt'][2]-dims['crt'][0]; hh = dims['crt'][3]-dims['crt'][1]
|
||||||
|
elif tmpl is not None:
|
||||||
|
tb = fp_bbox(dict(blk=tmpl['blk'], x=0, y=0, rot=tmpl['rot']))
|
||||||
|
ww, hh = tb[2]-tb[0]+0.4, tb[3]-tb[1]+0.4
|
||||||
|
else:
|
||||||
|
ww, hh = 2.4, 1.4
|
||||||
|
if rot in (90, 270): ww, hh = hh, ww
|
||||||
|
cx, cy = place(ww+0.2, hh+0.2, ax, ay, label=ref)
|
||||||
|
padnets = {'1': n1, '2': n2}
|
||||||
|
if dims: INS.append(build_generic(ref, value, lib, cx, cy, rot, dims, padnets, tmpl=tmpl))
|
||||||
|
else: INS.append(retarget(tmpl, ref, value, lib, cx, cy, rot, padnets))
|
||||||
|
report['placed'].append((ref, cx, cy, value))
|
||||||
|
return cx, cy
|
||||||
|
|
||||||
|
R_LIB = 'Resistor_SMD:R_0603_1608Metric'; C_LIB = 'Capacitor_SMD:C_0603_1608Metric'
|
||||||
|
# clone 0603 R/C via retarget (same lib) — dims=None path
|
||||||
|
def r0603(ref, val, n1, n2, ax, ay): return small(ref, val, R_LIB, None, n1, n2, ax, ay, tmpl=T_R)
|
||||||
|
def c0603(ref, val, n1, n2, ax, ay): return small(ref, val, C_LIB, None, n1, n2, ax, ay, tmpl=T_C)
|
||||||
|
|
||||||
|
# decoupling ring around U16
|
||||||
|
c0603('C105', '100nF', '3V3', 'GND', ux-7.5, uy-7.5)
|
||||||
|
c0603('C106', '100nF', '3V3', 'GND', ux+7.5, uy-7.5)
|
||||||
|
c0603('C107', '100nF', '3V3', 'GND', ux-7.5, uy+7.5)
|
||||||
|
c0603('C108', '100nF', '3V3', 'GND', ux+7.5, uy+7.5)
|
||||||
|
c0603('C110', '4.7uF', '3V3', 'GND', ux, uy-8.2)
|
||||||
|
c0603('C111', '4.7uF', 'VCAP1', 'GND', ux, uy+8.2)
|
||||||
|
c0603('C104', '100nF', 'NRST', 'GND', ux-8.2, uy-5)
|
||||||
|
r0603('R99', '10k', 'BOOT1_STRAP', 'GND', ux-8.2, uy+3)
|
||||||
|
# VDDA filter south
|
||||||
|
r0603('R104', '10R', '3V3', 'VDDA', ux-3, uy+8.9)
|
||||||
|
c0603('C109', '100nF', 'VDDA', 'GND', ux+3, uy+8.9)
|
||||||
|
c0603('C112', '1uF', 'VDDA', 'GND', ux+5.8, uy+8.9)
|
||||||
|
# crystals east of U16
|
||||||
|
small('Y3', '25MHz', T_HC49['lib'], None, 'HSE_IN', 'HSE_OUT', ux+11, uy+3, tmpl=T_HC49)
|
||||||
|
c0603('C113', '15pF', 'HSE_IN', 'GND', ux+11, uy+6.5)
|
||||||
|
c0603('C114', '15pF', 'HSE_OUT', 'GND', ux+14, uy+6.5)
|
||||||
|
small('Y4', '32.768kHz', 'Crystal:Crystal_SMD_3215-2Pin_3.2x1.5mm', X3215, 'LSE_IN', 'LSE_OUT', ux+11, uy-3)
|
||||||
|
c0603('C115', '12pF', 'LSE_IN', 'GND', ux+14, uy-3)
|
||||||
|
c0603('C116', '12pF', 'LSE_OUT', 'GND', ux+14, uy-0.5)
|
||||||
|
# BOOT0 pulldown near MCU
|
||||||
|
r0603('R98', '10k', 'BOOT0', 'GND', ux+8.2, uy+3)
|
||||||
|
|
||||||
|
# J11 USB-C at left edge (fixed) — clone J9, rot per convention: mouth (-x)
|
||||||
|
for rref in ['C83']:
|
||||||
|
rf = by_ref(rref)
|
||||||
|
occ[:] = [(r, bb) for r, bb in occ if r != rref]
|
||||||
|
rbb = fp_bbox(rf); rw, rh = rbb[2]-rbb[0], rbb[3]-rbb[1]
|
||||||
|
nx, ny = place(rw+0.2, rh+0.2, 79.0, 86.0, label=rref)
|
||||||
|
del_spans.append(rf['span'])
|
||||||
|
INS.append(re.sub(r'\(at [\-0-9. ]+\)', f'(at {nx:g} {ny:g}{(" %g"%rf["rot"]) if rf["rot"] else ""})', rf['blk'], count=1))
|
||||||
|
report['placed'].append((rref, nx, ny, 'relocated (was in J11 zone)'))
|
||||||
|
mouth_rot = 90 if ROTSGN == 1 else 270
|
||||||
|
jx, jy = 71.11, 92.0
|
||||||
|
jblk = retarget(T_USB, 'J11', 'USB-C DFU', T_USB['lib'], jx, jy, mouth_rot,
|
||||||
|
{'A1':'GND','B1':'GND','A12':'GND','B12':'GND',
|
||||||
|
'A4':'DFU_VBUS','A9':'DFU_VBUS','B4':'DFU_VBUS','B9':'DFU_VBUS',
|
||||||
|
'A5':'DFU_CC1','B5':'DFU_CC2','A6':'DFU_DP','B6':'DFU_DP',
|
||||||
|
'A7':'DFU_DM','B7':'DFU_DM','A8':'','B8':'','SH':'GND'})
|
||||||
|
bb = fp_bbox(dict(blk=jblk, x=jx, y=jy, rot=mouth_rot))
|
||||||
|
assert clear(bb, 0.25), f'J11 blocked at {bb} by {colliders(bb, 0.25)}'
|
||||||
|
occ.append(('J11', bb)); INS.append(jblk)
|
||||||
|
report['placed'].append(('J11', jx, jy, f'rot{mouth_rot} mouth-west'))
|
||||||
|
# CC + TVS east of J11
|
||||||
|
r0603('R100', '5.1k', 'DFU_CC1', 'GND', 79.5, 89)
|
||||||
|
r0603('R101', '5.1k', 'DFU_CC2', 'GND', 79.5, 91.5)
|
||||||
|
small('D14', 'PESD5V0S1BA', 'Diode_SMD:D_SOD-323', SOD323, 'DFU_DP', 'GND', 79.5, 94)
|
||||||
|
small('D15', 'PESD5V0S1BA', 'Diode_SMD:D_SOD-323', SOD323, 'DFU_DM', 'GND', 79.5, 96.5)
|
||||||
|
small('D16', 'PESD5V0S1BA', 'Diode_SMD:D_SOD-323', SOD323, 'DFU_VBUS', 'GND', 79.5, 99)
|
||||||
|
# LDO cluster (under shield, SMD)
|
||||||
|
small('D12', 'SS34', T_SMA['lib'], None, 'LDO_IN', 'SYS5V', 84, 101, tmpl=T_SMA)
|
||||||
|
small('D13', 'SS34', T_SMA['lib'], None, 'LDO_IN', 'DFU_VBUS', 84, 104.5, tmpl=T_SMA)
|
||||||
|
sx_, sy_ = place((SOT223['crt'][2]-SOT223['crt'][0])+0.2, (SOT223['crt'][3]-SOT223['crt'][1])+0.2, 91, 102.5, label='U17')
|
||||||
|
INS.append(build_generic('U17', 'AMS1117-3.3', 'Package_TO_SOT_SMD:SOT-223-3_TabPin2', sx_, sy_, 0,
|
||||||
|
SOT223, {'1':'GND','2':'3V3','3':'LDO_IN','4':'3V3'}))
|
||||||
|
report['placed'].append(('U17', sx_, sy_, 'AMS1117'))
|
||||||
|
ctmpl = T_C0805 or T_C
|
||||||
|
small('C117', '10uF', 'Capacitor_SMD:C_0805_2012Metric' if T_C0805 else C_LIB, None, 'LDO_IN', 'GND', 96.5, 100, tmpl=ctmpl)
|
||||||
|
small('C118', '22uF/16V', 'Capacitor_SMD:C_0805_2012Metric' if T_C0805 else C_LIB, None, '3V3', 'GND', 96.5, 103, tmpl=ctmpl)
|
||||||
|
# LEDs + resistors near USB (visible, not under shield)
|
||||||
|
small('D17', 'LED C13 (blue)', 'LED_SMD:LED_0603_1608Metric', LED063, 'LED_C13', 'LED_C13_A', 64.5, 84)
|
||||||
|
small('D18', 'LED PWR (green)', 'LED_SMD:LED_0603_1608Metric', LED063, 'GND', 'LED_PWR_A', 64.5, 86.6)
|
||||||
|
r0603('R102', '1k', '3V3', 'LED_C13_A', 67.3, 84)
|
||||||
|
r0603('R103', '1k', '3V3', 'LED_PWR_A', 67.3, 86.6)
|
||||||
|
# SW2 BOOT0 next to SW1
|
||||||
|
swp = pads_of(T_SW['blk']); swnets = {p['num'] for p in swp}
|
||||||
|
sw_nets = {}
|
||||||
|
for p in swp:
|
||||||
|
sw_nets[p['num']] = 'BOOT0' if p['net'] and 'RESET' not in (p['net'] or '') else None
|
||||||
|
# simple: SW_Push pads 1/2 -> 3V3/BOOT0 (both pads of each side share)
|
||||||
|
padmap = {}
|
||||||
|
for p in swp:
|
||||||
|
padmap[p['num']] = '3V3' if p['num'] in ('1', '3') else 'BOOT0'
|
||||||
|
sxw, syw = 191.0, 133.3
|
||||||
|
blk = retarget(T_SW, 'SW2', 'BOOT0', T_SW['lib'], sxw, syw, T_SW['rot'], padmap)
|
||||||
|
bb = fp_bbox(dict(blk=blk, x=sxw, y=syw, rot=T_SW['rot']))
|
||||||
|
if not clear(bb, 0.25):
|
||||||
|
placed = False
|
||||||
|
for ax, ay in [(66, 81), (203, 127.5), (155.5, 133), (189, 126), (127, 60)]:
|
||||||
|
try:
|
||||||
|
sxw, syw = place(bb[2]-bb[0]+0.4, bb[3]-bb[1]+0.4, ax, ay, label='SW2')
|
||||||
|
placed = True; break
|
||||||
|
except RuntimeError:
|
||||||
|
continue
|
||||||
|
assert placed, 'SW2: no home found'
|
||||||
|
blk = retarget(T_SW, 'SW2', 'BOOT0', T_SW['lib'], sxw, syw, T_SW['rot'], padmap)
|
||||||
|
else:
|
||||||
|
occ.append(('SW2', bb))
|
||||||
|
INS.append(blk); report['placed'].append(('SW2', sxw, syw, 'BOOT0 button'))
|
||||||
|
# SWD test points row (north strip)
|
||||||
|
for i, (ref, net) in enumerate([('TP3','SWDIO'),('TP4','SWCLK'),('TP5','NRST'),('TP6','GND'),('TP7','3V3')]):
|
||||||
|
txp, typ = place(2.2, 2.2, 116+i*2.8, 57.5, label=ref)
|
||||||
|
INS.append(retarget(T_TP, ref, net, T_TP['lib'], txp, typ, 0, {'1': net}))
|
||||||
|
report['placed'].append((ref, txp, typ, net))
|
||||||
|
# Y1 / Y2 moves: rewrite (at) in their blocks
|
||||||
|
Y1f = by_ref('Y1'); Y2f = by_ref('Y2')
|
||||||
|
y1x, y1y = place(12.4, 6.0, 104.5, 56.5, label='Y1')
|
||||||
|
y2x, y2y = place(12.4, 6.0, 80.0, 106.5, label='Y2')
|
||||||
|
def move_block(f, nx, ny):
|
||||||
|
nb = re.sub(r'\(at [\-0-9. ]+\)', f'(at {nx:g} {ny:g}{(" %g"%f["rot"]) if f["rot"] else ""})', f['blk'], count=1)
|
||||||
|
return nb
|
||||||
|
del_spans.append(Y1f['span']); INS.append(move_block(Y1f, y1x, y1y))
|
||||||
|
del_spans.append(Y2f['span']); INS.append(move_block(Y2f, y2x, y2y))
|
||||||
|
report['placed'].append(('Y1', y1x, y1y, 'moved east')); report['placed'].append(('Y2', y2x, y2y, 'moved to U10'))
|
||||||
|
# Block Q holes: 4 shield (fixed) + 2 XBee
|
||||||
|
mh_tmpl = T_MH['blk']
|
||||||
|
def add_hole(ref, x, y, drill):
|
||||||
|
t = mh_tmpl
|
||||||
|
t = re.sub(r'\(property "Reference"\s+"[^"]+"', f'(property "Reference" "{ref}"', t, count=1)
|
||||||
|
t = re.sub(r'\(property "Value"\s+"[^"]*"', f'(property "Value" "MountingHole_M2.5"', t, count=1)
|
||||||
|
t = re.sub(r'\(at [\-0-9. ]+\)', f'(at {x:g} {y:g})', t, count=1)
|
||||||
|
t = re.sub(r'\(drill [0-9.]+\)', f'(drill {drill:g})', t)
|
||||||
|
t = re.sub(r'\(size [0-9.]+ [0-9.]+\)', f'(size {drill:g} {drill:g})', t)
|
||||||
|
t = re.sub(r'\(uuid "[^"]*"\)', lambda m: f'(uuid "{NU()}")', t)
|
||||||
|
bb2 = (x-drill/2-0.5, y-drill/2-0.5, x+drill/2+0.5, y+drill/2+0.5)
|
||||||
|
ok = clear(bb2, 0.25)
|
||||||
|
occ.append((ref, bb2)); INS.append(t)
|
||||||
|
report['holes'].append((ref, x, y, drill, 'CLEAR' if ok else '⚠ TIGHT — review'))
|
||||||
|
for i, (hx, hy) in enumerate(shield_holes):
|
||||||
|
add_hole(f'MH{7+i}', hx, hy, 2.75)
|
||||||
|
add_hole('MH11', 178.0, 60.5, 2.75)
|
||||||
|
add_hole('MH12', 185.35, 91.5, 2.75)
|
||||||
|
|
||||||
|
# ---------------- title date ----------------
|
||||||
|
text_patches = []
|
||||||
|
m = re.search(r'\(title_block.*?\(date "([^"]*)"\)', src, re.S)
|
||||||
|
if m:
|
||||||
|
a = m.start(1) - 7; b = m.end(1) + 2
|
||||||
|
text_patches.append((m.start(1), m.end(1), '2026-08-12'))
|
||||||
|
|
||||||
|
# ---------------- splice ----------------
|
||||||
|
new = src
|
||||||
|
ops = [(a, b, '') for a, b in del_spans] + [(a, b, t) for a, b, t in text_patches]
|
||||||
|
ops.sort(key=lambda o: -o[0])
|
||||||
|
spansorted = sorted([(a, b) for a, b, _ in ops])
|
||||||
|
for (a1, b1), (a2, b2) in zip(spansorted, spansorted[1:]):
|
||||||
|
assert b1 <= a2, 'overlap'
|
||||||
|
for a, b, t in ops:
|
||||||
|
if t == '':
|
||||||
|
a0 = a
|
||||||
|
while a0 > 0 and new[a0-1] in ' \t\n': a0 -= 1
|
||||||
|
new = new[:a0] + '\n\t' + new[b:]
|
||||||
|
else:
|
||||||
|
new = new[:a] + t + new[b:]
|
||||||
|
# KiCad 10: no numbered net table — nets exist via pad references only
|
||||||
|
# insert footprints before final paren
|
||||||
|
end = new.rfind(')')
|
||||||
|
new = new[:end] + '\t' + '\n\t'.join(INS) + '\n' + new[end:]
|
||||||
|
open(PCB, 'w', encoding='utf-8').write(new)
|
||||||
|
|
||||||
|
print(f'WROTE {PCB}: {len(src)} -> {len(new)} bytes; balance={new.count("(")==new.count(")")}')
|
||||||
|
print(f'new nets: {addnets}')
|
||||||
|
for k in ('removed', 'placed', 'holes'):
|
||||||
|
print(f'-- {k}:')
|
||||||
|
for item in report[k]: print(' ', item)
|
||||||
Loading…
Reference in New Issue
Block a user