diff --git a/.claude/skills/project-drogheda/SKILL.md b/.claude/skills/project-drogheda/SKILL.md index 9f163e1..02cef53 100644 --- a/.claude/skills/project-drogheda/SKILL.md +++ b/.claude/skills/project-drogheda/SKILL.md @@ -1,49 +1,73 @@ --- name: project-drogheda -description: Load Project Drogheda context — the Helgen HBOX GPS-RTK tracker fleet deployed at Hutchison Ports ICAVE (Veracruz). Use whenever Leo works on anything Drogheda/HBOX-related: the simpleRTK2B / u-blox ZED-F9P, the 4G NTRIP Master, the Blackpill STM32 watchdog (blackpillrtkcode.ino), PowerBoost/LiPo power, the IP65 enclosure, retranslator.py / NTRIP caster / Wialon, the field failures and thermal issues, the watchdog PCB design, or any document/diagram/firmware destined for the Project-Drogheda folder — even if "Drogheda" isn't named. +description: Load Project Drogheda (HBOX RTK / EinarBoard) context and close every task on its command centre, drogheda.helgen.online. Use for any Drogheda, HBOX or EinarBoard work. --- -# Project Drogheda — HBOX RTK Tracker +# Project Drogheda — context and command centre -You are helping **Helgen Technologies** with **Project Drogheda**: a fleet of -vehicle-mounted high-precision **GPS-RTK trackers (HBOX)** deployed on heavy -equipment at **Hutchison Ports ICAVE, Veracruz, Mexico**, streaming RTK-corrected -position to the client's **Wialon** portal. +You are the CTO/CSO of Helgen Technologies and principal hardware/software architect for **Drogheda**: HBOX RTK +trackers (EinarBoard V5.5 in the field; V5.6, V5.7 and v6 toward an order of 570) for the Hutchison Ports yards +**ICAVE, LCT, EIT and TIMSA**. Tone: precise, fail-safe first; an objective partner, not a sycophant. -## Always do first -1. Read `CLAUDE.md` in the project root — it is the source of truth for hardware, - firmware, backend, deployment, people, and the current crisis. -2. Read `PLAN.md` for current priorities and open tasks. -3. For failures/diagnosis, read `06-Testing-Validation/RCA-2026-06-field-failures.md` (keep it a - ranked differential — don't over-anchor on "heat" before the cheap backend/ - SIM/caster checks are ruled out). +## Mantra -## System in one breath -simpleRTK2B (u-blox ZED-F9P) + 4G NTRIP Master pull RTCM3 over LTE and emit NMEA; -a Blackpill STM32 **watchdog** manages power (vehicle/ignition/LiPo) and restarts -the stack when the link drops; `retranslator.py` filters NMEA (anti-jump + speed) -and forwards to Wialon. Power: 12–24 V → PowerBoost 1000C (+LiPo) → switched 5 V. +**«Si no está en el sitio, no pasó.»** drogheda.helgen.online is the command centre: every task — engineering, +documents, firmware, the site itself — is coordinated and closed there. A task is not done until the closing +loop below is done. -## Hard-won facts (don't relearn these) -- **NMEA GGA quality:** 0 none · 1 GPS · 2 DGPS · **4 RTK-fixed** · **5 RTK-float**. - Corrections-healthy = quality **≥4** (fixed AND float are good). -- The **ZED-F9P is rated −40…+85 °C** — it's rarely the heat casualty. The weak - links are the **LiPo** (charge ≤45 °C), the **PowerBoost**, and the **4G modem**. -- Corrections come over the **4G modem**, not the GNSS — so a GNSS hot-reset does - **not** fix a dead NTRIP link. Recover by **power-cycling the stack**. -- UBX CFG-RATE 1 Hz/30 s commands and checksums are verified (see firmware-review). +## Read first -## Conventions -- Firmware: edit `04-Source-Code/firmware/blackpillrtkcode_v2/blackpillrtkcode_v2.ino`; **bench-test before field - flash** (the sandbox can't compile for STM32). Keep v1 as reference. -- Hardware/BOM changes go in `03-Architecture-Hardware/hardware-respec-and-pcb-brief.md`. -- Dates absolute (e.g., 2026-06-19). Don't leak internal paths to the client. -- Client-facing material is **Spanish** and routes through Leo. +1. `~/Documents/Claude/Projects/Drogheda/CLAUDE.md` — section ★ (the rule) and §0 (engineering status). +2. `hbox-docs/CLAUDE.md` — where each piece of the site lives and how to change it. +3. `hbox-docs/_estado/tablero.md` — the board snapshot (ask Leo for `./scripts/tablero.sh foto` if it is stale). +4. `hbox-docs/docs/datos/proyecto.json` (route to production, milestones) and `hbox-docs/docs/hardware/index.md` + (per-board state). + +Without the repo (a plain chat): the claude.ai Project docs (`claude/…`, start with the newest +`…Centro-de-Mando…`), the latest dated audit, and ask Leo for the snapshot. + +## Closing loop (every task) + +1. **Board** — a lote in `hbox-docs/backend/lotes/AAAA-MM-DD_tema.json`: close · create · comment, each with a + one-line why in Mexican Spanish; ids from the snapshot, `buscar` when unknown, `si_no_hay` before creating. + Leo applies it with `./scripts/tablero.sh revisar` → `aplicar`. Never change the board any other way. +2. **Docs** — source in the `NN-` folder (`AAAA-MM-DD_Drogheda_…`, `date:` front matter) → `scripts/sync-docs.sh` + MAP → `mkdocs.yml` nav → section index → a Bitácora line. Figures go on the site with the doc they explain. + A copy goes to the claude.ai Project. +3. **Route** — `proyecto.json` when a board changes stage, a date moves or the week's focus changes. The live + «Enfoque de la semana» belongs to Leo and Adriana: propose the wording. +4. **Decisions** — `docs/tableros/ingenieria.md` «Últimas decisiones» (dated, numbered D-xx-n) and `CLAUDE.md` §0. +5. **Improvements** — fix small site friction in the same task; otherwise a pendiente in the lote. +6. **Master index** — `CLAUDE.md` §0 and §2. Vault notes only for what became evergreen. +7. **Hand-off** — end with a «Centro de mando» block: what changed on the site and Leo's commands (sync → + `mkdocs build --strict` → commit/push `hbox-docs` → bump the submodule → `deploy.sh` → `tablero.sh revisar` / + `aplicar` → `restart actas-hbox` only if `backend/app.py` changed). + +## Hard rules + +- Mexican Spanish for everything the team reads. +- Never run git in the mounted folder (it leaves a stale `index.lock`): give Leo the commands. The mount cannot + delete: move leftovers to `_to_delete/`. +- No secrets: the 4G/NTRIP parameter file (caster, APN) never goes on the site — only its template. +- KiCad: one person per board at a time. T-scripts are dry-run by default, keep a `.Txxbak`, abort on drift, are + idempotent, and are proven on copies (DRC with the `.kicad_dru`, refilled zones, parity) before touching + HBox_PCB. Iterations are edited in place; V5.7 is its own project (`hbox-watchdog-v57`). Re-check the RS1 Kelvin + after any change near it. +- Firmware per board, never by version number; bench before field. +- Server steps are commands for Leo's own SSH session. +- Design and UI calls: pick the best option instead of asking. + +## Where things live + +- Repo (source of truth): `~/Documents/Claude/Projects/Drogheda/` — `NN-` folders; `kicad/` submodule + (HBox_PCB); `hbox-docs/` submodule = the site. +- Site: drogheda.helgen.online (basic auth; backend on `127.0.0.1:8081` at git.helgen.online). +- Vault: `Second Brain/03 Projects/Helgen/Project-Drogheda/` (MOC + memory set); the pattern: + `04 Resources/Helgen/Helgen Project Command Centre`. +- Drive: `Drogheda (GPS RTK)` — client exports. ## People -Helgen: Leo (founder/CEO), Adriana, Paola, Daniel, Gibran. -Client (ICAVE): **Agustín Alfonseca** (Supervisor de Investigación de Tecnología), -Leon David Piña (Hutchison Ports). -## Codename -Helgen uses Irish place-names (Ennis, **Drogheda**). This project = "Drogheda." +Leo (CEO; decides) · Adriana (PM) · Michelle (PCB layout) · Jesús (test technician) · Aldair (fabrication, role +to be confirmed) · Alán and Daniel (field) · Gibran (htracker). Client: ICAVE (Agustín Alfonseca); Hutchison Ports +(Leon David Piña). diff --git a/03-Architecture-Hardware/2026-10-22_Drogheda_Auditoria-Final-Produccion_V5.6-V5.7_Protocolo_ES_v1.0.md b/03-Architecture-Hardware/2026-10-22_Drogheda_Auditoria-Final-Produccion_V5.6-V5.7_Protocolo_ES_v1.0.md new file mode 100644 index 0000000..863eab2 --- /dev/null +++ b/03-Architecture-Hardware/2026-10-22_Drogheda_Auditoria-Final-Produccion_V5.6-V5.7_Protocolo_ES_v1.0.md @@ -0,0 +1,140 @@ +--- +title: "Protocolo de la auditoría final de producción — EinarBoard V5.6 y V5.7 (22-oct-2026)" +tags: [project-drogheda, hardware, hbox, einarboard, v5.6, v5.7, auditoria, produccion, protocolo, gerber, firmware] +project: Project Drogheda +author: Helgen Technologies (auditoría: Claude; decide: Leo) +date: 2026-10-22 +version: 1.0 +status: ACTIVO — es el «reprompt» que Leo pidió antes de empezar; la auditoría misma es el PDF `Auditoria-Final-V56-V57/` +audience: Leo (decide el pedido), Michelle, Jesús, Aldair, Adriana +--- + +# Protocolo de la auditoría final de producción — V5.6 y V5.7 · 22-oct-2026 + +> **Para qué existe este documento.** Leo pidió (22-oct, 10:01): *«antes de hacer nada, vuélvete a dar la +> instrucción y documenta este proceso de auditoría como el último paso antes de producción»*. Esto es esa +> instrucción, escrita para que la auditoría sea **una sola, completa y decisiva**, y para que la próxima +> tarjeta (v6) se audite igual. Es el paso 7 de la Ruta a producción: entre «Gerber» y «Piloto». + +## 0. El mandato, en las palabras de Leo + +1. **Meta de V5.6 y V5.7: que todos los puertos funcionen.** +2. **V5.7 no usa la Mean Well** (SD-15B): fuente de 9–32 V a bordo. +3. **Ethernet, RS-485 y RS-232 deben ser usables** si se les conectan señales. +4. **El módem 4G no debe provocar un apagón (brownout)**, sobre todo en batería. +5. **En batería:** apagarse o entrar en un modo de muy bajo consumo **10 minutos**, despertar, mandar **un par de + reportes**, y volver a dormir. Todo tiene que funcionar como debe. +6. Los Gerber, BOM y archivos de fabricación **ya están** en `kicad/production/HBOX_v5_Rev6_PROD` y + `HBOX_v5_Rev7_PROD`. +7. **Empezar el firmware**: tiene que quedar «spot on». +8. **Esta auditoría se hace una vez** (las otras sesiones dicen «casi listo»; se dejaron pasar detalles por falta de + espacio en la tarjeta): resaltar **riesgos** y **victorias fáciles (easy wins)**, con una **tabla** de + problema → arreglo, **imágenes** y explicaciones. +9. Entregables: **documento en español, formato Helgen, LaTeX** + **presentación Beamer**; resaltar los + **algoritmos** de las tarjetas; **evaluación de riesgos con matriz**; solo V5.6 y V5.7. +10. **Las tarjetas se piden hoy**: la auditoría termina en una decisión GO / NO-GO por tarjeta. + +## 1. Rol y postura + +- Actúo como **auditor independiente** con el sombrero de diseñador de electrónica y de dispositivos de + geolocalización: reviso lo que está en los archivos, no lo que los documentos anteriores dicen que está. +- **Socio objetivo, no complaciente**: si algo no está listo, se dice; si un riesgo se acepta, se dice por qué y + con qué mitigación. «Casi listo» no es un veredicto. +- Cada hallazgo cita **archivo, red, pin o coordenada** y trae un arreglo concreto, clasificado como + **bloqueante** (no se pide hoy), **alto** (se pide con mitigación y se mide en el piloto), **medio**, **bajo** + o **easy win** (barato, sin mover piezas: BOM, un valor, firmware o un paso del pedido). +- **No se mueve ninguna pieza ni se toca HBox_PCB** en esta auditoría. Si un arreglo pide cambiar los archivos, + queda escrito con sus coordenadas y Leo decide si va antes del pedido o a la siguiente revisión. + +## 2. Insumos (los archivos tal como están en la Mac, 22-oct 10:00) + +| Insumo | Archivo | SHA-256 (8) | +|---|---|---| +| V5.6 PCB (el de los Gerber) | `kicad/hbox-watchdog-v5.kicad_pcb` | `f07ad5b5` | +| V5.6 esquemático | `kicad/hbox-watchdog-v5.kicad_sch` | `dc9381d7` | +| V5.6 proyecto / reglas | `kicad/hbox-watchdog-v5.kicad_pro` · `.kicad_dru` | `f6721eb7` · `8e4d3a7b` | +| V5.7 PCB (el de los Gerber) | `kicad/hbox-watchdog-v57.kicad_pcb` | `9373ebe8` | +| V5.7 esquemático | `kicad/hbox-watchdog-v57.kicad_sch` | `e0e6caf6` | +| V5.7 proyecto / reglas | `kicad/hbox-watchdog-v57.kicad_pro` · `.kicad_dru` | `d36d5139` · `8e4d3a7b` | +| Paquete V5.6 | `production/HBOX_v5_Rev6_PROD.zip` + `_bom.csv` + `_positions.csv` + `_designators.csv` (22-oct 01:55) | `49969628` · `3fbb69f2` · `0904080d` | +| Paquete V5.7 | `production/HBOX_v5_Rev7_PROD.zip` + `_bom.csv` + `_positions.csv` + `_designators.csv` (22-oct 15:55) | `fb18a61b` · `08e53137` · `c6f2c750` | +| Firmware de referencia | `04-Source-Code/firmware/hbox_v5_bringup/` 0.6.3 (`hbox_v5_bringup.ino`, `board_v5.h`, `board_v4.h`) | — | +| Auditorías previas | 16-oct (producción), 19-oct (re-auditoría y críticos), 21-oct (pasada 4–6, T32–T37), ECO V5.6 (27-sep), ECO V5.7 (13-oct) | — | +| Hojas de datos | LTC4040, AP64350, TPS54360B, MP1584, SC16IS752, W5500, SP3485, MAX3232, SC7A20, STM32F411RE, SMBJ33(C)A, IRFR5305 | — | + +Verificado antes de empezar: los dos `.kicad_pcb` **solo** difieren de sus respaldos `.T35bak` / `.T37bak` en lo que +T35 y T37 agregaron (la vía de U7 y la vía de GND de C129): nada se movió después de la pasada 6, y los Gerber +se exportaron **después** del último guardado de cada PCB (V5.6 01:05 → 01:55; V5.7 01:30 → 15:55). + +## 3. Método — qué se revisa y cómo (A a G) + +**A · Integridad del paquete de fabricación.** Regenerar Gerber + taladros desde cada `.kicad_pcb` con +`kicad-cli` 10.0.4 en copias y comparar capa por capa con lo exportado; juego de capas completo (F/In1/In2/B, +máscaras, pasta, serigrafía, contorno, PTH/NPTH); tamaño de tarjeta; mínimos de pista, holgura y barreno contra +la capacidad de JLC de 4 capas; pasta del EP de U6 (≤ 50 %) y de U7/U25; serigrafía sobre pads; BOM: toda pieza +montada con código LCSC, sin duplicados de valor con dos códigos, DNP realmente fuera; CPL: cuenta de huellas +contra el PCB, **rotaciones** de U6, U7, U25, Q7, RS1, U16 y de todo lo polarizado (JLC gira distinto que KiCad); +reglas DFM del 8-oct (vías del EP de U6 «Epoxy Filled & Capped», rayos X). + +**B · Revisión eléctrica por bloque, sobre el netlist exportado de cada esquemático.** Entrada de V5.7 +(P1 → F2 → D10/Q10 → U25 → L22/D34 → VEH5V; FB, compensación, soft-start, UVLO, polaridad invertida, 9–32 V); +LTC4040 (PFI/PFO, flotación LFP, RNTB, RPROG, límite de entrada con RS1 Kelvin, VSYS/C129, BSTFB, F0–F2); +riel del módem (AP64350 desde SYS5V, MODEM_EN con su pull-down, MODEM_RST, MODEM_LED, C130, corriente de +ráfaga); etapa RTK (PA1 → Q5 → Q1, SW_5V, pull-up de seguridad); MCU (HSE/LSE, BOOT0/BOOT1, DFU/SWD, NRST, VBAT, +ADC de ignición en PA5 con 12 V y 24 V); bus I²C (direcciones, pull-ups, un solo maestro); Ethernet (W5500, +reset con pull-down, J10, LEDs, terminación); RS-485 (U14: DE/RE, estado tras reset, TVS, polarización); +RS-232 (U15, H4, R1OUT); sensores (SHT40, TMP102); acelerómetro (SC7A20, INT1 → PB9 = EXTI, dirección 0x18); +ventilador (JP1, Q2); LEDs y gauge (PCF8574); conectores y ESD (J9/J11, P1–P14, GX16). + +**C · Apagón del módem y ciclo de 10 minutos en batería.** Presupuesto de corriente en respaldo (lo que el +LTC4040 puede dar desde el paquete vs lo que piden etapa + módem en ráfaga), capacitancia de SYS5V y 3V3_MODEM, +umbrales (PFI 4.40 V, UVLO del AP64350 3.8 V, PSM del módem), **piso de sueño** (qué consume con todo apagado: +U17, K1, LEDs, U12/W5500, transceptores, MCU en STOP), **fuentes de despertar** (RTC con LSE Y4, INT1 del SC7A20, +PFO/VEH5V), rieles que el firmware puede cortar y cuáles no; la **secuencia** de dormir y despertar, con +tiempos, y qué pasa si algo falla a medio ciclo. + +**D · Cobre final, sobre los archivos exactos de los Gerber.** DRC de KiCad con el `.kicad_dru`, «Rellenar +zonas» y «Comprobar paridad» en copias; prueba Kelvin de RS1 (VIN y CLN); vías de corte (cambios de capa de +potencia con una sola vía); potencia por capas internas; vías sueltas; lazos de U25, U7 y U6; holguras mínimas de +lo que cambió en la pasada 6. + +**E · Firmware.** Leer 0.6.3 y `board_v5.h`; derivar **`board_v56.h` pin a pin del netlist de V5.6** (y +confirmar que V5.7 es idéntica en el MCU); documentar los **algoritmos** que ya existen (gobernador de carga, +ventilador, recuperación de enlace, modo B/K1, telemetría `$PHLG`/`$PHEV`, corte térmico, baja batería) y +diseñar los que faltan (**ciclo de 10 min**: STOP + alarma RTC, secuencia del módem sin brownout, reporte y +regreso a dormir; SC16IS752 con el RS-485 libre tras el reset; Ethernet de campo; SC7A20; ignición por ADC), +con pseudocódigo y máquinas de estados; listar los **riesgos de firmware** que el piloto tiene que probar. + +**F · Evaluación de riesgos.** Matriz **5 × 5** (probabilidad × impacto) por hallazgo; clase y dueño del +arreglo; qué se mide en el piloto de 5 + 5; **criterio GO / NO-GO** por tarjeta. + +**G · Entregables y cierre.** Documento LaTeX (estilo Helgen, XeLaTeX) con tabla de hallazgos, figuras +anotadas y matriz; presentación Beamer (helgen-beamer); `board_v56.h`; este protocolo; y el cierre en el centro +de mando (lote, docs, Ruta, decisiones, índice maestro, copia al Project). + +## 4. Criterio de decisión + +| Veredicto | Significa | Condición | +|---|---|---| +| **GO** | Se pide hoy el piloto de 5 (y las 108 / 322 después del banco). | Ningún hallazgo bloqueante; los altos tienen mitigación escrita y prueba en el piloto. | +| **GO con cambios de paquete** | Se pide hoy, pero **después** de corregir BOM/CPL/opciones del pedido (sin tocar cobre). | Los bloqueantes están todos en BOM, CPL u opciones del pedido. | +| **NO-GO** | No se pide hasta corregir el cobre. | Hay un hallazgo bloqueante en cobre (corto, red abierta, pieza fuera de capacidad de fábrica, riesgo de daño). | + +**Bloqueante** = algo que, fabricado así, deja una función del mandato (§0) sin poder cumplirse ni con firmware, +o daña la tarjeta. **Alto** = compromete el mandato en condiciones de campo (calor, batería baja, ráfaga LTE) +pero se puede mitigar con firmware, BOM o un paso del pedido, y se mide en el piloto. + +## 5. Reglas durante la auditoría + +- Todo en **copias**; HBox_PCB no se toca. `kicad-cli` solo sobre copias. +- Cada afirmación numérica sale de un archivo (netlist, PCB, Gerber, datasheet) y se cita. +- **Español mexicano** para todo lo que lee el equipo; sin secretos (el archivo de parámetros 4G/NTRIP no se cita). +- Lo que ya estaba cerrado el 21-oct **se vuelve a comprobar**, no se da por hecho. +- Si aparece algo que solo se puede confirmar en el banco, se escribe como **prueba del piloto** con criterio de + aceptación, no como suposición. +- Termina con el bloque «Centro de mando» para Leo. + +## 6. Orden de trabajo (hoy) + +1. Este protocolo → Leo (listo). 2. A + D (paquete y cobre, con `kicad-cli`). 3. B + C (eléctrica y batería). +4. E (firmware y `board_v56.h`). 5. F (matriz y veredicto). 6. Figuras. 7. LaTeX + Beamer. 8. Cierre. diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/2026-10-22_Drogheda_Auditoria-Final-Produccion_V5.6-V5.7_ES_v1.0.pdf b/03-Architecture-Hardware/Auditoria-Final-V56-V57/2026-10-22_Drogheda_Auditoria-Final-Produccion_V5.6-V5.7_ES_v1.0.pdf new file mode 100644 index 0000000..eb9297e Binary files /dev/null and b/03-Architecture-Hardware/Auditoria-Final-V56-V57/2026-10-22_Drogheda_Auditoria-Final-Produccion_V5.6-V5.7_ES_v1.0.pdf differ diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/2026-10-22_Drogheda_Auditoria-Final-Produccion_V5.6-V5.7_Presentacion_ES_v1.0.pdf b/03-Architecture-Hardware/Auditoria-Final-V56-V57/2026-10-22_Drogheda_Auditoria-Final-Produccion_V5.6-V5.7_Presentacion_ES_v1.0.pdf new file mode 100644 index 0000000..9464548 Binary files /dev/null and b/03-Architecture-Hardware/Auditoria-Final-V56-V57/2026-10-22_Drogheda_Auditoria-Final-Produccion_V5.6-V5.7_Presentacion_ES_v1.0.pdf differ diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/README.md b/03-Architecture-Hardware/Auditoria-Final-V56-V57/README.md new file mode 100644 index 0000000..8b23e1f --- /dev/null +++ b/03-Architecture-Hardware/Auditoria-Final-V56-V57/README.md @@ -0,0 +1,36 @@ +# Auditoría final de producción — EinarBoard V5.6 y V5.7 (22-oct-2026) + +Fuentes LaTeX, figuras y scripts de la auditoría. El documento canónico para el equipo es +`../2026-10-22_Drogheda_Auditoria-Final-Produccion_V5.6-V5.7_ES_v1.0.md` (sitio: `/hardware/auditoria-final-22oct/`); +el protocolo («reprompt») es `../2026-10-22_Drogheda_Auditoria-Final-Produccion_V5.6-V5.7_Protocolo_ES_v1.0.md`. + +| Archivo | Qué es | +|---|---| +| `auditoria.tex` + `sec1…sec10-*.tex`, `apendices.tex`, `tab-*.tex` | Informe completo (33 pp.), formato Helgen (`estilo-helgen.tex` = copia de `_brand/estilo-helgen.tex`) | +| `presentacion.tex` | Presentación Beamer (19 láminas, tema Metropolis + colores Helgen) | +| `fig/` | Figuras (renderizado propio de los Gerber + matplotlib). Copias con nombre canónico en `../img/2026-10-22_Drogheda_*.png` | +| `scripts/` | `gerb.py` (parser/render de Gerber) · `gcmp.py` (comparación de Gerber) · `netparse.py` (netlist KiCad) · `copper.py` (grafo de cobre, Kelvin, vías) · `render_*.py` (figuras) · `riesgos.py` (registro y matriz) | +| `*.pdf` | Salidas compiladas el 22-oct | + +## Compilar + +```bash +xelatex auditoria.tex && xelatex auditoria.tex # fuentes League Spartan + MADE Evolve Sans instaladas +xelatex presentacion.tex && xelatex presentacion.tex +``` + +Los scripts corren con Python 3.11+ (`shapely`, `matplotlib`, `numpy`) sobre las copias de +`kicad/_to_delete/audit-20261022/{v56,v57}/` (Gerber de `gerber-cli/`, `rf/gerber/` y del paquete `HBOX_v5_Rev*_PROD`). + +## Re-verificación después de un cambio (5 min) + +En la Mac, con copias nuevas en `kicad/_to_delete/audit-AAAAMMDDx/{v56,v57}/` (proyecto completo: `.kicad_pcb`, `.kicad_pro`, +`.kicad_prl`, `.kicad_dru`, tablas y `.pretty`) y los zips de producción descomprimidos en `pkg56/` y `pkg57/`: + +```bash +zsh scripts/verify_mac.sh v56 hbox-watchdog-v5 # DRC + paridad, Gerber as-saved, relleno con proyecto + Gerber +zsh scripts/verify_mac.sh v57 hbox-watchdog-v57 +python3 scripts/gcmp_b.py # A relleno guardado vs fresco · B paquete vs archivo · C/D contra la auditoría +``` + +`verify_mac.sh` y `refill.py` viven en `scripts/`; `gcmp_b.py` espera las rutas `../in` (auditoría) y `../inb` (copias nuevas). diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/apendices.tex b/03-Architecture-Hardware/Auditoria-Final-V56-V57/apendices.tex new file mode 100644 index 0000000..554072f --- /dev/null +++ b/03-Architecture-Hardware/Auditoria-Final-V56-V57/apendices.tex @@ -0,0 +1,58 @@ +% ================================================================ APÉNDICES +\appendix +\section{Mapa de pines del STM32F411 (netlist del 22-oct, V5.6 = V5.7)}\label{sec:pinmap} + +{\footnotesize +\begin{longtable}{@{}L{0.9cm}L{1.6cm}L{3.6cm}L{9.2cm}@{}} +\toprule +\cab{\cw{Pin} & \cw{Puerto} & \cw{Red} & \cw{Función / notas}}\\ +\midrule +\endfirsthead +\toprule +\cab{\cw{Pin} & \cw{Puerto} & \cw{Red} & \cw{Función / notas}}\\ +\midrule +\endhead +\input{tab-pinmap.tex} +\end{longtable}} + +\section{Diferencias de BOM entre V5.6 y V5.7}\label{sec:bomdiff} + +\hwtab{\begin{tabular}{@{}L{3.34cm}L{6.28cm}L{6.28cm}@{}} +\toprule +\cab{\cw{} & \cw{Solo V5.6} & \cw{Solo V5.7}}\\ +\midrule +Entrada y fuente & \refdes{P2} (5 V de la SD-15B); \refdes{U2} MP1584 + \refdes{L2} 10 $\mu$H + \refdes{Dbk1} SS34 + \refdes{Cbst1}, \refdes{Ccomp1}, \refdes{Rcomp1}, \refdes{Ren1}, \refdes{Ren2}, \refdes{Rfreq1}, \refdes{R20}, \refdes{R21} (buck del ventilador); \refdes{JP1} abierto & \refdes{F2} 3 A; \refdes{U25} TPS54360B; \refdes{L22} SRP1265A 10 $\mu$H; \refdes{D34} B560C; \refdes{C149/C150} 2.2 $\mu$F/100 V; \refdes{C153/C154} 47 $\mu$F/16 V; \refdes{C152} 100 nF (BOOT); \refdes{C155} 6.8 nF, \refdes{C156} 39 pF, \refdes{R123} 13 k (comp.); \refdes{R120} 162 k (RT); \refdes{R121} 57.6 k / \refdes{R122} 10.2 k (FB); \refdes{R124/R125} DNP (EN); \refdes{JP1} puenteado (ventilador desde VEH5V)\\ +\rowcolor{HelgenMist} Común (resumen) & \multicolumn{2}{L{12.8cm}@{}}{U6 LTC4040 + L6 + RS1 10 m$\Omega$ + Q7; U7 AP64350 + L7 + C130; U16 STM32F411RET6; U10 SC16IS752 + Y2; U11 W5500 + U12 + L8 + J10; U13 PCF8574; U14 SP3485; U15 MAX3232; U17 TLV1117LV33; U3 SHT40; U4/U18 TMP102; U26 SC7A20; K1 G5V-1; D10 SMBJ33A + Q10 IRFR5305 + DzG1; C129; paquete LFP (R55 5.6 k, JP2 2-3); conectores P1, P4, P6, P8, P10, P11, P14, P15, P16, H4, J7, J8, J9, J11.}\\ +\bottomrule +\end{tabular}} + +\section{Cómo se hizo (reproducible)}\label{sec:comohizo} + +\begin{itemize} +\item Copias de trabajo: \texttt{03-Architecture-Hardware/kicad/\_to\_delete/audit-20261022/\{v56,v57\}/} con el + \texttt{.kicad\_pcb}, \texttt{.kicad\_sch}, \texttt{.kicad\_pro}, \texttt{.kicad\_dru}, tablas de bibliotecas y las + bibliotecas \texttt{Drogheda.pretty} / \texttt{Drogheda-v6.pretty} / \texttt{*.kicad\_sym}. SHA-256 de las copias = + SHA-256 de los originales. +\item \texttt{kicad-cli pcb drc --schematic-parity --refill-zones --severity-all --format json}; + \texttt{kicad-cli sch export netlist --format kicadsexpr}; \texttt{kicad-cli sch erc}; + \texttt{kicad-cli pcb export gerbers --subtract-soldermask --no-protel-ext}; \texttt{export drill + --excellon-separate-th --generate-map}; \texttt{export pos}; \texttt{export svg} por capa (KiCad 10.0.4, Mac). +\item Relleno fresco con el proyecto cargado: \texttt{pcbnew} de KiCad (Python) en una copia con el mismo nombre + de proyecto (\texttt{rf/}), \texttt{ZONE\_FILLER.Fill()}, guardar, exportar Gerber y comparar. Sin el + \texttt{.kicad\_pro} al lado, el relleno sale con reglas por defecto y difiere en cientos de mm$^2$: no sirve como + referencia (lección del día). +\item Comparación de Gerber: parser propio (\texttt{gerb.py}): flashes (aperturas C/R/O/RoundRect/macros) y + trazos como conjuntos exactos; regiones rasterizadas a 20 $\mu$m y comparadas por XOR (\texttt{gcmp.py}). +\item Netlist: parser s-expr (\texttt{netparse.py}); mapa de pines, nets por bloque, pines al aire, diferencias + V5.6/V5.7. +\item Cobre: \texttt{copper.py} — grafo de conectividad por red (pads, pistas, vías; sin zonas: las redes de potencia + no tienen zonas); prueba Kelvin recortando el área del pad; vías de articulación; potencia en In1/In2. +\item BOM/CPL: cruce con las huellas del PCB (atributos DNP, fuera de BOM/posiciones), rotación de huella contra + rotación en la CPL, códigos LCSC de la propiedad contra el BOM. +\item Pasta: ventanas de \refdes{U6} y pads térmicos de \refdes{U7}/\refdes{U25} medidos sobre \texttt{F\_Paste}; + vías dentro de los pads desde el \texttt{.kicad\_pcb}. +\item Hojas de datos consultadas en línea el 22-oct: LTC4040 (ADI 4040fb), AP64350 (Diodes, databrief), W5500 + (v1.1.0), TPS54360B; piezas en \texttt{jlcpcb.com/partdetail/}: C85100, C32346, C15578, C99550, C840531. +\item Figuras: renderizado propio de los Gerber (matplotlib + shapely) con anotaciones; matriz y autonomía con + matplotlib. Todo en \texttt{03-Architecture-Hardware/Auditoria-Final-V56-V57/} (fuentes LaTeX, figuras y scripts). +\end{itemize} diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/auditoria.tex b/03-Architecture-Hardware/Auditoria-Final-V56-V57/auditoria.tex new file mode 100644 index 0000000..cf1f9ed --- /dev/null +++ b/03-Architecture-Hardware/Auditoria-Final-V56-V57/auditoria.tex @@ -0,0 +1,102 @@ +% ===================================================================== +% 2026-10-22_Drogheda_Auditoria-Final-Produccion_V5.6-V5.7_ES_v1.0 +% Helgen Technologies — Project Drogheda (GPS RTK) +% Auditoría final de producción: EinarBoard V5.6 y V5.7 (GO / NO-GO del pedido) +% Compilar: xelatex auditoria.tex (x2). Estilo: estilo-helgen.tex (_brand/). +% ===================================================================== +\documentclass[11pt]{article} + +\providecommand{\sistema}{Project Drogheda} +\providecommand{\sistemapdf}{Helgen Drogheda} +\providecommand{\doctipo}{Auditoría final de producción — EinarBoard V5.6 $\cdot$ V5.7} + +\input{estilo-helgen.tex} + +\usepackage{longtable} +\usepackage{listings} +\usepackage{amsmath} +\usepackage{amssymb} +\usepackage{multirow} +\usepackage{makecell} +\usetikzlibrary{chains, decorations.pathreplacing} + +\definecolor{CodeBg}{HTML}{F4F6F9} +\lstset{ + basicstyle=\ttfamily\scriptsize\color{HelgenIndigo}, + backgroundcolor=\color{CodeBg}, + frame=single, rulecolor=\color{HelgenIndigo!35}, + breaklines=true, columns=fullflexible, keepspaces=true, + showstringspaces=false, + commentstyle=\color{HelgenTeal}, + keywordstyle=\color{HelgenIndigo}\bfseries, + language=C++ +} + +\newcommand{\net}[1]{\texttt{#1}} +\newcommand{\refdes}[1]{\textbf{\texttt{#1}}} +\newcommand{\nbar}[1]{$\overline{\mbox{\footnotesize\texttt{#1}}}$} +\newcommand{\estado}[1]{\textcolor{HelgenTeal}{\textbf{#1}}} +\newcommand{\alerta}[1]{\textcolor{red!70!black}{\textbf{#1}}} +\newcommand{\ok}{\textcolor{HelgenTeal}{\textbf{OK}}} +\newcommand{\sevA}{\textcolor{red!75!black}{$\blacksquare$}} +\newcommand{\sevB}{\textcolor{orange!90!black}{$\blacksquare$}} +\newcommand{\sevC}{\textcolor{yellow!65!orange}{$\blacksquare$}} +\newcommand{\sevD}{\textcolor{green!60!black}{$\blacksquare$}} +\newcommand{\cab}[1]{\rowcolor{HelgenIndigo}#1} +\newcommand{\cw}[1]{\textcolor{white}{\textbf{#1}}} +\newcommand{\vA}{\textbf{V5.6}} +\newcommand{\vB}{\textbf{V5.7}} + +\renewcommand{\arraystretch}{1.22} + +\begin{document} + +% ================================================================ PORTADA +\helgenportada{Auditoría final de producción}% +{EinarBoard V5.6 $\cdot$ V5.7 — ¿se piden hoy? Paquete de fabricación, electrónica, batería, puertos, firmware y riesgo}% +{\begin{tabular}{@{}ll@{}} +Código & \texttt{2026-10-22\_Drogheda\_Auditoria-Final-Produccion\_V5.6-V5.7\_ES\_v1.0}\\ +Proyecto & Drogheda (GPS RTK) — HBOX $\cdot$ Hutchison Ports (ICAVE / TIMSA / EIT / LCT)\\ +Alcance & \texttt{HBOX\_v5\_Rev6\_PROD} (V5.6, \texttt{hbox-watchdog-v5}) $\cdot$ \texttt{HBOX\_v5\_Rev7\_PROD} (V5.7, \texttt{hbox-watchdog-v57}) $\cdot$ firmware 0.6.3 $\to$ 0.7.0\\ +Audiencia & Leo (decide el pedido) $\cdot$ Michelle $\cdot$ Jesús $\cdot$ Aldair $\cdot$ Adriana\\ +Auditor & Claude (CTO/CSO virtual, Helgen) — revisión independiente sobre los archivos tal como están en la Mac\\ +Fecha & 22 de octubre de 2026 (emisión 11:30; re-verificación 13:30 sobre los archivos de las 13:00)\\ +Veredicto & \textbf{GO} al piloto de 5 + 5 con tres condiciones de pedido $\cdot$ las 108 / 322 esperan al banco con 0.7.0\\ +\end{tabular}} + +% ================================================================ CONTROL +\section*{Control del documento} + +\hwtab{\begin{tabular}{@{}llL{9.2cm}@{}} +\toprule +\cab{\cw{Rev} & \cw{Fecha} & \cw{Cambio}}\\ +\midrule +1.0 & 2026-10-22 & Emisión. Auditoría final sobre los Gerber/BOM/CPL exportados el 22-oct (V5.6 01:55, V5.7 15:55), los proyectos KiCad que los produjeron (SHA-256 en §\ref{sec:metodo}) y el firmware 0.6.3. Es el paso 7 de la Ruta a producción (entre «Gerber» y «Piloto») y la respuesta a la pregunta de Leo: «¿se piden hoy?».\\ +\rowcolor{HelgenMist} 1.0 (13:30) & 2026-10-22 & Re-verificación sobre los archivos que Leo guardó a las 13:00 (V5.6 \texttt{338ee14b}, V5.7 \texttt{85baca51}; paquetes regenerados a las 13:00): el relleno guardado ya es el fresco (P-1 cerrado, falta el commit), el cobre y los 11 Gerber + taladros son idénticos a los auditados, BOM y CPL iguales byte a byte. El veredicto no cambia. §\ref{sec:paquete}, al final.\\ +\bottomrule +\end{tabular}} + +\begin{helgennotice}[Cómo leer este documento en cinco minutos] +§\ref{sec:resumen} trae el veredicto y las tres condiciones del pedido. §\ref{sec:hallazgos} es la tabla +problema $\to$ arreglo. §\ref{sec:riesgos} es la matriz de riesgo. Lo demás es la evidencia: paquete +(§\ref{sec:paquete}), electrónica (§\ref{sec:electrica}), batería y ciclo de 10 min (§\ref{sec:bateria}), +cobre (§\ref{sec:cobre}) y firmware con sus algoritmos (§\ref{sec:firmware}). El protocolo con el que se hizo +(«reprompt») es \path{2026-10-22_Drogheda_Auditoria-Final-Produccion_V5.6-V5.7_Protocolo_ES_v1.0.md}. +\end{helgennotice} + +{\small\tableofcontents} +\clearpage + +\input{sec1-resumen.tex} +\input{sec2-metodo.tex} +\input{sec3-paquete.tex} +\input{sec4-electrica.tex} +\input{sec5-bateria.tex} +\input{sec6-cobre.tex} +\input{sec7-firmware.tex} +\input{sec8-hallazgos.tex} +\input{sec9-riesgos.tex} +\input{sec10-plan.tex} +\input{apendices.tex} + +\end{document} diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/estilo-helgen.tex b/03-Architecture-Hardware/Auditoria-Final-V56-V57/estilo-helgen.tex new file mode 100644 index 0000000..328e489 --- /dev/null +++ b/03-Architecture-Hardware/Auditoria-Final-V56-V57/estilo-helgen.tex @@ -0,0 +1,117 @@ +% ---------- Estilo de marca Helgen (compartido, Project Drogheda) ---------- +% Reutiliza la identidad de Project Ennis (_estilo-helgen.tex). Cada documento define +% \sistema, \sistemapdf y \doctipo antes de \input{...}. Compilar con XeLaTeX. +% ---------- Geometría y base ---------- +\usepackage[letterpaper, margin=2.4cm, headheight=14pt]{geometry} +\usepackage{polyglossia} +\setmainlanguage[variant=mexican]{spanish} +\usepackage{xcolor} +\usepackage{colortbl} +\usepackage{graphicx} +\usepackage{booktabs} +\usepackage{array} +\usepackage{tabularx} +\usepackage{enumitem} +\usepackage{titlesec} +\usepackage{float} +\usepackage{fancyhdr} +\usepackage{tikz} +\usetikzlibrary{arrows.meta, positioning, shapes.misc, calc, fit, automata} +\usepackage{caption} +\captionsetup{font=small, labelfont={bf,color=HelgenIndigo}} +\usepackage{microtype} +\setlength{\emergencystretch}{3em}\tolerance=2000\hbadness=2000 +\usepackage{hyperref} +\usepackage{textcomp} +\usepackage{ragged2e} +\usepackage{xltabular} +\usepackage[export]{adjustbox} +\usepackage[most]{tcolorbox} + +\providecommand{\sistema}{Helgen Drogheda} +\providecommand{\sistemapdf}{Helgen Drogheda} +\providecommand{\doctipo}{Documento} + +% ---------- Paleta oficial Helgen ---------- +\definecolor{HelgenIndigo}{HTML}{2C3C5B} +\definecolor{HelgenCyan}{HTML}{51F3DA} +\definecolor{HelgenTeal}{HTML}{17A08C} +\definecolor{HelgenMist}{HTML}{EFF1F5} +\definecolor{HelgenLightCyan}{HTML}{E7FCF8} +\definecolor{HelgenLightIndigo}{HTML}{EDEFF4} + +\newtcolorbox{helgennotice}[1][Aviso]{enhanced,breakable,colback=HelgenLightCyan,colframe=HelgenIndigo,boxrule=0.6pt,arc=2pt,left=9pt,right=9pt,top=7pt,bottom=7pt,coltitle=white,colbacktitle=HelgenIndigo,fonttitle=\helgentitle\bfseries\small,title={#1}} +\newcommand{\hwtab}[1]{\begin{center}\footnotesize\renewcommand{\arraystretch}{1.25}#1\end{center}} + +\hypersetup{colorlinks=true, linkcolor=HelgenTeal, urlcolor=HelgenTeal, pdftitle={\sistemapdf{} - \doctipo}, pdfauthor={Dr. Leopoldo Rodríguez Salazar (Helgen Technologies)}} + +% ---------- Tipografía de marca (XeLaTeX) ---------- +\usepackage{iftex} +\ifXeTeX + \usepackage{fontspec} + \IfFontExistsTF{MADE Evolve Sans}{\setmainfont{MADE Evolve Sans}[AutoFakeSlant=0.18]}{\setmainfont{Latin Modern Sans}[AutoFakeSlant=0.18]} + \IfFontExistsTF{League Spartan}{\newfontfamily\helgentitle{League Spartan}[BoldFont={League Spartan SemiBold}]}{\newcommand{\helgentitle}{\sffamily\bfseries}} +\else + \usepackage[T1]{fontenc} + \renewcommand{\familydefault}{\sfdefault} + \newcommand{\helgentitle}{\sffamily\bfseries} +\fi + +% ---------- Color de texto global ---------- +\color{HelgenIndigo} + +% ---------- Títulos de sección ---------- +\titleformat{\section}{\helgentitle\Large\bfseries\color{HelgenIndigo}}{\thesection}{0.8em}{}[{\color{HelgenCyan}\titlerule[1.6pt]}] +\titleformat{\subsection}{\helgentitle\large\bfseries\color{HelgenIndigo}}{\thesubsection}{0.8em}{} +\titleformat{\subsubsection}{\helgentitle\normalsize\bfseries\color{HelgenIndigo}}{\thesubsubsection}{0.8em}{} +\titlespacing{\section}{0pt}{18pt}{10pt} + +% ---------- Encabezado / pie ---------- +\pagestyle{fancy} +\fancyhf{} +\fancyhead[L]{\helgentitle\small\color{HelgenIndigo}\textbf{\sistema} — \doctipo} +\fancyhead[R]{\helgentitle\small\color{HelgenIndigo}Hutchison Ports · ICAVE} +\fancyfoot[L]{\helgentitle\scriptsize\color{gray}Confidencial — Helgen Servicios Especializados S.A. de C.V.} +\fancyfoot[R]{\helgentitle\scriptsize\color{HelgenIndigo}\thepage} +\renewcommand{\headrulewidth}{0.4pt} +\renewcommand{\headrule}{\color{HelgenCyan}\hrule width\headwidth height 1.2pt} + +% ---------- Estilos TikZ Helgen ---------- +\tikzset{ + caja/.style={draw=HelgenIndigo, fill=HelgenMist, rounded corners=2pt, text=HelgenIndigo, + align=center, font=\small, inner sep=5pt, minimum height=9mm}, + cajaoscura/.style={draw=HelgenIndigo, fill=HelgenIndigo, rounded corners=2pt, text=white, + align=center, font=\small\bfseries, inner sep=5pt, minimum height=9mm}, + zona/.style={draw=HelgenIndigo!50, dashed, rounded corners=4pt, inner sep=8pt}, + etiqueta/.style={font=\scriptsize\bfseries, text=HelgenTeal}, + flecha/.style={-{Stealth[length=2.6mm]}, thick, draw=HelgenIndigo}, + flechaacento/.style={-{Stealth[length=2.6mm]}, very thick, draw=HelgenTeal}, +} + +\newcolumntype{L}[1]{>{\raggedright\arraybackslash}p{#1}} +\newcolumntype{C}[1]{>{\centering\arraybackslash}p{#1}} + +% ---------- Listas con viñeta de marca ---------- +\setlist[itemize]{label={\textcolor{HelgenTeal}{\rule[0.18ex]{0.5em}{0.5em}}}, leftmargin=1.4em, itemsep=2pt} + +% ---------- Portada de marca (comando reutilizable) ---------- +% Uso: \helgenportada{Título}{Subtítulo cian}{Bloque de metadatos (tabular)} +\newcommand{\helgenportada}[3]{% +\begin{titlepage} +\begin{tikzpicture}[remember picture, overlay] + \fill[HelgenIndigo] (current page.south west) rectangle (current page.north east); + \draw[HelgenCyan, line width=2.5pt] ([xshift=2.4cm, yshift=-8.1cm]current page.north west) -- ([xshift=-2.4cm, yshift=-8.1cm]current page.north east); + \node[anchor=north west, text=white] at ([xshift=2.4cm, yshift=-3.2cm]current page.north west) + {\helgentitle\fontsize{30}{34}\selectfont Helgen}; + \node[anchor=north west, text=HelgenCyan] at ([xshift=2.4cm, yshift=-4.4cm]current page.north west) + {\helgentitle\small Ingeniería que produce, mantenimiento que protege}; + \node[anchor=north west, text=white, text width=16.5cm] at ([xshift=2.4cm, yshift=-9.0cm]current page.north west) + {\helgentitle\fontsize{24}{30}\selectfont #1\\[6pt] + \helgentitle\fontsize{14}{19}\selectfont\color{HelgenCyan} #2}; + \node[anchor=north west, text=white, text width=16.5cm] at ([xshift=2.4cm, yshift=-12.6cm]current page.north west) + {\helgentitle\fontsize{18}{22}\selectfont \sistema\\[5pt] + \normalsize Fleet RTK GPS — Hutchison Ports (ICAVE · TIMSA · EIT · LCT)}; + \node[anchor=south west, text=white] at ([xshift=2.4cm, yshift=2.2cm]current page.south west) + {\footnotesize\helgentitle #3}; +\end{tikzpicture} +\end{titlepage}} diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/fig/fig-autonomia.png b/03-Architecture-Hardware/Auditoria-Final-V56-V57/fig/fig-autonomia.png new file mode 100644 index 0000000..d5a01c4 Binary files /dev/null and b/03-Architecture-Hardware/Auditoria-Final-V56-V57/fig/fig-autonomia.png differ diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/fig/fig-matriz-riesgo.png b/03-Architecture-Hardware/Auditoria-Final-V56-V57/fig/fig-matriz-riesgo.png new file mode 100644 index 0000000..85382e5 Binary files /dev/null and b/03-Architecture-Hardware/Auditoria-Final-V56-V57/fig/fig-matriz-riesgo.png differ diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/fig/fig-relleno-viejo.png b/03-Architecture-Hardware/Auditoria-Final-V56-V57/fig/fig-relleno-viejo.png new file mode 100644 index 0000000..cdc3d28 Binary files /dev/null and b/03-Architecture-Hardware/Auditoria-Final-V56-V57/fig/fig-relleno-viejo.png differ diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/fig/fig-rs1-kelvin.png b/03-Architecture-Hardware/Auditoria-Final-V56-V57/fig/fig-rs1-kelvin.png new file mode 100644 index 0000000..866230a Binary files /dev/null and b/03-Architecture-Hardware/Auditoria-Final-V56-V57/fig/fig-rs1-kelvin.png differ diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/fig/fig-u6-pasta.png b/03-Architecture-Hardware/Auditoria-Final-V56-V57/fig/fig-u6-pasta.png new file mode 100644 index 0000000..45b0320 Binary files /dev/null and b/03-Architecture-Hardware/Auditoria-Final-V56-V57/fig/fig-u6-pasta.png differ diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/fig/fig-v56-top.png b/03-Architecture-Hardware/Auditoria-Final-V56-V57/fig/fig-v56-top.png new file mode 100644 index 0000000..435a41f Binary files /dev/null and b/03-Architecture-Hardware/Auditoria-Final-V56-V57/fig/fig-v56-top.png differ diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/fig/fig-v57-fuente.png b/03-Architecture-Hardware/Auditoria-Final-V56-V57/fig/fig-v57-fuente.png new file mode 100644 index 0000000..1762483 Binary files /dev/null and b/03-Architecture-Hardware/Auditoria-Final-V56-V57/fig/fig-v57-fuente.png differ diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/fig/fig-v57-top.png b/03-Architecture-Hardware/Auditoria-Final-V56-V57/fig/fig-v57-top.png new file mode 100644 index 0000000..a798bd8 Binary files /dev/null and b/03-Architecture-Hardware/Auditoria-Final-V56-V57/fig/fig-v57-top.png differ diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/presentacion.tex b/03-Architecture-Hardware/Auditoria-Final-V56-V57/presentacion.tex new file mode 100644 index 0000000..bb241b4 --- /dev/null +++ b/03-Architecture-Hardware/Auditoria-Final-V56-V57/presentacion.tex @@ -0,0 +1,407 @@ +% Helgen Technologies — Auditoría final de producción V5.6 / V5.7 (Beamer / Metropolis) +% Compilar: latexmk -xelatex presentacion.tex +\documentclass[10pt,aspectratio=169]{beamer} +\usetheme[progressbar=frametitle, numbering=fraction, block=fill]{metropolis} + +\definecolor{HelgenIndigo}{HTML}{2C3C5B} +\definecolor{HelgenCyan}{HTML}{51F3DA} +\definecolor{HelgenTeal}{HTML}{17A08C} +\definecolor{HelgenMist}{HTML}{EFF1F5} +\setbeamercolor{normal text}{fg=HelgenIndigo, bg=white} +\setbeamercolor{alerted text}{fg=HelgenTeal} +\setbeamercolor{frametitle}{bg=HelgenIndigo, fg=white} +\setbeamercolor{progress bar}{fg=HelgenCyan, bg=HelgenMist} +\setbeamercolor{title separator}{fg=HelgenCyan} +\setbeamercolor{block title}{bg=HelgenMist, fg=HelgenIndigo} +\setbeamertemplate{itemize item}{\textcolor{HelgenTeal}{\rule[0.18ex]{0.45em}{0.45em}}} +\setbeamertemplate{itemize subitem}{\textcolor{HelgenTeal}{\rule[0.18ex]{0.3em}{0.3em}}} +\setbeamertemplate{enumerate items}[default] + +\usepackage{iftex} +\ifXeTeX + \usepackage{fontspec} + \IfFontExistsTF{League Spartan}{% + \newfontfamily\helgentitle{League Spartan}[BoldFont={* Bold}] + \setbeamerfont{title}{family=\helgentitle, series=\bfseries} + \setbeamerfont{frametitle}{family=\helgentitle, series=\bfseries} + \setbeamerfont{section title}{family=\helgentitle, series=\bfseries} + \setbeamerfont{standout}{family=\helgentitle, series=\bfseries} + }{} + \IfFontExistsTF{MADE Evolve Sans}{\setsansfont{MADE Evolve Sans}}{} +\else + \usepackage[T1]{fontenc} +\fi +\usepackage{booktabs} +\usepackage{colortbl} +\usepackage{tikz} +\usetikzlibrary{arrows.meta, positioning, shapes.misc, automata} +\usepackage{graphicx} +\usepackage{amssymb} +\newcommand{\refdes}[1]{\texttt{#1}} +\newcommand{\sevA}{\textcolor{red!75!black}{$\blacksquare$}} +\newcommand{\sevB}{\textcolor{orange!90!black}{$\blacksquare$}} +\newcommand{\sevC}{\textcolor{yellow!65!orange}{$\blacksquare$}} +\newcommand{\sevD}{\textcolor{green!60!black}{$\blacksquare$}} +\newcommand{\ok}{\textcolor{HelgenTeal}{$\checkmark$}} + +\setbeamertemplate{frame footer}{% + \scriptsize\color{gray}\insertshortauthor\ $\cdot$ \insertshorttitle\ $\cdot$ Confidencial — Helgen Servicios Especializados} + +\title{Auditoría final de producción} +\subtitle{EinarBoard V5.6 $\cdot$ V5.7 — ¿se piden hoy?} +\author[Helgen CTO/CSO]{Project Drogheda — Helgen Technologies} +\date{22 de octubre de 2026, 13:30 — re-verificada sobre los archivos de las 13:00} + +\begin{document} +\maketitle + +\begin{frame}{Veredicto} + \begin{columns}[T] + \column{0.58\textwidth} + \begin{alertblock}{GO al piloto: 5 V5.6 + 5 V5.7, hoy} + Gerber = cobre de la pasada 6 con relleno fresco, \textbf{re-verificado a las 13:00 sobre los archivos nuevos} $\cdot$ DRC 0 / sin conectar 0 / paridad OK $\cdot$ RS1 Kelvin $\cdot$ BOM 100 \% LCSC $\cdot$ CPL cuadra. + \end{alertblock} + \begin{block}{Tres condiciones del pedido (sin tocar cobre)} + \begin{enumerate} + \item Vías \emph{Epoxy Filled \& Capped} + rayos X en \refdes{U6} + \item Rotación y polaridad en el visor de JLC: U6, U7, U25, U26, L22, Q7, U16, D34, D10, electrolíticos + \item BOM: \refdes{D10} SMBJ33A $\to$ SMBJ33CA + \end{enumerate} + \end{block} + \column{0.40\textwidth} + \begin{block}{NO-GO para 108 / 322} + Hasta que el piloto pase el banco con \textbf{0.7.0}: hoy ningún firmware enciende el módem de estas tarjetas. + \end{block} + \begin{block}{Camino crítico} + Ya no es el PCB, es 0.7.0: \texttt{board\_v56.h} entregado, 0.7.0-pre en 1 día. \ok\ P-1 cerrado 13:00. + \end{block} + \end{columns} +\end{frame} + +\begin{frame}{El mandato de Leo, punto por punto} + \small + \begin{tabular}{@{}p{4.5cm}p{2.0cm}p{5.9cm}@{}} + \toprule + \textbf{Pidió} & \textbf{Estado} & \textbf{Evidencia}\\ + \midrule + Que todos los puertos funcionen & \alert{HW sí} / FW no & Netlist contra hojas de datos; falta SC16IS752 y Ethernet de campo\\ + V5.7 sin la Mean Well & \alert{Sí} & U25 5.32 V / 600 kHz, 9--32 V; banco a 9/24/32 V\\ + Ethernet, RS-485, RS-232 usables & \alert{Usables} & RS-485 toma el bus $\sim$1 s al arrancar; H4 y P16 nunca juntos\\ + Módem sin apagón & \alert{Resuelto en HW} & AP64350 desde 3.8 V, boost 2.5 A vs 1.8 A pico, PFI 4.40 V\\ + 10 min dormida, 2 reportes, dormir & \alert{HW sí} / FW no & STOP + RTC (LSE), INT1 del SC7A20, MODEM\_EN; piso $\approx$ 75 mW\\ + Gerber/BOM/CPL generados & \alert{Verificados} & 0.000 mm$^2$ de diferencia contra relleno fresco\\ + Empezar el firmware & \alert{Empezado} & \texttt{board\_v56.h} (64 pines) + especificación 0.7.0\\ + Riesgos, easy wins, matriz & \alert{Hecho} & 30 hallazgos, 16 riesgos, 6 easy wins\\ + \bottomrule + \end{tabular} +\end{frame} + +\begin{frame}{Método: A--G, todo sobre copias, nada se movió} + \begin{columns}[T] + \column{0.5\textwidth} + \begin{itemize} + \item \textbf{A} Paquete: regenerar con \texttt{kicad-cli} y comparar primitiva por primitiva; relleno fresco con el proyecto cargado + \item \textbf{B} Eléctrica: netlist de cada esquemático contra hojas de datos + \item \textbf{C} Batería: presupuesto, piso dormido, secuencia + \item \textbf{D} Cobre: DRC + paridad, Kelvin, vías de corte, capas internas + \end{itemize} + \column{0.5\textwidth} + \begin{itemize} + \item \textbf{E} Firmware: 0.6.3 vs hardware nuevo; \texttt{board\_v56.h}; algoritmos + \item \textbf{F} Riesgo: matriz 5 × 5 antes/después + \item \textbf{G} Entrega y cierre en el centro de mando + \end{itemize} + \begin{block}{Insumos (SHA-256)} + Mañana: \texttt{f07ad5b5} / \texttt{9373ebe8}. \textbf{13:00:} \texttt{338ee14b} / \texttt{85baca51}, paquetes nuevos: mismo cobre, relleno ya en el repo. KiCad 10.0.4. + \end{block} + \end{columns} +\end{frame} + +\begin{frame}{V5.6 — lo que se fabrica} + \centering\includegraphics[height=0.82\textheight]{fig/fig-v56-top.png} +\end{frame} + +\begin{frame}{V5.7 — lo que se fabrica} + \centering\includegraphics[height=0.82\textheight]{fig/fig-v57-top.png} +\end{frame} + +\begin{frame}{A $\cdot$ ¿Los Gerber son el cobre auditado? Sí — y el hallazgo de proceso ya quedó cerrado} + \begin{columns}[T] + \column{0.46\textwidth} + \begin{itemize}\small + \item Máscaras, pasta, serigrafía, contorno, taladros: \textbf{idénticos} + \item Cobre: pads y pistas \textbf{idénticos}; rellenos \textbf{0.000 mm$^2$} contra un relleno fresco con reglas del proyecto + \item \alert{P-1} (mañana): el repo traía el relleno de la pasada 5; el Toolkit rellenó al exportar, \texttt{kicad-cli} no lo haría + \item \ok\ \textbf{13:00:} rellenado, guardado y paquetes regenerados $\to$ 0.000 mm$^2$ en las dos. Falta el commit. Regla D-22-3: B antes de cada commit + \end{itemize} + \column{0.54\textwidth} + \includegraphics[width=\linewidth]{fig/fig-relleno-viejo.png} + \end{columns} +\end{frame} + +\begin{frame}{A $\cdot$ Re-verificación de las 13:00: mismo cobre, relleno ya en el repo} + \begin{columns}[T] + \column{0.62\textwidth} + \footnotesize + \begin{tabular}{@{}p{4.9cm}p{1.7cm}p{1.7cm}@{}} + \toprule + \textbf{Comparación (4 capas de cobre, 20 $\mu$m)} & \textbf{V5.6} & \textbf{V5.7}\\ + \midrule + A $\cdot$ relleno guardado vs fresco con el proyecto (P-1) & 0.000 mm$^2$ & 0.000 mm$^2$\\ + B $\cdot$ paquete 13:00 vs archivo guardado & idéntico & idéntico\\ + C $\cdot$ cobre 13:00 vs cobre auditado en la mañana & idéntico & idéntico\\ + D $\cdot$ paquete 13:00 vs paquete de la mañana (11 capas + taladros) & idéntico & idéntico\\ + DRC (\texttt{.kicad\_dru}, relleno, paridad) & 3 MOD1 $\cdot$ 0 $\cdot$ PF & 3 MOD1 $\cdot$ 0 $\cdot$ PF\\ + BOM y CPL (SHA-256) & iguales & iguales\\ + \bottomrule + \end{tabular} + \par\medskip + Pistas / vías: 2264 / 396 (V5.6) y 2253 / 403 (V5.7), sin cambios. Lo único distinto en los archivos es la caché de glifos del texto «EINARBoard 5.x»: cosmético, la serigrafía exportada es idéntica. + \column{0.38\textwidth} + \begin{block}{Qué quiere decir} + El veredicto de la mañana sigue tal cual. P-1 pasa a cerrado. La condición 3 sigue viva: el BOM del paquete aún dice \refdes{D10} = SMBJ33A. + \end{block} + \begin{block}{Para la próxima vez} + \texttt{verify.sh} + \texttt{gcmp\_b.py}: 5 min después de cualquier cambio, antes de pagar. Quick wins en curso en otra sesión: re-correr al terminar. + \end{block} + \end{columns} +\end{frame} + +\begin{frame}{A $\cdot$ La condición 1: U6 y la pasta} + \begin{columns}[T] + \column{0.46\textwidth} + \begin{itemize} + \item \refdes{U6} LTC4040, QFN-24 a 0.5 mm: el defecto más visto en V5.5/V4 (puentes, bolas) + \item Pasta al 50 \% (regla del 8-oct) $\cdot$ pero las \textbf{3 vías térmicas caen dentro de las ventanas} + \item \refdes{U7} y \refdes{U25}: pasta al 100 \% con 4 / 6 vías en el pad + \item \textbf{Pedido:} Via covering = Epoxy Filled \& Capped $\cdot$ rayos X en U6 $\cdot$ ENIG $\cdot$ lupa 10× antes de energizar + \end{itemize} + \column{0.54\textwidth} + \includegraphics[width=\linewidth]{fig/fig-u6-pasta.png} + \end{columns} +\end{frame} + +\begin{frame}{A $\cdot$ Condiciones 2 y 3: rotaciones y D10} + \begin{columns}[T] + \column{0.5\textwidth} + \begin{block}{Rotaciones (P-3)} + El Toolkit corrige huellas KiCad (QFN, SOIC, LQFP, SOT, electrolíticos) como en V5.5. Las easyeda2kicad (\refdes{U7}, \refdes{U25}, \refdes{U26}, \refdes{L22}) y \refdes{D34} salen sin corrección: \textbf{nunca fabricadas}. Confirmar pin 1 / cátodo en el visor. + \end{block} + \column{0.5\textwidth} + \begin{block}{D10 SMBJ33A $\to$ SMBJ33CA (P-4)} + Arnés al revés: Q10 bloquea, pero el TVS unidireccional conduce y \textbf{abre F2} (SMD, no se cambia en campo). Bidireccional, misma huella, una línea de BOM (C8838 / C2688178). + \end{block} + \begin{block}{Otros easy wins de BOM} + 10 nF en un solo código (C1589) $\cdot$ etiqueta de C22 (es 10 $\mu$F/50 V) $\cdot$ THVD1410 / TRS3232E en la pre-orden de las 108 / 322 + \end{block} + \end{columns} +\end{frame} + +\begin{frame}{B $\cdot$ Cargador, respaldo y riel del módem: verificados contra hoja de datos} + \small + \begin{tabular}{@{}p{3.2cm}p{3.2cm}p{6.1cm}@{}} + \toprule + \textbf{Función} & \textbf{Valor} & \textbf{Piezas}\\ + \midrule + PFI (a batería) & 4.40 V cae / 4.51 sube & R51 270k / R52 100k, ref. 1.19 V\\ + VSYS en respaldo & 4.79 V & R53 499k / R54 100k, ref. 0.8 V\\ + Límite de entrada & 2.5 A & RS1 10 m$\Omega$ \textbf{Kelvin} (VIN y CLN comprobados)\\ + Carga / flotación & 1.40 A / 3.50 V LFP & R50 1.43k; JP2 2-3, F1 = 0, F0 = 1\\ + Ventana NTC & +10 … +60 °C & R55 5.6k desde VIN (ratiométrico), B3380\\ + Riel del módem & 3.33 V, 500 kHz, desde 3.8 V & AP64350, L7 4.7 $\mu$H, C43 220 $\mu$F, EN = PC3 (off por defecto)\\ + Respaldo disponible & 2.5 A = 12 W & contra 8.7 W de pico (módem 2 A a 3.3 V)\\ + \bottomrule + \end{tabular} + \begin{alertblock}{Por qué ya no hay apagón} + V5.5: MP1584 pedía 4.5 V sobre un riel de 4.6 V. V5.6/V5.7: AP64350 regula desde 3.8 V con 1 V de margen. Lo que queda es secuencia (firmware): etapa $\to$ NMEA $\to$ módem. + \end{alertblock} +\end{frame} + +\begin{frame}{B $\cdot$ V5.7: fuente de 9 a 32 V} + \begin{columns}[T] + \column{0.5\textwidth} + \begin{itemize} + \item P1 $\to$ F2 3 A lento $\to$ D10 + Q10 (polaridad) $\to$ U25 TPS54360B + \item 5.32 V (57.6k / 10.2k), 600 kHz (162k), comp. 13k / 6.8 nF / 39 pF, EN flotante + \item L22 10 $\mu$H (15.5 A sat.), D34 B560C ($\approx$ 1.2 W a 24 V / 2.8 A) + \item Rango continuo \textbf{9--32 V}; a 9 V entran 1.9 A + \item Lazo de entrada 56 mm$^2$ sobre plano sólido (D-21-2): \textbf{se mide el timbre} + \item Vía única de 24 V (182.4, 68.1): 0.7 A a 24 V; cámara térmica a 9 V + \end{itemize} + \column{0.5\textwidth} + \includegraphics[width=\linewidth]{fig/fig-v57-fuente.png} + \end{columns} +\end{frame} + +\begin{frame}{B $\cdot$ Puertos: usables, con dos reglas y un pendiente de firmware} + \small + \begin{tabular}{@{}p{1.9cm}p{4.7cm}p{5.8cm}@{}} + \toprule + \textbf{Puerto} & \textbf{Hardware} & \textbf{Regla / hallazgo}\\ + \midrule + Ethernet J10 & W5500 SPI2, RST con pull-down, PMODE auto & J10.8 al aire y LED ACT invertido (cosmético). En batería: PHY power-down (13 mA) — no hay enable del riel (E-3)\\ + RS-485 P15 & SP3485, DE = $\overline{\mathrm{RE}}$ = $\overline{\mathrm{RTSA}}$ de U10 & \textbf{Transmisor encendido desde el reset hasta que 0.7.0 escribe EFCR}: punto a punto o tolerar $\sim$1 s. Sin TVS ni polarización: THVD1410 para 108/322 (E-4)\\ + RS-232 P16 & MAX3232 a 3.3 V, canal 2 a tierra & H4 (TTL) y P16 comparten RXB: nunca juntos (E-5)\\ + USB J11 / J9 & DFU del MCU / paso al módem & Como V5.5\\ + I$^2$C & SHT40, TMP102 ×2 (cargador y módem), SC16IS752, PCF8574, SC7A20 (WHO\_AM\_I 0x11, INT1 PB9) & Un solo bus, 6 esclavos\\ + Ignición PA5 & ×0.1154: 12 V $\to$ 1.38 V & \textbf{ADC}, no digitalRead (E-7)\\ + \bottomrule + \end{tabular} +\end{frame} + +\begin{frame}{C $\cdot$ Batería: presupuesto y piso dormido} + \begin{columns}[T] + \column{0.48\textwidth} + \begin{block}{Ventana encendida} + Etapa 0.7 W $\cdot$ módem 1.5 W (pico 7.3) $\cdot$ MCU 0.5 W $\cdot$ W5500 PD 0.05 W $\cdot$ K1 0.15 W $\Rightarrow$ \textbf{2.9 W promedio, 8.7 W pico} (1.8 A de 2.5 A) + \end{block} + \begin{block}{Piso dormido (estimado)} + W5500 en PD 50 mW $\cdot$ MAX3232 + SP3485 4 mW $\cdot$ LED D18 4 mW $\cdot$ MCU STOP 1.5 mW $\cdot$ resto 2 mW $\Rightarrow$ \textbf{$\approx$ 75 mW}. Sin PD del W5500: 450 mW. + \end{block} + \begin{block}{Qué manda} + La ventana y el piso, no el periodo. 45 s cada 10 min: $\approx$ 5 días; cada 20 min: $\approx$ 8.5 días. + \end{block} + \column{0.52\textwidth} + \includegraphics[width=\linewidth]{fig/fig-autonomia.png} + \end{columns} +\end{frame} + +\begin{frame}{C $\cdot$ El ciclo de 10 minutos (0.7.0)} + \centering + \begin{tikzpicture}[node distance=4mm and 3mm, font=\scriptsize, + paso/.style={draw=HelgenIndigo, fill=HelgenMist, rounded corners=2pt, text width=25mm, minimum height=10mm, align=center, inner sep=2pt}, + acento/.style={draw=HelgenIndigo, fill=HelgenIndigo, text=white, rounded corners=2pt, text width=25mm, minimum height=10mm, align=center, inner sep=2pt}, + arr/.style={-{Stealth}, thick, HelgenTeal}] + \node[paso] (a) {\textbf{1 Respaldo}\\5V\_SENSE $<$ 4.2 V (media 200 ms)}; + \node[paso, right=of a] (b) {\textbf{2 Última palabra}\\\$PHLG + posición; TX vacío}; + \node[paso, right=of b] (c) {\textbf{3 Apagar}\\MODEM\_EN = 0, PA1 = 0, K1 suelto, UARTs hi-Z, W5500 PD}; + \node[acento, right=of c] (d) {\textbf{4 STOP}\\RTC 10 min (LSE / LSI) $\cdot$ INT1 $\cdot$ 24 V}; + \node[paso, below=of d] (e) {\textbf{5 Despertar}\\vbat $<$ 2.95 V $\to$ dormir otra vez}; + \node[paso, left=of e] (f) {\textbf{6 Etapa ON}\\PA1 = 1 (rampa 20 ms); NMEA $\le$ 30 s}; + \node[paso, left=of f] (g) {\textbf{7 Módem ON}\\+2 s MODEM\_EN; LED/RTCM $\le$ 90 s o pulso RST}; + \node[paso, left=of g] (h) {\textbf{8 Reportar}\\K1; 2 × \$PHLG/\$PHCG pwr = BATT; \$PHEV con tiempos}; + \draw[arr] (a)--(b); \draw[arr] (b)--(c); \draw[arr] (c)--(d); \draw[arr] (d)--(e); \draw[arr] (e)--(f); \draw[arr] (f)--(g); \draw[arr] (g)--(h); + \draw[arr, dashed] (h.north) -- ++(0,1.5mm) -| (c.south); + \end{tikzpicture} + \vspace{2mm} + \begin{itemize}\small + \item Umbrales \textbf{LFP}: corte 2.95 V, rearme 3.20 V (0.6.3 trae 3.40 / 3.70 de Li-ion) $\cdot$ SoC por culombios + \item Ventana meta $\le$ 60 s $\cdot$ posición guardada con bandera de antigüedad $\cdot$ fix fresco solo si llega + \end{itemize} +\end{frame} + +\begin{frame}{D $\cdot$ Cobre: DRC limpio, RS1 Kelvin, vías únicas conocidas} + \begin{columns}[T] + \column{0.42\textwidth} + \begin{itemize} + \item DRC con \texttt{.kicad\_dru}, relleno y paridad: \textbf{3 errores} (MOD1, por diseño, excluidos), \textbf{0} sin conectar, paridad solo PWR\_FLAG — en las dos + \item RS1: VIN y CLN llegan \textbf{solo} a su pad (prueba recortando el pad) + \item Vías únicas: las aceptadas el 19/21-oct + dos notas: V5.7 (146.37, 86.96) lleva el LDO del MCU + U12 ($\approx$ 0.3 A); V5.7 24 V por dos vías 0.8/0.3 en serie + \item 0 mm de potencia en capas internas salvo la rama de R2 (permitida) + \end{itemize} + \column{0.58\textwidth} + \includegraphics[width=\linewidth]{fig/fig-rs1-kelvin.png} + \end{columns} +\end{frame} + +\begin{frame}{E $\cdot$ Firmware: 0.6.3 no sirve a V5.6/V5.7; board\_v56.h sí} + \begin{columns}[T] + \column{0.5\textwidth} + \begin{block}{Lo que 0.6.3 hace mal en V5.6} + No enciende el módem (PC3) $\cdot$ reset del módem por PCF P7 que ya no existe $\cdot$ NTC en PB1 que ya no existe $\cdot$ flotación 4.00 V (es 3.50) $\cdot$ corte 3.40/3.70 V (LFP: 2.95/3.20) $\cdot$ ignición por digitalRead + \end{block} + \begin{block}{Entregado hoy} + \texttt{board\_v56.h}: 64 pines del netlist (V5.6 = V5.7), umbrales del hardware como constantes, notas por pin nuevo (MODEM\_EN/RST/LED, RTCM\_TAP, ACC\_INT1, NTC\_CELL). + \end{block} + \column{0.5\textwidth} + \begin{block}{0.7.0: trabajo con tamaño} + \begin{itemize} + \item F-1 0.7.0-pre (módem, NTC, LFP, ADC): \textbf{1 día} + \item F-2 ciclo de respaldo STOP + RTC: 3--4 días + \item F-3 SC16IS752 + EFCR primero: 1 día + \item F-4 Ethernet de campo: 2 días + \item F-5..F-8 acelerómetro, vigilancia del módem, Modo B, recuperación: 2 días + \end{itemize} + \end{block} + \end{columns} +\end{frame} + +\begin{frame}{E $\cdot$ Los algoritmos de la tarjeta} + \begin{columns}[T] + \column{0.5\textwidth} + \begin{itemize}\small + \item \textbf{Gobernador de carga}: HOLDOFF 120 s $\to$ PROVING (riel $\ge$ 5.05 V 30 s) $\to$ ON $\to$ SHED ($<$ 4.70 V muestra, $<$ 4.90 V media 1 s) $\to$ COOLDOWN 60 s × 2$^n$ $\to$ WAIT; HOT $\ge$ 45 °C + \item \textbf{Recuperación de enlace}: gracia 90 s; sin NMEA 60 s $\to$ ciclo (1 / 5 min); RTK perdido 15 min $\to$ ciclo (1 / 30 min); 3 ciclos $\to$ LIMP + \item \textbf{Modo B}: K1 a los 10 s de NMEA; inyección solo en huecos $\ge$ 8 ms; \$PHLG $\le$ 100 caracteres; soltar antes de cortar + \end{itemize} + \column{0.5\textwidth} + \begin{itemize}\small + \item \textbf{Vigilancia del módem}: caída del riel por ventanas (30/50 mV) + edad del RTCM; 0.7.0: LED (PC2) + RTCM (PC7) + reset con límite + \item \textbf{Cortes}: térmico 60/55 °C; batería por media de 200 ms (LFP en 0.7.0) + \item \textbf{Medición}: ADC con VREFINT; mínimos de ventana y medias de 200 ms + \item \textbf{Supervisión}: IWDG 16 s; razón del reset en registros RTC; holdoff ×2$^n$ + \item \textbf{Ciclo de respaldo} (nuevo): STOP + RTC + INT1 + \end{itemize} + \end{columns} +\end{frame} + +\begin{frame}{Hallazgos: los que deciden} + \small + \begin{tabular}{@{}p{0.9cm}p{0.4cm}p{5.5cm}p{5.5cm}@{}} + \toprule + \textbf{Id} & & \textbf{Problema} & \textbf{Arreglo}\\ + \midrule + P-1 & \ok & Relleno viejo en el repo (mañana) & \textbf{Cerrado 13:00}: relleno fresco en los dos archivos; falta commit\\ + P-2 & \sevB & U6: 3 vías en la pasta & Epoxy Filled \& Capped + rayos X\\ + P-3 & \sevB & Rotación de huellas easyeda2kicad & Visor de JLC\\ + P-4 & \sevD & D10 unidireccional $\to$ F2 abre con el arnés al revés & SMBJ33CA\\ + E-3 & \sevB & W5500 sin enable: 65--132 mA en batería & PHY power-down (13 mA) en 0.7.0\\ + E-4 & \sevC & RS-485 toma el bus desde el reset; sin TVS & EFCR primero; THVD1410 para 108/322\\ + E-7 & \sevB & Ignición a 12 V en zona indefinida & ADC con histéresis\\ + E-9/10 & \sevC & U25: lazo 56 mm$^2$, vía única de 24 V & Banco 9/24/32 V, cámara térmica\\ + F-1 & \sevA & 0.6.3 no enciende el módem & 0.7.0-pre, 1 día\\ + F-2 & \sevB & Ciclo de 10 min y umbrales LFP & STOP + RTC, 2.95/3.20 V\\ + \bottomrule + \end{tabular} + \par\medskip 30 hallazgos en total (8 de pedido, 16 eléctricos, 8 de firmware); 6 easy wins. +\end{frame} + +\begin{frame}{Matriz de riesgo} + \centering\includegraphics[width=0.96\linewidth]{fig/fig-matriz-riesgo.png} +\end{frame} + +\begin{frame}{El pedido de hoy y el camino a las 108 / 322} + \begin{columns}[T] + \column{0.5\textwidth} + \begin{block}{Hoy ($\approx$ 40 min)} + \begin{enumerate} + \item BOM: D10 $\to$ SMBJ33CA (el \texttt{\_bom.csv} de las 13:00 aún dice SMBJ33A) + \item PCB: 4 capas, ENIG, \textbf{Epoxy Filled \& Capped} + \item Ensamble top; rayos X en U6 en las notas + \item Visor: pin 1, cátodos, «+» de electrolíticos + \item 5 + 5; número de orden al acta + \item \ok\ B y guardar ya están (13:00); falta commit de kicad/ y production/ + \end{enumerate} + \end{block} + \column{0.5\textwidth} + \begin{block}{Antes de las 108 / 322 (banco con 0.7.0)} + \begin{enumerate} + \item Lupa en U6 + autoprueba + \item 24 V: NMEA, registro, Kelvin (TP1 ÷ 32), carga 1.2--1.4 A + \item 20 ciclos de 10 min (paquete 20 \%, 45 °C): piso $<$ 100 mW + \item 20 cortes 24 V $\leftrightarrow$ batería sin reset + \item RS-485/RS-232 en lazo; Ethernet 24 h + \item V5.7: 9/12/24/32 V, polaridad, térmico + \item Temperaturas de U6, L6, L7 + \item Arneses, tapa, barrenos + \end{enumerate} + \end{block} + \end{columns} +\end{frame} + +\begin{frame}[standout] + GO al piloto 5 + 5 con tres condiciones.\\[3mm] + \small El cobre está listo y ya vive en el repo (P-1 cerrado); el camino crítico es 0.7.0. +\end{frame} + +\end{document} diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/scripts/copper.py b/03-Architecture-Hardware/Auditoria-Final-V56-V57/scripts/copper.py new file mode 100644 index 0000000..07d3493 --- /dev/null +++ b/03-Architecture-Hardware/Auditoria-Final-V56-V57/scripts/copper.py @@ -0,0 +1,150 @@ +import re, math, sys +from collections import defaultdict +def parse_pcb(path): + txt=open(path).read() + fps=[] + for m in re.finditer(r'\(footprint "([^"]+)"(.*?)\n\t\)\n', txt, re.S): + body=m.group(2) + ref=re.search(r'\(property "Reference" "([^"]+)"', body).group(1) + at=re.search(r'\n\t\t\(at (-?[\d.]+) (-?[\d.]+)(?: (-?[\d.]+))?\)', body) + fx,fy,frot=float(at.group(1)),float(at.group(2)),float(at.group(3) or 0) + layer=re.search(r'\(layer "([^"]+)"\)', body).group(1) + pads=[] + for p in re.finditer(r'\(pad "([^"]*)" (\w+) (\w+)\s*\(at (-?[\d.]+) (-?[\d.]+)(?: (-?[\d.]+))?\)\s*\(size ([\d.]+) ([\d.]+)\)(.*?)\n\t\t\)', body, re.S): + num,ptype,shape=p.group(1),p.group(2),p.group(3) + ox,oy,prot=float(p.group(4)),float(p.group(5)),float(p.group(6) or 0) + sx,sy=float(p.group(7)),float(p.group(8)) + rest=p.group(9) + lay=re.search(r'\(layers ([^)]*)\)', rest); lays=re.findall(r'"([^"]+)"', lay.group(1)) if lay else [] + net=re.search(r"\(net \"([^\"]*)\"\)", rest) + th=math.radians(frot) + px=fx+ox*math.cos(th)+oy*math.sin(th); py=fy-ox*math.sin(th)+oy*math.cos(th) + # pad absolute rotation = prot (kicad stores absolute rotation in pad 'at' for footprint pads) -> in v8+ pad rotation is relative? In KiCad 8/9 file, pad rotation is absolute (fp rot + pad rot). We'll treat prot as absolute. + pads.append(dict(ref=ref,num=num,type=ptype,shape=shape,x=px,y=py,rot=prot,sx=sx,sy=sy,layers=lays,net=net.group(1) if net else "")) + fps.append(dict(ref=ref,x=fx,y=fy,rot=frot,layer=layer,pads=pads)) + segs=[dict(x1=float(a),y1=float(b),x2=float(c),y2=float(d),w=float(w),layer=l,net=n) for a,b,c,d,w,l,n in re.findall(r'\(segment\s*\(start (-?[\d.]+) (-?[\d.]+)\)\s*\(end (-?[\d.]+) (-?[\d.]+)\)\s*\(width ([\d.]+)\)\s*\(layer "([^"]+)"\)\s*\(net "([^"]*)"\)', txt)] + arcs=re.findall(r'\(arc\s*\(start', txt) + vias=[dict(x=float(x),y=float(y),size=float(s),drill=float(d),layers=[l1,l2],net=n) for x,y,s,d,l1,l2,n in re.findall(r'\(via\s*\(at (-?[\d.]+) (-?[\d.]+)\)\s*\(size ([\d.]+)\)\s*\(drill ([\d.]+)\)\s*\(layers "([^"]+)" "([^"]+)"\)(?:\s*\([^)]*\))*?\s*\(net "([^"]*)"\)', txt)] + return fps,segs,vias,len(arcs) +COPPER=["F.Cu","In1.Cu","In2.Cu","B.Cu"] +def pad_layers(p): + out=set() + for l in p["layers"]: + if l=="*.Cu": out.update(COPPER) + elif l.endswith(".Cu"): out.add(l) + return out +def point_in_pad(x,y,p,tol=0.0): + # rotate point into pad frame + th=math.radians(p["rot"]); dx=x-p["x"]; dy=y-p["y"] + u= dx*math.cos(th)-dy*math.sin(th); w= dx*math.sin(th)+dy*math.cos(th) + # kicad y is down; rotation sign: try both conventions by testing symmetric sizes; use |u|<=sx/2 || |w|<=sy/2 with swapped if rot 90 + if abs(u)<=p["sx"]/2+tol and abs(w)<=p["sy"]/2+tol: return True + u2= dx*math.cos(th)+dy*math.sin(th); w2=-dx*math.sin(th)+dy*math.cos(th) + return abs(u2)<=p["sx"]/2+tol and abs(w2)<=p["sy"]/2+tol +def seg_dist(px,py,s): + x1,y1,x2,y2=s["x1"],s["y1"],s["x2"],s["y2"] + dx,dy=x2-x1,y2-y1; L2=dx*dx+dy*dy + t=0 if L2==0 else max(0,min(1,((px-x1)*dx+(py-y1)*dy)/L2)) + cx,cy=x1+t*dx,y1+t*dy + return math.hypot(px-cx,py-cy) +class UF: + def __init__(s): s.p={} + def f(s,a): + s.p.setdefault(a,a) + while s.p[a]!=a: s.p[a]=s.p[s.p[a]]; a=s.p[a] + return a + def u(s,a,b): s.p[s.f(a)]=s.f(b) +def build(net, fps, segs, vias, exclude_pads=(), exclude_vias=()): + items=[] + for f in fps: + for p in f["pads"]: + if p["net"]==net and (p["ref"],p["num"]) not in exclude_pads: items.append(("pad",p)) + for s in segs: + if s["net"]==net: items.append(("seg",s)) + for i,v in enumerate(vias): + if v["net"]==net and (round(v["x"],3),round(v["y"],3)) not in exclude_vias: items.append(("via",v)) + uf=UF() + n=len(items) + for i in range(n): uf.f(i) + for i in range(n): + ki,oi=items[i] + for j in range(i+1,n): + kj,oj=items[j] + if connected(ki,oi,kj,oj): uf.u(i,j) + return items,uf +def layers_of(k,o): + if k=="pad": return pad_layers(o) + if k=="seg": return {o["layer"]} + if k=="via": return set(COPPER) if o["layers"]==["F.Cu","B.Cu"] else set(o["layers"]) +def connected(ka,a,kb,b): + la,lb=layers_of(ka,a),layers_of(kb,b) + if not (la&lb): return False + if ka=="seg" and kb=="seg": + wa,wb=a["w"]/2,b["w"]/2 + for (x,y) in ((a["x1"],a["y1"]),(a["x2"],a["y2"])): + if seg_dist(x,y,b)<=wa+wb-0.001+0.002: return True + for (x,y) in ((b["x1"],b["y1"]),(b["x2"],b["y2"])): + if seg_dist(x,y,a)<=wa+wb-0.001+0.002: return True + return False + if ka=="seg" or kb=="seg": + s,o,ko=(a,b,kb) if ka=="seg" else (b,a,ka) + if ko=="via": + return seg_dist(o["x"],o["y"],s)<=s["w"]/2+o["size"]/2-0.001 + else: + for (x,y) in ((s["x1"],s["y1"]),(s["x2"],s["y2"])): + if point_in_pad(x,y,o,tol=s["w"]/2*0.0): return True + # also pad center near segment + return seg_dist(o["x"],o["y"],s)<=s["w"]/2+min(o["sx"],o["sy"])/2-0.001 + if ka=="via" and kb=="via": + return math.hypot(a["x"]-b["x"],a["y"]-b["y"])<=(a["size"]+b["size"])/2-0.001 + if ka=="via" or kb=="via": + v,p=(a,b) if ka=="via" else (b,a) + return point_in_pad(v["x"],v["y"],p,tol=v["size"]/2-0.001) + if ka=="pad" and kb=="pad": + return math.hypot(a["x"]-b["x"],a["y"]-b["y"])<=(min(a["sx"],a["sy"])+min(b["sx"],b["sy"]))/2-0.001 + return False +def comp_of(items,uf,key): + for i,(k,o) in enumerate(items): + if k=="pad" and (o["ref"],o["num"])==key: return uf.f(i) + return None + +def clip_segments_outside_rect(segs, net, x0,y0,x1,y1): + """Return segs with the parts inside the rect removed (Liang-Barsky), for a given net.""" + out=[] + for s in segs: + if s["net"]!=net: out.append(s); continue + ax,ay,bx,by=s["x1"],s["y1"],s["x2"],s["y2"] + ina = x0<=ax<=x1 and y0<=ay<=y1; inb = x0<=bx<=x1 and y0<=by<=y1 + if ina and inb: continue + if not ina and not inb: + # could cross the rect; check with Liang-Barsky + dx,dy=bx-ax,by-ay; t0,t1=0.0,1.0; ok=True + for p,q in ((-dx,ax-x0),(dx,x1-ax),(-dy,ay-y0),(dy,y1-ay)): + if p==0: + if q<0: ok=False; break + else: + t=q/p + if p<0: t0=max(t0,t) + else: t1=min(t1,t) + if ok and t00.001: out.append(dict(s,x1=ax,y1=ay,x2=ax+t*dx,y2=ay+t*dy)) + return out +def kelvin_test(fps,segs,vias,net,pad_ref,pad_num,sense_ref,sense_num): + pad=[p for f in fps for p in f["pads"] if (p["ref"],p["num"])==(pad_ref,pad_num)][0] + x0,y0,x1,y1=pad["x"]-pad["sx"]/2,pad["y"]-pad["sy"]/2,pad["x"]+pad["sx"]/2,pad["y"]+pad["sy"]/2 + segs2=clip_segments_outside_rect(segs,net,x0,y0,x1,y1) + vias2=[v for v in vias if not (v["net"]==net and x0<=v["x"]<=x1 and y0<=v["y"]<=y1)] + items,uf=build(net,fps,segs2,vias2,exclude_pads=((pad_ref,pad_num),)) + c=comp_of(items,uf,(sense_ref,sense_num)) + pads=[o["ref"]+"."+o["num"] for i,(k,o) in enumerate(items) if k=="pad" and uf.f(i)==c] + nvia=sum(1 for i,(k,o) in enumerate(items) if k=="via" and uf.f(i)==c) + return pads,nvia diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/scripts/gcmp.py b/03-Architecture-Hardware/Auditoria-Final-V56-V57/scripts/gcmp.py new file mode 100644 index 0000000..a4c4733 --- /dev/null +++ b/03-Architecture-Hardware/Auditoria-Final-V56-V57/scripts/gcmp.py @@ -0,0 +1,63 @@ +import re, sys +from PIL import Image, ImageDraw +import numpy as np +from scipy import ndimage +def regions(path): + inreg=False; regs=[]; cur=[]; x=y=0; pol="D" + for line in open(path, errors="replace"): + s=line.strip() + if s=="%LPC*%": pol="C" + if s=="%LPD*%": pol="D" + if s=="G36*": inreg=True; cur=[]; continue + if s=="G37*": inreg=False; regs.append((pol,cur)); continue + m=re.match(r"(?:X(-?\d+))?(?:Y(-?\d+))?D0([123])\*$",s) + if m: + nx=int(m.group(1)) if m.group(1) is not None else x; ny=int(m.group(2)) if m.group(2) is not None else y + if inreg: cur.append((nx,ny)) + x,y=nx,ny + return regs +def prims(path): + ap=None; inreg=False; x=y=0; flashes=set(); draws=set(); apdefs={} + for line in open(path, errors="replace"): + s=line.strip() + if s.startswith("G04") or s.startswith("%T"): continue + m=re.match(r"%ADD(\d+)(.*)\*%",s) + if m: apdefs[m.group(1)]=m.group(2); continue + if s=="G36*": inreg=True; continue + if s=="G37*": inreg=False; continue + m=re.match(r"D(\d+)\*$",s) + if m and int(m.group(1))>=10: ap=apdefs.get(m.group(1)); continue + m=re.match(r"(?:X(-?\d+))?(?:Y(-?\d+))?D0([123])\*$",s) + if m: + nx=int(m.group(1)) if m.group(1) is not None else x; ny=int(m.group(2)) if m.group(2) is not None else y + if not inreg: + if m.group(3)=="3": flashes.add((ap,nx,ny)) + elif m.group(3)=="1": draws.add((ap,x,y,nx,ny)) + x,y=nx,ny + return flashes,draws +SC=50; W,H=int(141*SC),int(101*SC) +def raster_regs(regs): + im=Image.new("1",(W,H),0); d=ImageDraw.Draw(im) + for pol,pts in regs: + d.polygon([((x/1e6-60)*SC,(-y/1e6-40)*SC) for x,y in pts], fill=1 if pol=="D" else 0) + return np.array(im) +def compare(a,b): + fa,da=prims(a); fb,db=prims(b) + ra=raster_regs(regions(a)); rb=raster_regs(regions(b)) + x=ra^rb + er=ndimage.binary_erosion(x, structure=np.ones((3,3))) + lab,n=ndimage.label(er) + blobs=[] + for i in range(1,n+1): + ys,xs=np.nonzero(lab==i) + if len(xs)<9: continue + blobs.append((len(xs)/SC/SC, round(xs.min()/SC+60,1),round(ys.min()/SC+40,1),round(xs.max()/SC+60,1),round(ys.max()/SC+40,1), "A-only" if ra[ys[0],xs[0]] else "B-only")) + blobs.sort(reverse=True) + return fa==fb, da==db, x.sum()/SC/SC, blobs +if __name__=="__main__": + base="../in/03-Architecture-Hardware/kicad" + for v,b,prod in (("v56","v5","HBOX_v5_Rev6_PROD"),("v57","v57","HBOX_v5_Rev7_PROD")): + print("=====",v) + for lay,e1 in (("F_Cu","gtl"),("In1_Cu","g1"),("In2_Cu","g2"),("B_Cu","gbl")): + fs,ds,xa,blobs=compare(f"{base}/production/{prod}/hbox-watchdog-{b}-{lay}.{e1}", f"{base}/_to_delete/audit-20261022/{v}/rf/gerber/hbox-watchdog-{b}-{lay}.gbr") + print(f" {lay:7s} flashes={fs} draws={ds} fill-xor={xa:.3f} mm2 blobs={len(blobs)}", [f"{a:.2f}@({x1},{y1})-({x2},{y2}){t}" for a,x1,y1,x2,y2,t in blobs[:5]]) diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/scripts/gcmp_b.py b/03-Architecture-Hardware/Auditoria-Final-V56-V57/scripts/gcmp_b.py new file mode 100644 index 0000000..c2a0168 --- /dev/null +++ b/03-Architecture-Hardware/Auditoria-Final-V56-V57/scripts/gcmp_b.py @@ -0,0 +1,30 @@ +import sys, hashlib +sys.path.insert(0, '.') +from gcmp import compare, prims +OLD="../in/03-Architecture-Hardware/kicad"; NEW="../inb" +LAY=(("F_Cu","gtl"),("In1_Cu","g1"),("In2_Cu","g2"),("B_Cu","gbl")) +def row(tag,a,b): + fs,ds,xa,blobs=compare(a,b) + print(f" {tag:34s} flashes={fs!s:5} draws={ds!s:5} fill-xor={xa:.3f} mm2 blobs={len(blobs)}", [f"{ar:.2f}@({x1},{y1})-({x2},{y2}){t}" for ar,x1,y1,x2,y2,t in blobs[:4]]) +for v,b,prod in (("v56","v5","HBOX_v5_Rev6_PROD"),("v57","v57","HBOX_v5_Rev7_PROD")): + print("=====",v) + for lay,e in LAY: + saved=f"{NEW}/{v}/gerber-saved/hbox-watchdog-{b}-{lay}.gbr" + rfn=f"{NEW}/{v}/rf/gerber/hbox-watchdog-{b}-{lay}.gbr" + pkg=f"{NEW}/pkg{v[1:]}/hbox-watchdog-{b}-{lay}.{e}" + rfo=f"{OLD}/_to_delete/audit-20261022/{v}/rf/gerber/hbox-watchdog-{b}-{lay}.gbr" + pko=f"{OLD}/production/{prod}/hbox-watchdog-{b}-{lay}.{e}" + print(f" [{lay}]") + row("A saved-fill vs fresh refill (P-1)", saved, rfn) + row("B new package vs saved-fill", pkg, saved) + row("C new refill vs morning refill", rfn, rfo) + row("D new package vs morning package", pkg, pko) + # non-copper layers: primitive sets + for lay,e in (("F_Mask","gts"),("B_Mask","gbs"),("F_Paste","gtp"),("B_Paste","gbp"),("F_Silkscreen","gto"),("B_Silkscreen","gbo"),("Edge_Cuts","gm1")): + a=f"{NEW}/pkg{v[1:]}/hbox-watchdog-{b}-{lay}.{e}"; o=f"{OLD}/production/{prod}/hbox-watchdog-{b}-{lay}.{e}" + fa,da=prims(a); fo,do=prims(o) + print(f" {lay:12s} new pkg vs morning pkg: flashes={fa==fo} draws={da==do}") + for d in ("PTH.drl","NPTH.drl"): + a=open(f"{NEW}/pkg{v[1:]}/hbox-watchdog-{b}-{d}").read().splitlines(); o=open(f"{OLD}/production/{prod}/hbox-watchdog-{b}-{d}").read().splitlines() + body=lambda L:[l for l in L if not l.startswith(";")] + print(f" {d:12s} new pkg vs morning pkg: same={body(a)==body(o)} ({len(body(a))} lines)") diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/scripts/gerb.py b/03-Architecture-Hardware/Auditoria-Final-V56-V57/scripts/gerb.py new file mode 100644 index 0000000..1237257 --- /dev/null +++ b/03-Architecture-Hardware/Auditoria-Final-V56-V57/scripts/gerb.py @@ -0,0 +1,144 @@ +"""Minimal Gerber (RS-274X, KiCad flavour) parser + matplotlib renderer.""" +import re, math +from shapely.geometry import Polygon, LineString, Point, box +from shapely.ops import unary_union +import matplotlib +matplotlib.use("Agg") +import matplotlib.pyplot as plt +from matplotlib.patches import Polygon as MPoly +from matplotlib.collections import PatchCollection + +def parse(path): + macros={}; apdefs={}; cur_macro=None; mbody=[] + ap=None; inreg=False; x=y=0; pol="D" + objs=[] # (kind, geom-params, polarity, net) + cur=[]; net=None + for raw in open(path, errors="replace"): + s=raw.strip() + if not s: continue + if cur_macro is not None: + mbody.append(s) + if s.endswith("%"): macros[cur_macro]="".join(mbody).rstrip("%"); cur_macro=None; mbody=[] + continue + m=re.match(r"%AM([^*]+)\*",s) + if m: + cur_macro=m.group(1); mbody=[s[len(m.group(0)):]] + if s.endswith("%"): macros[cur_macro]="".join(mbody).rstrip("%"); cur_macro=None; mbody=[] + continue + if s.startswith("G04 #@! TO.N,"): net=s[len("G04 #@! TO.N,"):].rstrip("*"); continue + if s.startswith("G04 #@! TD"): net=None; continue + if s.startswith("G04"): continue + m=re.match(r"%ADD(\d+)([^,*]+)(?:,([^*]*))?\*%",s) + if m: apdefs[m.group(1)]=(m.group(2),[float(t) for t in (m.group(3) or "").split("X") if t]); continue + if s=="%LPC*%": pol="C"; continue + if s=="%LPD*%": pol="D"; continue + if s.startswith("%"): continue + if s=="G36*": inreg=True; cur=[]; continue + if s=="G37*": inreg=False; objs.append(("region",cur,pol,net)); continue + m=re.match(r"D(\d+)\*$",s) + if m and int(m.group(1))>=10: ap=apdefs.get(m.group(1)); continue + m=re.match(r"(?:X(-?\d+))?(?:Y(-?\d+))?D0([123])\*$",s) + if m: + nx=int(m.group(1)) if m.group(1) is not None else x; ny=int(m.group(2)) if m.group(2) is not None else y + op=m.group(3) + if inreg: cur.append((nx,ny)) + elif op=="3": objs.append(("flash",(ap,nx,ny),pol,net)) + elif op=="1": objs.append(("draw",(ap,x,y,nx,ny),pol,net)) + x,y=nx,ny + return objs, macros + +def ap_shape(ap, cx, cy, macros): + """shapely geometry of an aperture flashed at (cx,cy) in mm (y up negative handled by caller).""" + kind,par=ap + if kind=="C": return Point(cx,cy).buffer(par[0]/2, resolution=8) + if kind=="R": return box(cx-par[0]/2,cy-par[1]/2,cx+par[0]/2,cy+par[1]/2) + if kind=="O": + w,h=par[0],par[1] + if w>=h: return LineString([(cx-(w-h)/2,cy),(cx+(w-h)/2,cy)]).buffer(h/2, resolution=8) + return LineString([(cx,cy-(h-w)/2),(cx,cy+(h-w)/2)]).buffer(w/2, resolution=8) + if kind=="RoundRect": + r=par[0]; pts=[(cx+par[1+2*i],cy+par[2+2*i]) for i in range(4)] + return Polygon(pts).buffer(r, resolution=6, join_style=1) + if kind=="P": # regular polygon + d,n=par[0],int(par[1]); rot=par[2] if len(par)>2 else 0 + return Polygon([(cx+d/2*math.cos(math.radians(rot+360*i/n)), cy+d/2*math.sin(math.radians(rot+360*i/n))) for i in range(n)]) + body=macros.get(kind,"") + # KiCad custom macros: polygon primitives "4,1,n,x1,y1,...,rot" possibly several; also circles "1,1,d,x,y" + geoms=[] + for prim in body.split("*"): + prim=prim.strip() + if not prim or prim.startswith("0 "): continue + toks=prim.split(",") + try: + if toks[0]=="4": + n=int(float(toks[2])); coords=[float(t) for t in toks[3:3+2*n]] + rot=float(toks[3+2*n]) if len(toks)>3+2*n else 0 + pts=[(coords[2*i],coords[2*i+1]) for i in range(n)] + th=math.radians(rot) + pts=[(cx+px*math.cos(th)-py*math.sin(th), cy+px*math.sin(th)+py*math.cos(th)) for px,py in pts] + if len(pts)>=3: geoms.append(Polygon(pts)) + elif toks[0]=="1": + d=float(toks[2]); px=float(toks[3]); py=float(toks[4]) + geoms.append(Point(cx+px,cy+py).buffer(d/2, resolution=6)) + elif toks[0] in ("20","21"): + # vector line / center line: 21 = center line: exposure,w,h,cx,cy,rot + if toks[0]=="21": + w,h,px,py,rot=[float(t) for t in toks[2:7]] + pts=[(-w/2,-h/2),(w/2,-h/2),(w/2,h/2),(-w/2,h/2)] + th=math.radians(rot) + pts=[(cx+px+a*math.cos(th)-b*math.sin(th), cy+py+a*math.sin(th)+b*math.cos(th)) for a,b in pts] + geoms.append(Polygon(pts)) + except Exception: + pass + if geoms: return unary_union(geoms) + return Point(cx,cy).buffer(0.3) + +def geoms_of(objs, macros, window=None): + """Return list of (shapely geom, polarity, net). y flipped to board coords (y down positive like KiCad).""" + out=[] + wx0,wy0,wx1,wy1 = window if window else (-1e9,-1e9,1e9,1e9) + for kind,g,pol,net in objs: + if kind=="region": + pts=[(px/1e6,-py/1e6) for px,py in g] + if len(pts)<3: continue + xs=[p[0] for p in pts]; ys=[p[1] for p in pts] + if max(xs)wx1 or max(ys)wy1: continue + try: poly=Polygon(pts) + except Exception: continue + if not poly.is_valid: poly=poly.buffer(0) + out.append((poly,pol,net)) + elif kind=="flash": + ap,px,py=g + if ap is None: continue + cx,cy=px/1e6,-py/1e6 + if cxwx1+3 or cywy1+3: continue + # macros defined with y up: flip y params -> we flip the whole shape: build in y-up space then mirror + sh=ap_shape(ap,cx,-cy,macros) + from shapely.affinity import scale + sh=scale(sh, xfact=1, yfact=-1, origin=(0,0)) + out.append((sh,pol,net)) + elif kind=="draw": + ap,x1,y1,x2,y2=g + if ap is None: continue + a=(x1/1e6,-y1/1e6); b=(x2/1e6,-y2/1e6) + if max(a[0],b[0])wx1+1 or max(a[1],b[1])wy1+1: continue + w=ap[1][0] if ap[0]=="C" else max(ap[1][:1] or [0.1]) + if a==b: sh=Point(a).buffer(w/2, resolution=6) + else: sh=LineString([a,b]).buffer(w/2, resolution=6) + out.append((sh,pol,net)) + return out + +def draw_geoms(ax, geoms, color, alpha=1.0, bg="white", zorder=1, net_colors=None): + patches=[]; colors=[] + for sh,pol,net in geoms: + c = color + if net_colors and net in net_colors: c=net_colors[net] + if pol=="C": c=bg + polys=[sh] if sh.geom_type=="Polygon" else list(getattr(sh,"geoms",[])) + for p in polys: + if p.is_empty or p.geom_type!="Polygon": continue + patches.append(MPoly(list(p.exterior.coords), closed=True)); colors.append(c) + for ring in p.interiors: + patches.append(MPoly(list(ring.coords), closed=True)); colors.append(bg) + pc=PatchCollection(patches, facecolors=colors, edgecolors="none", alpha=alpha, zorder=zorder) + ax.add_collection(pc) diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/scripts/netparse.py b/03-Architecture-Hardware/Auditoria-Final-V56-V57/scripts/netparse.py new file mode 100644 index 0000000..9117f11 --- /dev/null +++ b/03-Architecture-Hardware/Auditoria-Final-V56-V57/scripts/netparse.py @@ -0,0 +1,59 @@ +import re, sys, json +def tokenize(s): + tok=[]; i=0; n=len(s) + while i2 and isinstance(f[2],str) else '' + props={} + for p in find(c,'property'): + nm=first(p,'name')[1]; v=first(p,'value'); props[nm]=v[1] if v else '' + comps[ref]=dict(value=val, fp=fp, fields=fields, props=props, dnp=bool(find(c,'dnp')) or props.get('dnp') is not None) + nets={} + for nt in find(first(tree,'nets'),'net'): + name=first(nt,'name')[1] + nodes=[] + for nd in find(nt,'node'): + ref=first(nd,'ref')[1]; pin=first(nd,'pin')[1]; pf=first(nd,'pinfunction',[None,''])[1]; pt=first(nd,'pintype',[None,''])[1] + nodes.append((ref,pin,pf,pt)) + nets[name]=nodes + # pin->net map + pinnet={} + for name,nodes in nets.items(): + for ref,pin,pf,pt in nodes: pinnet[(ref,pin)]=name + return comps,nets,pinnet +if __name__=="__main__": + comps,nets,pinnet=load(sys.argv[1]) + print(len(comps),"components,",len(nets),"nets") diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/scripts/refill.py b/03-Architecture-Hardware/Auditoria-Final-V56-V57/scripts/refill.py new file mode 100644 index 0000000..d7968de --- /dev/null +++ b/03-Architecture-Hardware/Auditoria-Final-V56-V57/scripts/refill.py @@ -0,0 +1,7 @@ +import pcbnew, sys +p = sys.argv[1] +b = pcbnew.LoadBoard(p) +f = pcbnew.ZONE_FILLER(b) +f.Fill(b.Zones()) +pcbnew.SaveBoard(p, b) +print("refilled", p, "zones:", len(b.Zones())) diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/scripts/render_boards.py b/03-Architecture-Hardware/Auditoria-Final-V56-V57/scripts/render_boards.py new file mode 100644 index 0000000..f905398 --- /dev/null +++ b/03-Architecture-Hardware/Auditoria-Final-V56-V57/scripts/render_boards.py @@ -0,0 +1,48 @@ +import sys, time +sys.path.insert(0,'.') +from gerb import * +import matplotlib.pyplot as plt +from matplotlib.patches import Rectangle, FancyBboxPatch +import matplotlib.patheffects as pe +base="../in/03-Architecture-Hardware/kicad/production" +CU="#C8A05A"; CU2="#B8894A"; SILK="#F4F4F4"; BOARD="#1E3A2E"; EDGE="#333333" +INDIGO="#2C3C5B"; CYAN="#51F3DA"; TEAL="#17A08C" +def board_fig(b, prod, title, blocks, out, dpi=200): + t0=time.time() + cu,mac=parse(f"{base}/{prod}/hbox-watchdog-{b}-F_Cu.gtl") + silk,mac2=parse(f"{base}/{prod}/hbox-watchdog-{b}-F_Silkscreen.gto") + mask,mac3=parse(f"{base}/{prod}/hbox-watchdog-{b}-F_Mask.gts") + g_cu=geoms_of(cu,mac); g_silk=geoms_of(silk,mac2) + fig,ax=plt.subplots(figsize=(14,10.2)) + ax.add_patch(Rectangle((60.19,40.32),140,100,facecolor=BOARD,edgecolor=EDGE,lw=1.5,zorder=0)) + draw_geoms(ax,g_cu,CU,alpha=0.95,bg=BOARD,zorder=1) + draw_geoms(ax,g_silk,SILK,alpha=0.9,bg=BOARD,zorder=2) + for blk in blocks: + x0,y0,x1,y1,label,col=blk[:6]; pos=blk[6] if len(blk)>6 else "top" + ax.add_patch(FancyBboxPatch((x0,y0),x1-x0,y1-y0,boxstyle="round,pad=0.3,rounding_size=1.2",fill=False,edgecolor=col,lw=2.2,zorder=5)) + if pos=="top": tx,ty,va=x0+0.8,y0+0.9,"top" + else: tx,ty,va=x0+0.8,y1-0.9,"bottom" + t=ax.text(tx,ty,label,color="white",fontsize=9.5,fontweight="bold",va=va,ha="left",zorder=6, + bbox=dict(boxstyle="round,pad=0.25",facecolor=col,edgecolor="none",alpha=0.92)) + ax.set_xlim(58,202); ax.set_ylim(142,38.5) # y down like KiCad + ax.set_aspect("equal"); ax.axis("off") + ax.set_title(title,color=INDIGO,fontsize=15,fontweight="bold",loc="left") + fig.tight_layout(); fig.savefig(out,dpi=dpi,facecolor="white"); plt.close(fig) + print(out, f"{time.time()-t0:.1f}s") +common=[ + (147,104,167,122,"U6 LTC4040 · L6 · RS1 · Q7 — respaldo y carga","#E9533A"), + (131,104,147,122,"U7 AP64350 · L7 — riel 3.3 V del módem","#F2A93B","bottom"), + (170,76,200,92,"J7/J8 zócalo XBee — 4G NTRIP Master","#9B59B6"), + (112,52,134,74,"U16 STM32F411 · Y3/Y4","#2EA3F2"), + (62,46,104,66,"U11 W5500 · J10 RJ45 — Ethernet","#3BB273"), + (150,62,163,108,"U10 SC16IS752 · U14 RS-485 · U15 RS-232 · U13","#3BB273"), + (131,124,158,136,"P15 RS-485 · P16 RS-232","#3BB273"), + (62,88,138,135,"MOD1 simpleRTK2B Pro (cara inferior)","#BBBBBB"), + (150,50,166,64,"K1 Modo B","#F2A93B"), + (172,128,194,139,"P1 GX16 (24 V · GND · IGN)","#E9533A"), + (86,41,100,50,"U26 SC7A20","#2EA3F2"), +] +v56=common+[(182,52,198,74,"U2 · L2 buck del ventilador (24 V)","#E9533A"),(176,114,200,127,"D10 · Q10 · C10 — entrada 24 V","#E9533A"),(101,41,122,50,"P2 5 V (SD-15B) · P10","#E9533A")] +v57=common+[(176,45,199,74,"U25 TPS54360B · L22 · D34 · C149/C150 — fuente 9–32 V","#E9533A"),(173,114,200,127,"F2 · D10 · Q10 · C10 — entrada 9–32 V","#E9533A")] +board_fig("v5","HBOX_v5_Rev6_PROD","EinarBoard V5.6 — cara superior (Gerber HBOX_v5_Rev6_PROD, 22-oct-2026)",v56,"fig/fig-v56-top.png") +board_fig("v57","HBOX_v5_Rev7_PROD","EinarBoard V5.7 — cara superior (Gerber HBOX_v5_Rev7_PROD, 22-oct-2026)",v57,"fig/fig-v57-top.png") diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/scripts/render_fills.py b/03-Architecture-Hardware/Auditoria-Final-V56-V57/scripts/render_fills.py new file mode 100644 index 0000000..eac399a --- /dev/null +++ b/03-Architecture-Hardware/Auditoria-Final-V56-V57/scripts/render_fills.py @@ -0,0 +1,35 @@ +import sys; sys.path.insert(0,'.') +from gerb import * +import matplotlib.pyplot as plt +from matplotlib.patches import Rectangle, Circle +from shapely.ops import unary_union +INDIGO="#2C3C5B"; BOARD="#1E3A2E" +base="../in/03-Architecture-Hardware/kicad" +def fills(path, win, layer_filter=None): + objs,mac=parse(path) + regs=[g for g in geoms_of([o for o in objs if o[0]=="region"],mac,window=win)] + polys=[sh for sh,pol,net in regs if pol=="D"] + return unary_union(polys) if polys else None +fig,axs=plt.subplots(1,2,figsize=(13,4.9)) +for ax,(v,b,prod,lay,ext,win,ttl) in zip(axs,[("v56","v5","HBOX_v5_Rev6_PROD","B_Cu","gbl",(136.0,111.0,154.0,121.0),"V5.6 B.Cu — zona de U7 (vía de T35) y RS1 (T34)"), + ("v57","v57","HBOX_v5_Rev7_PROD","B_Cu","gbl",(136.0,108.0,154.0,118.0),"V5.7 B.Cu — zona de U7 (T36) y C129 (T37)")]): + ft=f"{base}/production/{prod}/hbox-watchdog-{b}-{lay}.{ext}"; stale=f"{base}/_to_delete/audit-20261022/{v}/gerber-cli/hbox-watchdog-{b}-{lay}.gbr" + objs,mac=parse(ft) + ax.add_patch(Rectangle((win[0],win[1]),win[2]-win[0],win[3]-win[1],facecolor=BOARD,zorder=0)) + # tracks + pads from FT (same in both) + nonreg=geoms_of([o for o in objs if o[0]!="region"],mac,window=win) + draw_geoms(ax,nonreg,"#C8A05A",bg=BOARD,zorder=2) + f_ft=fills(ft,win); f_st=fills(stale,win) + both=f_ft.intersection(f_st); only_st=f_st.difference(f_ft).buffer(0); only_ft=f_ft.difference(f_st).buffer(0) + draw_geoms(ax,[(both,"D",None)],"#8E9A8E",bg=BOARD,zorder=1) + draw_geoms(ax,[(only_st,"D",None)],"#FF2D2D",bg=BOARD,zorder=3) + draw_geoms(ax,[(only_ft,"D",None)],"#51F3DA",bg=BOARD,zorder=3) + ax.set_xlim(win[0],win[2]); ax.set_ylim(win[3],win[1]); ax.set_aspect("equal"); ax.axis("off") + ax.set_title(ttl,color=INDIGO,fontsize=12,fontweight="bold",loc="left") + pass +axs[0].annotate("vía /SYS5V (138.7, 117.45) de T35:\nel relleno viejo le pasa encima (corto)",xy=(138.7,117.45),xytext=(139.5,112.2),color="white",fontsize=9,arrowprops=dict(arrowstyle="->",color="white"),bbox=dict(boxstyle="round",fc="#C0392B",ec="none")) +axs[0].annotate("RS1: vías de entrada de T34",xy=(150.8,116.3),xytext=(144.0,119.8),color="white",fontsize=9,arrowprops=dict(arrowstyle="->",color="white"),bbox=dict(boxstyle="round",fc="#C0392B",ec="none")) +axs[1].annotate("vía GND de C129 (151.25, 112.5) de T37",xy=(151.25,112.5),xytext=(139.5,109.2),color="white",fontsize=9,arrowprops=dict(arrowstyle="->",color="white"),bbox=dict(boxstyle="round",fc="#C0392B",ec="none")) +fig.suptitle("El .kicad_pcb en disco trae el relleno de zonas viejo (pasada 5); Fabrication Toolkit rellenó al exportar.\ngris = relleno igual · ROJO = cobre del relleno viejo que el Gerber NO tiene · cian = cobre nuevo del Gerber · dorado = pistas, pads y vías",color=INDIGO,fontsize=11,fontweight="bold") +fig.tight_layout(rect=(0,0,1,0.88)); fig.savefig("fig/fig-relleno-viejo.png",dpi=200,facecolor="white"); plt.close(fig) +print("ok") diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/scripts/render_zooms.py b/03-Architecture-Hardware/Auditoria-Final-V56-V57/scripts/render_zooms.py new file mode 100644 index 0000000..97659f2 --- /dev/null +++ b/03-Architecture-Hardware/Auditoria-Final-V56-V57/scripts/render_zooms.py @@ -0,0 +1,53 @@ +import sys; sys.path.insert(0,'.') +from gerb import * +import matplotlib.pyplot as plt +from matplotlib.patches import Rectangle, Circle, FancyArrowPatch +base="../in/03-Architecture-Hardware/kicad/production" +INDIGO="#2C3C5B"; TEAL="#17A08C"; BOARD="#1E3A2E" +def zoom(ax, b, prod, win, net_colors, default="#9A9A9A", silk=True, mask=False, paste=False): + cu,mac=parse(f"{base}/{prod}/hbox-watchdog-{b}-F_Cu.gtl") + g=geoms_of(cu,mac,window=win) + ax.add_patch(Rectangle((win[0],win[1]),win[2]-win[0],win[3]-win[1],facecolor=BOARD,zorder=0)) + draw_geoms(ax,g,default,bg=BOARD,zorder=1,net_colors=net_colors) + if silk: + sk,m2=parse(f"{base}/{prod}/hbox-watchdog-{b}-F_Silkscreen.gto"); draw_geoms(ax,geoms_of(sk,m2,window=win),"#EDEDED",alpha=0.85,bg=BOARD,zorder=2) + if paste: + ps,m3=parse(f"{base}/{prod}/hbox-watchdog-{b}-F_Paste.gtp"); draw_geoms(ax,geoms_of(ps,m3,window=win),"#51F3DA",alpha=0.55,bg=BOARD,zorder=3) + ax.set_xlim(win[0],win[2]); ax.set_ylim(win[3],win[1]); ax.set_aspect("equal"); ax.axis("off") +# ---- Fig: RS1 Kelvin, both boards ---- +fig,axs=plt.subplots(1,2,figsize=(13,6.2)) +for ax,b,prod,ttl in ((axs[0],"v5","HBOX_v5_Rev6_PROD","V5.6"),(axs[1],"v57","HBOX_v5_Rev7_PROD","V5.7")): + win=(146.5,110.5,160.5,121.5) + zoom(ax,b,prod,win,{"/VEH5V":"#E9533A","/VIN_SW":"#F2A93B","/MAIN5V":"#2EA3F2","GND":"#5C6B5C"},default="#9A9A9A") + ax.set_title(f"{ttl} — RS1 10 mΩ con sensado Kelvin (F.Cu)",color=INDIGO,fontsize=12,fontweight="bold",loc="left") + # annotations + ax.annotate("hilo de sensado\nU6.6 (VIN)",xy=(151.6,116.8),xytext=(147.2,112.3),color="white",fontsize=9,arrowprops=dict(arrowstyle="->",color="white",lw=1.2),bbox=dict(boxstyle="round",fc="#E9533A",ec="none")) + ax.annotate("hilo de sensado\nU6.7 (CLN)",xy=(153.0,115.3),xytext=(155.5,119.9),color="white",fontsize=9,arrowprops=dict(arrowstyle="->",color="white",lw=1.2),bbox=dict(boxstyle="round",fc="#F2A93B",ec="none")) + ax.annotate("entrada VEH5V:\n2 vías 0.6/0.3",xy=(150.75,116.2),xytext=(146.9,120.2),color="white",fontsize=9,arrowprops=dict(arrowstyle="->",color="white",lw=1.2),bbox=dict(boxstyle="round",fc="#C0392B",ec="none")) + ax.annotate("RS1.2 → Q7 (VIN_SW)",xy=(153.3,117.9),xytext=(156.3,121.0),color="white",fontsize=9,arrowprops=dict(arrowstyle="->",color="white",lw=1.2),bbox=dict(boxstyle="round",fc="#B9770E",ec="none")) + ax.text(146.7,111.0,"rojo = /VEH5V · naranja = /VIN_SW · azul = /MAIN5V (VSYS) · gris = GND",color="white",fontsize=8,va="top") +fig.tight_layout(); fig.savefig("fig/fig-rs1-kelvin.png",dpi=200,facecolor="white"); plt.close(fig) +# ---- Fig: U6 EP paste windows vs thermal vias ---- +fig,axs=plt.subplots(1,2,figsize=(12,6.6)) +for ax,b,prod,ttl in ((axs[0],"v5","HBOX_v5_Rev6_PROD","V5.6"),(axs[1],"v57","HBOX_v5_Rev7_PROD","V5.7")): + win=(153.2,109.9,159.7,116.4) + zoom(ax,b,prod,win,{"GND":"#5C6B5C","/MAIN5V":"#2EA3F2","/VEH5V":"#E9533A"},default="#9A9A9A",silk=False,paste=True) + ax.add_patch(Rectangle((156.4475-1.325,113.12-1.825),2.65,3.65,fill=False,edgecolor="white",lw=1.2,ls="--",zorder=5)) + vias={"v5":[(156.4475,112.935),(155.6,112.4),(157.2,112.4)],"v57":[(157.135,111.88),(156.45,112.5),(155.735,111.925)]}[b] + for (vx,vy) in vias: + ax.add_patch(Circle((vx,vy),0.3,facecolor="#C8A05A",edgecolor="white",lw=0.8,zorder=6)) + ax.add_patch(Circle((vx,vy),0.15,facecolor=BOARD,edgecolor="none",zorder=7)) + ax.annotate("vías térmicas 0.6/0.3\ndentro de la pasta",xy=vias[0],xytext=(157.4,115.6),color="white",fontsize=9,arrowprops=dict(arrowstyle="->",color="white",lw=1.1),bbox=dict(boxstyle="round",fc="#E9533A",ec="none"),zorder=8) + ax.set_title(f"{ttl} — U6 LTC4040: pad térmico, pasta y vías",color=INDIGO,fontsize=12,fontweight="bold",loc="left") + ax.text(153.4,110.1,"cian = ventanas de pasta (6 × 0.95×0.85 mm = 50 %)\nblanco punteado = pad térmico 2.65×3.65 mm\n3 vías 0.6/0.3 dentro de las ventanas → pedir «Epoxy Filled & Capped»",color="white",fontsize=8.5,va="top",bbox=dict(boxstyle="round",fc="#2C3C5B",ec="none",alpha=0.9)) +fig.tight_layout(rect=(0,0,1,0.97)); fig.savefig("fig/fig-u6-pasta.png",dpi=200,facecolor="white"); plt.close(fig) +# ---- Fig: V5.7 supply block ---- +fig,ax=plt.subplots(figsize=(12,8.5)) +win=(172,44,200,76) +zoom(ax,"v57","HBOX_v5_Rev7_PROD",win,{"/24V":"#E9533A","/SW_PWRIN":"#F2A93B","/VEH5V":"#2EA3F2","GND":"#5C6B5C","/VIN_FUSED":"#C0392B","/FB_PWRIN":"#9B59B6"},default="#9A9A9A") +ax.set_title("V5.7 — fuente a bordo U25 TPS54360B (F.Cu)",color=INDIGO,fontsize=13,fontweight="bold",loc="left") +for (x,y,txt) in ((187.7,68.6,"U25"),(186.4,50.0,"L22 10 µH"),(188.4,61.0,"D34 B560C"),(180.9,62.1,"C22"),(179.0,67.0,"C149/C150"),(182.396,68.11,"vía única /24V\n(182.4, 68.1)")): + ax.annotate(txt,xy=(x,y),xytext=(x-6.5,y+3.2) if "vía" in txt else (x+2.0,y-2.5),color="white",fontsize=9,arrowprops=dict(arrowstyle="->",color="white",lw=1.1),bbox=dict(boxstyle="round",fc="#2C3C5B",ec="none",alpha=0.9)) +ax.text(172.3,44.3,"rojo = /24V · naranja = nodo SW · azul = /VEH5V (5.32 V) · morado = FB",color="white",fontsize=9,va="top") +fig.tight_layout(); fig.savefig("fig/fig-v57-fuente.png",dpi=200,facecolor="white"); plt.close(fig) +print("zooms done") diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/scripts/riesgos.py b/03-Architecture-Hardware/Auditoria-Final-V56-V57/scripts/riesgos.py new file mode 100644 index 0000000..bdd00ff --- /dev/null +++ b/03-Architecture-Hardware/Auditoria-Final-V56-V57/scripts/riesgos.py @@ -0,0 +1,20 @@ +# Registro de riesgos — auditoría final V5.6/V5.7, 22-oct-2026. P = probabilidad 1-5, I = impacto 1-5. +RIESGOS = [ + # id, titulo corto, tarjeta, P0, I0, P1, I1, mitigacion (corta), clase + ("R1","Soldadura de U6 (QFN 0.5 mm, 3 vías en la pasta): puentes y bolas como en V5.5/V4","V5.6 · V5.7",4,4,2,3,"Pedir con «Epoxy Filled & Capped» + rayos X en U6; lupa en cada tarjeta antes de energizar","Pedido"), + ("R2","Rotación de huellas easyeda2kicad (U7, U25, U26, L22) y polaridad de D34 en JLC","V5.6 · V5.7",2,5,1,5,"Confirmar pin 1 y polaridad en el visor de JLC antes de pagar","Pedido"), + ("R3","Apagón (brownout) del módem en batería al arrancar o en ráfaga LTE","V5.6 · V5.7",1,4,1,3,"Hardware ya resuelto (AP64350 desde 3.8 V, 2.5 A de boost, C43 220 µF); 0.7.0 secuencia etapa → NMEA → MODEM_EN","Diseño"), + ("R4","Piso de consumo dormido demasiado alto (W5500 65–132 mA sin enable)","V5.6 · V5.7",4,3,2,3,"0.7.0: W5500 en power-down (13 mA) antes de dormir; medir el piso en el piloto (PPK2)","Firmware"), + ("R5","RS-485 toma el bus desde el encendido hasta que el firmware configura U10","V5.6 · V5.7",3,2,2,2,"EFCR/MCR como primer paso del arranque; uso punto a punto; THVD1410 en BOM para 108/322","Firmware"), + ("R6","Ignición mal leída en máquinas de 12 V (1.38 V en PA5, zona indefinida)","V5.7",4,3,1,3,"0.7.0: PA5 por ADC con histéresis 0.80/0.55 V","Firmware"), + ("R7","Arnés al revés: D10 SMBJ33A conduce y abre F2 (SMD) / quema D10","V5.7 (V5.6)",2,3,2,1,"D10 → SMBJ33CA (misma huella); V5.6 sin fusible: el breaker del gabinete","BOM"), + ("R8","U25: timbre en SW/VIN (lazo 56 mm²) o calor de U25/D34 a 32 V y 2.8 A","V5.7",2,3,2,2,"Banco: 9/24/32 V con 2.5 A, osciloscopio y cámara térmica; D-21-2","Banco"), + ("R9","Firmware 0.7.0 no existe: el piloto no se puede probar (ni el módem enciende)","V5.6 · V5.7",5,4,3,4,"board_v56.h hoy; 0.7.0-pre (módem + ADC) antes de que lleguen las tarjetas","Firmware"), + ("R10","Arneses cortos / tapa: conectores JST movidos 12–68 mm; LEDs del gauge en otro borde (V5.7)","V5.7 (V5.6)",3,2,3,1,"Medir con la primera tarjeta; tapa V5.7 si el gauge se ve por la tapa","Mecánica"), + ("R11","Relleno de zonas viejo en los .kicad_pcb del repo: una exportación sin rellenar manda cortos","V5.6 · V5.7",2,4,1,4,"Hoy: Gerber verificado = relleno fresco. Leo: abrir, B, guardar y commit","Proceso"), + ("R12","Umbrales de batería pensados para Li-ion (3.40/3.70 V) con paquete LFP (meseta 3.2–3.3 V)","V5.6 · V5.7",4,3,1,3,"0.7.0: corte 2.95 V / rearme 3.20 V con media de 200 ms; SoC por culombios","Firmware"), + ("R13","Lazos de convertidores heredados de V5.5 (U12/L8 35 mm, U2/Dbk1 18 mm): EMC / ruido","V5.6 · V5.7",2,2,2,2,"Se mide en el piloto; corregir en v6","Diseño"), + ("R14","Vías únicas en el camino de 24 V (V5.7) a 9 V y 1.9 A: calentamiento","V5.7",1,2,1,2,"Instalaciones a 24 V (0.7 A); cámara térmica a 9 V; 2.ª vía en la siguiente revisión","Diseño"), + ("R15","Módem «encendido pero muerto» tras dormir (riel sostenido por Rdfu1 22k vía K1/DIN)","V5.6 · V5.7",2,3,1,3,"Pulso de MODEM_RST (PC1) tras cada MODEM_EN (SW4G1 probado); revisar Rdfu1 en v6","Firmware"), + ("R16","LSE no arranca (FC-135 CL 12.5 pF con 12 pF) y el ciclo de 10 min se queda sin reloj","V5.6 · V5.7",1,3,1,1,"LSEDRV alto + timeout → RTC con LSI (±5 %) y evento; IWDG independiente","Firmware"), +] diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/scripts/verify_mac.sh b/03-Architecture-Hardware/Auditoria-Final-V56-V57/scripts/verify_mac.sh new file mode 100755 index 0000000..2136060 --- /dev/null +++ b/03-Architecture-Hardware/Auditoria-Final-V56-V57/scripts/verify_mac.sh @@ -0,0 +1,26 @@ +#!/bin/zsh +# uso: verify.sh v56 hbox-watchdog-v5 | verify.sh v57 hbox-watchdog-v57 +set -e +KC=/Applications/KiCad/KiCad.app/Contents/MacOS/kicad-cli +PY=/Applications/KiCad/KiCad.app/Contents/Frameworks/Python.framework/Versions/Current/bin/python3 +A="$(cd "$(dirname "$0")" && pwd)"; D="$A/$1"; S="$2" +cd "$D" +echo "== DRC (parity + refill) $S" +"$KC" pcb drc --schematic-parity --refill-zones --severity-all --format json -o "drc-$1.json" "$S.kicad_pcb" >/dev/null 2>&1 || true +"$PY" - "drc-$1.json" <<'PYEOF' +import json,sys +d=json.load(open(sys.argv[1])) +from collections import Counter +print("violations:",len(d.get("violations",[])), Counter((v["type"],v["severity"]) for v in d.get("violations",[]))) +print("unconnected:",len(d.get("unconnected_items",[])), "parity:",len(d.get("schematic_parity",[])), Counter(v["type"] for v in d.get("schematic_parity",[]))) +PYEOF +echo "== gerber as-saved" +rm -rf gerber-saved; mkdir gerber-saved +"$KC" pcb export gerbers --subtract-soldermask --no-protel-ext -o gerber-saved/ "$S.kicad_pcb" >/dev/null +"$KC" pcb export drill --excellon-separate-th -o gerber-saved/ "$S.kicad_pcb" >/dev/null +echo "== refill copy + gerber" +rm -rf rf; mkdir rf; cp "$S".kicad_pcb "$S".kicad_pro "$S".kicad_prl "$S".kicad_dru fp-lib-table sym-lib-table rf/ 2>/dev/null || true; cp -R Drogheda.pretty Drogheda-v6.pretty rf/ +"$PY" "$A/refill.py" "rf/$S.kicad_pcb" +mkdir -p rf/gerber +"$KC" pcb export gerbers --subtract-soldermask --no-protel-ext -o rf/gerber/ "rf/$S.kicad_pcb" >/dev/null +echo "== done $1"; ls gerber-saved | wc -l; ls rf/gerber | wc -l diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/sec1-resumen.tex b/03-Architecture-Hardware/Auditoria-Final-V56-V57/sec1-resumen.tex new file mode 100644 index 0000000..a295f9f --- /dev/null +++ b/03-Architecture-Hardware/Auditoria-Final-V56-V57/sec1-resumen.tex @@ -0,0 +1,64 @@ +% ================================================================ RESUMEN +\section{Resumen ejecutivo y veredicto}\label{sec:resumen} + +\begin{helgennotice}[Veredicto — 22 de octubre de 2026] +\textbf{GO al pedido de hoy: 5 EinarBoard V5.6 + 5 EinarBoard V5.7 (piloto), con tres condiciones de pedido +que no tocan el cobre.} Los Gerber, taladros, máscaras, pasta y serigrafía que exportó Leo son, pad por pad y +pista por pista, los archivos de la pasada 6 con el relleno de zonas fresco (§\ref{sec:paquete}); el DRC con las +reglas del proyecto y la paridad con el esquemático salen limpios (0 errores salvo los 3 barrenos de MOD1, por +diseño; 0 sin conectar); el sensado Kelvin de RS1 está íntegro en VIN y CLN; el BOM tiene código LCSC en las +226 / 229 piezas montadas y la lista de posiciones cuadra con el PCB. + +\textbf{Condiciones del pedido} (§\ref{sec:plan}): (1) vías del PCB con \emph{Epoxy Filled \& Capped} y +rayos X en \refdes{U6} — las tres vías térmicas del LTC4040 caen dentro de las ventanas de pasta; +(2) confirmar en el visor de JLC la rotación y el pin 1 de \refdes{U6}, \refdes{U7}, \refdes{U25}, +\refdes{U26}, \refdes{L22}, \refdes{Q7}, \refdes{U16} y la polaridad de \refdes{D34}, \refdes{D10}, +\refdes{C3}/\refdes{C43}/\refdes{C78}/\refdes{C10}/\refdes{C103} — las huellas easyeda2kicad no pasan por +la tabla de correcciones del Fabrication Toolkit; (3) antes de pedir, cambiar en el BOM \refdes{D10} +SMBJ33A $\to$ SMBJ33CA (misma huella; con el arnés al revés la V5.7 abre su fusible SMD \refdes{F2}). + +\textbf{NO-GO para las 108 V5.6 y las 322 V5.7} hasta que el piloto pase el banco con el firmware 0.7.0: hoy +\emph{ningún firmware enciende el módem de estas tarjetas} (\net{MODEM\_EN} en PC3 es nuevo), y el ciclo de 10 min +en batería, el RS-485 y el Ethernet de campo existen en hardware pero no en software (§\ref{sec:firmware}). +\end{helgennotice} + +\subsection{Lo que pidió Leo y lo que encontró la auditoría} + +\hwtab{\begin{tabular}{@{}L{4.46cm}L{2.13cm}L{9.31cm}@{}} +\toprule +\cab{\cw{Mandato (22-oct)} & \cw{Estado} & \cw{Qué respalda el estado}}\\ +\midrule +1 $\cdot$ Que todos los puertos funcionen & \estado{Hardware sí} $\cdot$ firmware no & USB-C DFU, USB-C del módem, RJ45, RS-485, RS-232, TTL (H4), GX16, JST internos: netlist correcto contra las hojas de datos (§\ref{sec:puertos}). Lo que falta es software: SC16IS752, Ethernet de campo.\\ +\rowcolor{HelgenMist} 2 $\cdot$ V5.7 sin la Mean Well & \estado{Sí} & U25 TPS54360B: 5.32 V a 600 kHz, 9--32 V continuos, EN flotante habilita, L22 15.5 A de saturación, D34 5 A/60 V (§\ref{sec:v57-fuente}). Se mide en banco a 9/24/32 V.\\ +3 $\cdot$ Ethernet, RS-485 y RS-232 usables & \estado{Usables} con dos reglas & RS-485 ocupa el bus desde el encendido hasta que 0.7.0 escribe EFCR (uso punto a punto o tolerar $\sim$1 s en el arranque); H4 y P16 nunca al mismo tiempo (§\ref{sec:puertos}).\\ +\rowcolor{HelgenMist} 4 $\cdot$ Que el módem no provoque un apagón & \estado{Resuelto en hardware} & AP64350 desde \net{SYS5V} (arranca a 3.8 V; en respaldo el riel es 4.79 V), 2.5 A del boost del LTC4040 contra 1.8 A de pico, 220 $\mu$F en \net{3V3\_MODEM}, PFI a 4.40 V. El firmware secuencia: etapa $\to$ NMEA $\to$ módem (§\ref{sec:bateria}).\\ +5 $\cdot$ 10 min dormida en batería, despertar, dos reportes, dormir & \estado{Hardware sí} $\cdot$ firmware no & STM32 alimentado en respaldo, LSE Y4 para la alarma del RTC, INT1 del SC7A20 en PB9 para despertar por movimiento, \net{MODEM\_EN}/\net{PWR\_CTRL} para cortar rieles. Piso dormido estimado 75 mW si el W5500 se pone en power-down; 5 días con ventanas de 45 s cada 10 min (§\ref{sec:bateria}).\\ +\rowcolor{HelgenMist} 6 $\cdot$ Gerber/BOM/CPL ya generados & \estado{Verificados} & Idénticos a una regeneración con relleno fresco (§\ref{sec:paquete}); P-1 (relleno viejo en el repo) quedó cerrado a las 13:00.\\ +7 $\cdot$ Empezar el firmware & \estado{Empezado} & \texttt{board\_v56.h} entregado (mapa de 64 pines del netlist, idéntico en V5.6 y V5.7) y la especificación 0.7.0 con sus algoritmos (§\ref{sec:firmware}).\\ +\rowcolor{HelgenMist} 8 $\cdot$ Última auditoría: riesgos y easy wins & \estado{Hecho} & 30 hallazgos (§\ref{sec:hallazgos}), 16 riesgos puntuados antes y después de mitigar (§\ref{sec:riesgos}), 6 easy wins de BOM/pedido/proceso.\\ +9 $\cdot$ Documento Helgen + Beamer & \estado{Hecho} & Este PDF y \texttt{…\_Presentacion\_ES\_v1.0.pdf}.\\ +\rowcolor{HelgenMist} 10 $\cdot$ Pedir hoy & \estado{GO piloto} & Con las condiciones de arriba. Las 108 / 322 después del banco.\\ +\bottomrule +\end{tabular}} + +\subsection{Lo que cambió respecto a «casi listo»} + +Las sesiones anteriores decían «casi listo» porque medían el cobre. Esta auditoría midió además lo que el +cobre no muestra: \emph{el paquete que va a JLC} (¿es el cobre que auditamos?), \emph{el pedido} +(vías en la pasta, rotaciones), \emph{el comportamiento en batería} (presupuesto, piso dormido, secuencia del +módem) y \emph{el firmware que tiene que existir para que todo eso se pueda probar}. De ahí salen las tres +condiciones del pedido y el límite claro: GO para 5 + 5, no para 430. + +Dos cosas que vale la pena decir sin rodeos: + +\begin{itemize} +\item \textbf{El camino crítico ya no es el PCB, es el firmware 0.7.0.} Sin él las tarjetas del piloto no + encienden el módem. La especificación está en §\ref{sec:firmware}; el mapa de pines ya está escrito y verificado + pin a pin contra los dos netlists. +\item \textbf{Había un riesgo de proceso que hoy no mordía pero mañana sí:} los dos \texttt{.kicad\_pcb} del repo + tenían el relleno de zonas de la pasada 5. El Fabrication Toolkit rellenó al exportar (por eso los Gerber estaban + bien), pero cualquier otra exportación —\texttt{kicad-cli}, o el GUI sin «B»— habría mandado a fábrica un relleno + que pasa encima de las vías nuevas de T35 y T37 (figura \ref{fig:relleno}). \textbf{Cerrado a las 13:00:} Leo + rellenó, guardó y regeneró los paquetes; la re-verificación (§\ref{sec:paquete}) encontró 0.000 mm$^2$ entre el + relleno guardado y uno fresco, y el mismo cobre de la mañana. Queda el commit y la regla D-22-3. +\end{itemize} diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/sec10-plan.tex b/03-Architecture-Hardware/Auditoria-Final-V56-V57/sec10-plan.tex new file mode 100644 index 0000000..17c2ee6 --- /dev/null +++ b/03-Architecture-Hardware/Auditoria-Final-V56-V57/sec10-plan.tex @@ -0,0 +1,59 @@ +% ================================================================ PLAN +\section{El pedido de hoy y el camino a las 108 / 322}\label{sec:plan} + +\subsection{Lista de verificación del pedido (Leo, $\approx$ 40 min)} + +\begin{enumerate} +\item \textbf{BOM} (antes de subir): \refdes{D10} $\to$ SMBJ33CA con existencia; opcional, 10 nF a C1589 y etiqueta de + \refdes{C22}. Si se cambia el BOM, regenerar con el Toolkit (los Gerber no cambian) o editar la fila a mano en + \texttt{\_bom.csv}. +\item \textbf{PCB}: 4 capas, 1.6 mm, stackup JLC04161H-7628, \textbf{ENIG}, \textbf{Via covering: Epoxy Filled \& + Capped}, máscara verde, serigrafía blanca, «Remove order number: specify location» si se quiere (hay espacio en + B.Cu), \textbf{Confirm production file: Yes}. +\item \textbf{Ensamble}: ambas caras no — solo \textbf{top} (B.Paste tiene 5 comandos: nada montado abajo); «Do not + confirm parts placement» = \textbf{No} (queremos el visor); \textbf{X-ray}: pedir inspección en U6 en las notas + del pedido. +\item \textbf{Visor de JLC}: pin 1 de \refdes{U6}, \refdes{U7}, \refdes{U25}, \refdes{U26}, \refdes{U16}, + \refdes{Q7}; punto de \refdes{L22}; cátodo de \refdes{D34}, \refdes{D10}, \refdes{D5}, \refdes{D6}, + \refdes{D11--D13}; «+» de \refdes{C3}, \refdes{C43}, \refdes{C78}, \refdes{C10}, \refdes{C103}; \refdes{K1}; + \refdes{Q10}. Corregir ahí mismo si algo gira. +\item \textbf{Cantidad}: 5 + 5. Guardar el número de orden en el acta de la tarjeta y en \texttt{Bitácora}. +\item \textbf{Después de pagar}: abrir cada tarjeta en KiCad, \textsf{B}, guardar, \texttt{git add kicad/} + + \texttt{production/HBOX\_v5\_Rev[67]\_PROD*} + commit «V5.6/V5.7: paquete del piloto 22-oct, relleno fresco» + push + + bump del submódulo. Así el repo es exactamente lo que se fabricó. +\end{enumerate} + +\subsection{Mientras llegan las tarjetas ($\approx$ 2 semanas)} + +\hwtab{\begin{tabular}{@{}L{0.68cm}L{6.82cm}L{2.73cm}L{5.26cm}@{}} +\toprule +\cab{\cw{} & \cw{Qué} & \cw{Quién $\cdot$ cuándo} & \cw{Sale con}}\\ +\midrule +1 & 0.7.0-pre (F-1): módem, NTC, LFP, ignición por ADC & Leo + Claude $\cdot$ 24-oct & binario \path{hbox-tarjetaV56_0.7.0-pre.bin} probado en hostsim\\ +\rowcolor{HelgenMist} 2 & 0.7.0 ciclo de respaldo (F-2) + SC16IS752 (F-3) + módem (F-6/F-7/F-8) & Leo + Claude $\cdot$ 31-oct & hostsim con escenarios: ciclo, LFP, recuperación\\ +3 & Ethernet de campo (F-4) + acelerómetro (F-5) & Leo + Claude $\cdot$ 5-nov & hostsim + build \texttt{-eth}\\ +\rowcolor{HelgenMist} 4 & Procedimiento de banco del piloto (versión 0.7.0 del acta): mediciones de §\ref{sec:bateria} y §\ref{sec:v57-fuente}, PPK2, cámara térmica & Claude $\cdot$ 28-oct & \path{06-Testing-Validation/..._Banco-Piloto_V5.6-V5.7...}\\ +5 & Pre-orden THVD1410 / TRS3232E / SMBJ33CA para las 108 / 322 & Adriana $\cdot$ 24-oct & JLC parts pre-order\\ +\rowcolor{HelgenMist} 6 & Arneses y tapa: medir contra la V5.5 con el STEP de la V5.6/V5.7 & Jesús $\cdot$ al llegar & lista de largos nuevos\\ +\bottomrule +\end{tabular}} + +\subsection{Criterios para liberar las 108 / 322 (banco del piloto con 0.7.0)} + +\hwtab{\begin{tabular}{@{}L{0.7cm}L{7.6cm}L{7.6cm}@{}} +\toprule +\cab{\cw{} & \cw{Prueba} & \cw{Pasa si}}\\ +\midrule +1 & Inspección de U6 (lupa 10×) y energizado en USB & sin puentes ni bolas; 3V3 presente; autoprueba OK (HSE, LSE, I$^2$C ×6, ADC)\\ +\rowcolor{HelgenMist} 2 & 24 V: etapa + módem; carga con TP1 ÷ 32 & NMEA $<$ 2 s; registro $<$ 60 s; razón Kelvin 1.0--1.1; carga 1.2--1.4 A; CHRG\_STAT en el monitor\\ +3 & Ciclo de 10 min ×20 en batería (paquete 20 \%, 45 °C) & 20/20 con reporte en el servidor; piso $<$ 100 mW; \net{SYS5V} $>$ 4.3 V; sin reset\\ +\rowcolor{HelgenMist} 4 & Cortes 24 V $\leftrightarrow$ batería ×20 & sin reset del MCU, módem vivo, eventos BACKUP en el servidor\\ +5 & RS-485 y RS-232 en lazo; Ethernet 24 h & 0 errores a 115200; bus libre $<$ 100 ms tras reset; 24 h sin desconexión\\ +\rowcolor{HelgenMist} 6 & V5.7: 9 / 12 / 24 / 32 V con 2.5 A; polaridad invertida; térmico & 5.32 ± 0.1 V; sin timbre $>$ 0.5 V en SW; U25 $<$ 110 °C, D34 $<$ 100 °C a 32 V; al revés nada se daña (con SMBJ33CA)\\ +7 & Temperatura de U6, L6, L7 en respaldo a plena carga & $<$ 85 °C en la superficie a 45 °C ambiente\\ +\rowcolor{HelgenMist} 8 & Mecánica: arneses, tapa, barrenos, GX16 & todo entra sin forzar; gauge visible\\ +\bottomrule +\end{tabular}} + +Con los 8 en verde en las 10 tarjetas, se liberan las 108 V5.6 (con SD-15B) y las 322 V5.7, con los easy wins de +BOM ya aplicados. Con un rojo en 1--4 se corrige antes de pedir; con un rojo en 5--8 se decide por tarjeta. diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/sec2-metodo.tex b/03-Architecture-Hardware/Auditoria-Final-V56-V57/sec2-metodo.tex new file mode 100644 index 0000000..38c02a9 --- /dev/null +++ b/03-Architecture-Hardware/Auditoria-Final-V56-V57/sec2-metodo.tex @@ -0,0 +1,70 @@ +% ================================================================ MANDATO Y MÉTODO +\section{Mandato, insumos y método}\label{sec:metodo} + +\subsection{El mandato, en las palabras de Leo (22-oct, 10:01)} + +Meta de V5.6 y V5.7: que \textbf{todos los puertos funcionen}; la \textbf{V5.7 no usa la Mean Well}; +\textbf{Ethernet, RS-485 y RS-232} usables si se les conectan señales; el \textbf{módem 4G no debe provocar un +apagón}; en batería, \textbf{10 minutos dormida}, despertar, mandar \textbf{un par de reportes} y volver a dormir; +los Gerber, BOM y archivos de fabricación \textbf{ya están} en \texttt{HBOX\_v5\_Rev6\_PROD} y +\texttt{HBOX\_v5\_Rev7\_PROD}; \textbf{empezar el firmware} y que quede «spot on»; \textbf{esta auditoría se hace +una vez} (las demás sesiones dicen «casi listo»; se dejaron pasar detalles por falta de espacio): resaltar +\textbf{riesgos} y \textbf{victorias fáciles}, con \textbf{tabla} problema $\to$ arreglo, \textbf{imágenes} y +explicaciones; \textbf{documento en español, formato Helgen, LaTeX} + \textbf{Beamer}; resaltar los +\textbf{algoritmos}; \textbf{matriz de riesgo}; solo V5.6 y V5.7; \textbf{las tarjetas se piden hoy}: hace +falta una decisión. + +Antes de empezar, la auditoría se escribió a sí misma el protocolo (el «reprompt» que pidió Leo): +\path{2026-10-22_Drogheda_Auditoria-Final-Produccion_V5.6-V5.7_Protocolo_ES_v1.0.md}. Define el rol +(auditor independiente; socio objetivo, no complaciente), las clases de hallazgo, los criterios GO / NO-GO y el +método A--G que sigue este documento. Queda como el paso 7 de la Ruta a producción para cualquier tarjeta futura. + +\subsection{Insumos: exactamente lo que está en la Mac}\label{sec:insumos} + +\hwtab{\begin{tabular}{@{}L{3.49cm}L{8.34cm}L{4.07cm}@{}} +\toprule +\cab{\cw{Insumo} & \cw{Archivo} & \cw{SHA-256 (primeros 8)}}\\ +\midrule +V5.6 PCB (el de los Gerber) & \texttt{kicad/hbox-watchdog-v5.kicad\_pcb} (guardado 22-oct 01:05) & \texttt{f07ad5b5}\\ +V5.6 esquemático & \texttt{kicad/hbox-watchdog-v5.kicad\_sch} & \texttt{dc9381d7}\\ +V5.6 proyecto $\cdot$ reglas & \texttt{hbox-watchdog-v5.kicad\_pro} $\cdot$ \texttt{.kicad\_dru} & \texttt{f6721eb7} $\cdot$ \texttt{8e4d3a7b}\\ +\rowcolor{HelgenMist} V5.7 PCB (el de los Gerber) & \texttt{kicad/hbox-watchdog-v57.kicad\_pcb} (guardado 22-oct 01:30) & \texttt{9373ebe8}\\ +\rowcolor{HelgenMist} V5.7 esquemático & \texttt{kicad/hbox-watchdog-v57.kicad\_sch} & \texttt{e0e6caf6}\\ +\rowcolor{HelgenMist} V5.7 proyecto $\cdot$ reglas & \texttt{hbox-watchdog-v57.kicad\_pro} $\cdot$ \texttt{.kicad\_dru} & \texttt{d36d5139} $\cdot$ \texttt{8e4d3a7b}\\ +Paquete V5.6 & \texttt{production/HBOX\_v5\_Rev6\_PROD.zip} + \texttt{\_bom.csv} + \texttt{\_positions.csv} (22-oct 01:55) & \texttt{49969628} $\cdot$ \texttt{3fbb69f2} $\cdot$ \texttt{0904080d}\\ +Paquete V5.7 & \texttt{production/HBOX\_v5\_Rev7\_PROD.zip} + \texttt{\_bom.csv} + \texttt{\_positions.csv} (22-oct 15:55) & \texttt{fb18a61b} $\cdot$ \texttt{08e53137} $\cdot$ \texttt{c6f2c750}\\ +\rowcolor{HelgenMist} Firmware & \texttt{04-Source-Code/firmware/hbox\_v5\_bringup/} 0.6.3 (\texttt{.ino} 2025 líneas, \texttt{board\_v5.h}, \texttt{board\_v4.h}) & —\\ +Referencias previas & Auditorías del 16, 19 y 21-oct; ECO V5.6 (27-sep); ECO V5.7 (13-oct); auditoría EMC V5.5 (22-ago) & —\\ +\rowcolor{HelgenMist} Hojas de datos & LTC4040 (ADI 4040fb), AP64350 (Diodes), TPS54360B (TI), W5500 (WIZnet v1.1.0), SC16IS752, SP3485, MAX3232, SC7A20, STM32F411RE; piezas en JLC: C85100, C32346, C15578, C99550, C840531 & —\\ +\bottomrule +\end{tabular}} + +Verificación previa: los dos \texttt{.kicad\_pcb} solo difieren de sus respaldos \texttt{.T35bak} / +\texttt{.T37bak} en lo que T35 y T37 agregaron (la segunda vía de entrada de U7 y la vía de GND de C129): +\textbf{nadie movió nada después de la pasada 6}, y los Gerber se exportaron después del último guardado de cada +PCB. El submódulo \texttt{kicad/} está en \texttt{b74b96f} (T34--T38 ya en commits); los paquetes +\texttt{production/HBOX\_v5\_Rev[67]\_PROD*} siguen sin commit. + +\subsection{Método A--G y herramientas} + +\hwtab{\begin{tabular}{@{}L{0.87cm}L{3.20cm}L{11.83cm}@{}} +\toprule +\cab{\cw{} & \cw{Qué} & \cw{Cómo}}\\ +\midrule +A & Integridad del paquete & Regeneración con \texttt{kicad-cli} 10.0.4 en copias (\texttt{\_to\_delete/audit-20261022/}) y comparación primitiva por primitiva (flashes = pads, trazos = pistas, regiones = rellenos) contra lo exportado; rellenado de zonas con el proyecto cargado (\texttt{pcbnew} + \texttt{.kicad\_pro} + \texttt{.kicad\_dru}); BOM/CPL contra las huellas del PCB; rotaciones; pasta; taladros.\\ +\rowcolor{HelgenMist} B & Eléctrica por bloque & Netlist exportado de cada esquemático (254 / 259 componentes, 240 / 241 redes) y revisión de cada bloque contra su hoja de datos: valores, umbrales, pull-ups, estados por defecto, pines al aire.\\ +C & Batería y módem & Presupuesto de corriente en respaldo (límites del LTC4040 y del AP64350), piso dormido por componente, autonomía por ventana/periodo, secuencia de dormir/despertar.\\ +\rowcolor{HelgenMist} D & Cobre final & DRC de KiCad con \texttt{--schematic-parity --refill-zones --severity-all}; prueba Kelvin de RS1 (recortando el área del pad); vías de corte (articulación) por red de potencia; potencia por capas internas; pasta de los pads térmicos.\\ +E & Firmware & Lectura de 0.6.3; \texttt{board\_v56.h} derivado del netlist (los 64 pines, V5.6 = V5.7); inventario de algoritmos existentes; diseño de los que faltan; riesgos.\\ +\rowcolor{HelgenMist} F & Riesgo & Matriz 5 × 5 (probabilidad × impacto) antes y después de las mitigaciones; criterio GO / NO-GO.\\ +G & Entrega y cierre & Este documento, el Beamer, \texttt{board\_v56.h}, el protocolo; lote en el centro de mando, Ruta, decisiones, índice maestro.\\ +\bottomrule +\end{tabular}} + +\begin{helgennotice}[Qué significa cada clase de hallazgo] +\sevA\ \textbf{Bloqueante}: fabricado así, una función del mandato no se cumple ni con firmware, o la tarjeta se +daña. \sevB\ \textbf{Alto}: compromete el mandato en condiciones de campo (calor, batería baja, ráfaga LTE), +pero se mitiga con firmware, BOM o un paso del pedido, y se mide en el piloto. \sevC\ \textbf{Medio}: degrada +una función o la mantenibilidad; se acepta con mitigación. \sevD\ \textbf{Bajo / easy win}: barato y sin +mover piezas (BOM, un valor, firmware, un paso del pedido), o una nota para la siguiente revisión. +\end{helgennotice} diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/sec3-paquete.tex b/03-Architecture-Hardware/Auditoria-Final-V56-V57/sec3-paquete.tex new file mode 100644 index 0000000..e014b31 --- /dev/null +++ b/03-Architecture-Hardware/Auditoria-Final-V56-V57/sec3-paquete.tex @@ -0,0 +1,146 @@ +% ================================================================ PAQUETE +\section{A $\cdot$ El paquete de fabricación}\label{sec:paquete} + +\subsection{¿Los Gerber son el cobre que auditamos?} + +Sí. Cada capa exportada por el Fabrication Toolkit se comparó contra una regeneración hecha hoy con +\texttt{kicad-cli} 10.0.4 sobre copias de los mismos archivos. Primero se compararon los comandos Gerber +quitando solo los comentarios y atributos X2 (\texttt{\%TF}/\texttt{\%TA}/\texttt{\%TO}, que el Toolkit escribe +como \texttt{G04} y \texttt{kicad-cli} como extendidos); después, por tipo de primitiva. + +\hwtab{\begin{tabular}{@{}L{2.83cm}L{1.89cm}L{1.89cm}L{8.87cm}@{}} +\toprule +\cab{\cw{Capa} & \cw{V5.6} & \cw{V5.7} & \cw{Resultado}}\\ +\midrule +F.Mask $\cdot$ B.Mask $\cdot$ F.Paste $\cdot$ B.Paste $\cdot$ F.Silk $\cdot$ B.Silk $\cdot$ Edge.Cuts & idénticas & idénticas & Comando por comando (1319 / 261 / 976 / 5 / 24 702 / 339 / 15 comandos en V5.6).\\ +\rowcolor{HelgenMist} PTH.drl $\cdot$ NPTH.drl & idénticos & idénticos & NPTH: 8 barrenos iguales. PTH: iguales una vez normalizada la notación de ranuras (el Toolkit escribe \texttt{G00/M15/G01/M16}, \texttt{kicad-cli} \texttt{G85}; ambas válidas para JLC).\\ +F.Cu $\cdot$ In1.Cu $\cdot$ In2.Cu $\cdot$ B.Cu — pads (flashes) y pistas (trazos) & idénticos & idénticos & 1236 / 547 / 547 / 547 flashes y 1564 / 130 / 193 / 377 trazos en V5.6; mismos conjuntos exactos en ambos.\\ +\rowcolor{HelgenMist} F.Cu $\cdot$ In1.Cu $\cdot$ In2.Cu $\cdot$ B.Cu — rellenos de zona (regiones) & 0.000 mm$^2$ XOR & 0.000 mm$^2$ XOR & Contra un relleno fresco hecho con \texttt{pcbnew} \emph{con el proyecto cargado} (reglas \texttt{.kicad\_dru} y netclasses). A 20 $\mu$m por pixel no hay un solo pixel distinto.\\ +\bottomrule +\end{tabular}} + +\begin{helgennotice}[Hallazgo P-1 (11:30) — el repo guardaba el relleno viejo; el Gerber traía el fresco. Cerrado a las 13:00] +Las regiones del Gerber \textbf{no} son las que están guardadas en los \texttt{.kicad\_pcb} del repo: contra el +relleno guardado difieren 6.4 mm$^2$ (V5.6 F.Cu), 7.4 mm$^2$ (V5.7 F.Cu) y 9.5 mm$^2$ (V5.7 B.Cu), justo donde la +pasada 6 (T34--T37) agregó vías y movió el hilo de sensado. Los scripts T no rellenan zonas; el Toolkit sí +(\texttt{AUTO FILL: true}). Por eso el paquete está bien, pero \textbf{el archivo en disco no}: una exportación +sin rellenar (o un \texttt{kicad-cli pcb export gerbers}, que no rellena) mandaría cobre de GND encima de la vía +de \net{/SYS5V} en (138.7, 117.45) de T35 y de las vías de entrada de RS1 de T34 (figura \ref{fig:relleno}). +Esto ya lo vimos en forma de «sin conectar» falsos el 21-oct; hoy se vio en forma de corto. +\textbf{Arreglo (Leo, 5 min):} abrir cada tarjeta, \textsf{B}, guardar, \texttt{git commit}. Regla nueva (D-22-3): +\emph{los scripts T que agregan o quitan cobre terminan con un rellenado del GUI antes del commit}. +\textbf{Hecho a las 13:00} (ver la re-verificación al final de esta sección); falta el commit. +\end{helgennotice} + +\begin{figure}[H]\centering +\includegraphics[width=\linewidth]{fig/fig-relleno-viejo.png} +\caption{Relleno guardado en el repo (pasada 5) contra el relleno del Gerber (fresco). En rojo, el cobre que +tendría el archivo en disco y el Gerber no: pasa encima de la vía de T35 en V5.6 y de la vía de GND de C129 de T37 +en V5.7.}\label{fig:relleno} +\end{figure} + +\subsection{Capas, taladros y mínimos contra la capacidad de JLC (4 capas)} + +\hwtab{\begin{tabular}{@{}L{4.20cm}L{3.06cm}L{3.06cm}L{5.16cm}@{}} +\toprule +\cab{\cw{Parámetro} & \cw{V5.6} & \cw{V5.7} & \cw{Límite JLC / comentario}}\\ +\midrule +Contorno & 140.0 × 100.0 mm & 140.0 × 100.0 mm & Igual que V5.5; cabe en el HBOX.\\ +\rowcolor{HelgenMist} Capas de cobre & F $\cdot$ In1 $\cdot$ In2 $\cdot$ B & igual & Stackup JLC04161H-7628 escrito en el archivo (T30): 0.035 / 0.0175 / 0.0175 / 0.035 mm, núcleo 1.065 mm, prepreg 7628.\\ +Pista mínima & 0.20 mm (3 tramos), 0.25 mm (158) & 0.20 (2), 0.25 (167) & JLC 4 capas: 0.09 mm. Holgura mínima por regla 0.15 mm (DRC limpio).\\ +\rowcolor{HelgenMist} Vías & 0.8/0.3 (268) $\cdot$ 0.6/0.3 (118) $\cdot$ 0.8/0.4 (8) $\cdot$ 0.5/0.3 (1) & 268 $\cdot$ 125 $\cdot$ 8 $\cdot$ 1 & Barreno mínimo 0.30 mm (JLC $\ge$ 0.15; las vías de 0.1 mm de \net{/NTC} ya no existen, T30). Anillo mínimo 0.10 mm ($\ge$ 0.13 recomendado por JLC: la 0.5/0.3 es una).\\ +NPTH & 3 × 2.75 mm (MH7/9/10 ArduSimple) $\cdot$ 3 × 3.20 (MH4/5/6 placa base; MH4 en (185.2, 90.3)) $\cdot$ 2 × 3.25 (postes del RJ45 J10) & iguales & Los 6 barrenos de la V5.5 de producción, menos MH11 (abrazadera, decisión del 16-oct).\\ +\rowcolor{HelgenMist} Ranuras PTH & 13 (conectores) & 13 & Expresadas como ruta; JLC las acepta.\\ +Serigrafía & 2 avisos: contorno de MOD1 recortado por el borde; 1 sobre la máscara de MH6 & iguales & Cosméticos.\\ +\rowcolor{HelgenMist} Cajetín & «EINARBoard HBOX V5.6», rev 5.6, 2026-10-19 & «… V5.7», rev 5.7 & Correctos (T30).\\ +Acabado & \texttt{copper\_finish None} en el archivo & igual & Se elige en el pedido: \textbf{ENIG} (recomendado para QFN de 0.5 mm; HASL con plomo vale si el presupuesto manda).\\ +\bottomrule +\end{tabular}} + +\subsection{Pasta y pads térmicos — la condición 1 del pedido} + +El DFM del 8 de octubre (regla permanente: \texttt{drogheda-dfm-ltc4040-qfn}) nació de los puentes y bolas de +soldadura que Leo vio en \refdes{U6} en las V5.5 y V4. La regla pedía pasta $\le$ 50 \% en el pad térmico y +\emph{vías fuera de las ventanas de pasta o pedido con Epoxy Filled \& Capped}. Medido sobre el Gerber de hoy: + +\hwtab{\begin{tabular}{@{}L{2.10cm}L{2.86cm}L{2.29cm}L{2.48cm}L{5.34cm}@{}} +\toprule +\cab{\cw{Pieza} & \cw{Pad térmico} & \cw{Pasta} & \cw{Vías dentro} & \cw{Consecuencia}}\\ +\midrule +\refdes{U6} LTC4040 QFN-24 0.5 mm & 2.65 × 3.65 mm & 6 ventanas 0.95 × 0.85 = \textbf{50 \%} & \textbf{3} (0.6/0.3), las tres dentro de ventanas & Sin tapar, la pasta se mete en la vía: la pieza se inclina y puentea a 0.5 mm. \textbf{Pedir vías Epoxy Filled \& Capped + rayos X en U6.}\\ +\rowcolor{HelgenMist} \refdes{U7} AP64350 ESOP-8 & 3.2 × 2.5 mm & \textbf{100 \%} (huella easyeda2kicad) & 4 (0.8/0.3) & Paso 1.27 mm: tolera, y la misma opción del pedido lo cubre. Siguiente revisión: pasta al 60 \%.\\ +\refdes{U25} TPS54360B HSOP-8 (V5.7) & 2.5 × 3.2 mm & \textbf{100 \%} & 6 (0.8/0.3) & Igual que U7.\\ +\rowcolor{HelgenMist} \refdes{U26} SC7A20 LGA-12 & — & 100 \% (pads 0.5 × 0.28) & 0 & Normal.\\ +\bottomrule +\end{tabular}} + +\begin{figure}[H]\centering +\includegraphics[width=0.92\linewidth]{fig/fig-u6-pasta.png} +\caption{\refdes{U6}: pad térmico, ventanas de pasta al 50 \% y las tres vías térmicas dentro de las ventanas, +en V5.6 y V5.7. Es la razón de la condición 1 del pedido.}\label{fig:u6pasta} +\end{figure} + +\subsection{BOM y lista de posiciones} + +\begin{itemize} +\item \textbf{Cuadre con el PCB.} V5.6: 247 huellas en el PCB; 226 filas en la CPL y 226 referencias en el BOM; + las 21 restantes son exactamente las que deben faltar: \refdes{JP1--JP6}, \refdes{TP1--TP7}, \refdes{MOD1}, + \refdes{MH4/5/6/7/9/10} (fuera de BOM y posiciones, T30) y \refdes{R109} (DNP). V5.7: 252 / 229 / 229, con + \refdes{R124} y \refdes{R125} (DNP, divisor de EN de U25) además. Ninguna fila sin código LCSC; ningún código + distinto entre la propiedad de la huella y el BOM. +\item \textbf{Rotaciones.} El Toolkit corrigió, como en la V5.5, las huellas de biblioteca KiCad (U6 QFN 0$\to$90°, + Q7/U14 SOIC 0$\to$270°, U16 LQFP 180$\to$90°, U17 SOT-223 0$\to$180°, SOT-23 0$\to$180°, CP\_Elec 180$\to$0°, …). Las + huellas \texttt{Drogheda-v6} (easyeda2kicad: \refdes{U7}, \refdes{U25}, \refdes{U26}, \refdes{L22}) y + \refdes{D34} (\texttt{D\_SMC}, nuevo) \emph{no} están en su tabla y salen con la rotación de KiCad. Para huellas + convertidas de EasyEDA eso es lo correcto (conservan la orientación de JLC), pero \textbf{nunca se ha fabricado + con ellas}: condición 2 del pedido, confirmar en el visor. Los diodos SMA/SMB/SOD y las SOT ya pasaron en la + V5.5 con la misma convención. +\item \textbf{Códigos nuevos verificados en JLC:} \refdes{D34} C85100 = B560C-13-F (5 A, 60 V, SMC); + \refdes{F2} C99550 = Littelfuse 0452003.MRL (3 A, 125 V, NANO2 lento); \refdes{L22} C840531 = Bourns + SRP1265A-100M (10 $\mu$H, 15.5 A sat., 16.5 m$\Omega$); \refdes{Y4} C32346 = Epson FC-135 (CL 12.5 pF, 70 k$\Omega$); + \refdes{U17} C15578 = TLV1117LV33DCYR (Iq $\approx$ 100 $\mu$A, no los 5 mA de un AMS1117); \refdes{U25} C524806; + \refdes{U7} C2071691; \refdes{U26} C5126709; \refdes{C129} C19702; \refdes{C130} C1525. Todos «Extended» salvo + los básicos conocidos; existencias se confirman al cargar el BOM. +\item \textbf{Easy wins de BOM} (sin tocar cobre): \refdes{D10} SMBJ33A C224019 $\to$ \textbf{SMBJ33CA} + (bidireccional, misma huella D\_SMB; p.\,ej.\ C8838 Littelfuse o C2688178 — el que tenga existencia); + 10 nF 0603 con dos códigos (\refdes{C100/C125/CBST1} C1589 básico y \refdes{CCOMP2} C57112 extendido): unificar en + C1589; \refdes{C22} dice «22uF/50V» pero C138687 es 10 $\mu$F/50 V (es la pieza que ya se usó en V5.5: corregir la + etiqueta, no la pieza); para las 108 / 322: \refdes{U14} SP3485EN $\to$ THVD1410DR (C2671345, mismo pinout SOIC-8, + receptor a prueba de bus abierto y ±16 kV) y \refdes{U15} MAX3232 $\to$ TRS3232E (mismo SOIC-16), como en la v6. +\end{itemize} + +\subsection{Lo mecánico que cambió sin cambiar el contorno} + +Los conectores que atraviesan la pared del HBOX no se movieron (\refdes{J9}, \refdes{J11} USB-C; \refdes{J10} +RJ45; \refdes{P15}/\refdes{P16}; \refdes{H4}; \refdes{P1}). Los JST internos del borde superior sí: respecto a la +V5.5, \refdes{P4} (batería) 25 mm en V5.6 y 38 mm en V5.7; \refdes{P6} (ventilador) 18 / 29 mm; \refdes{P8} (LED +del panel) 17 / 29 mm; \refdes{P11} (cutoff) 12 / 21 mm; y en V5.7 \refdes{P14} (RGB) pasó del borde derecho al +superior (68 mm) y los LED del gauge \refdes{DB1--DB4} al borde derecho (14--21 mm). Nada de esto rompe la +tarjeta; lo que hay que revisar con la primera unidad son los \textbf{largos de los arneses} y, si el gauge se ve +por la tapa, la \textbf{tapa de la V5.7} (hallazgo P-7). + +\subsection{Re-verificación de las 13:30 sobre los archivos de las 13:00}\label{sec:reverif} + +Leo rellenó las zonas, guardó los dos tableros y regeneró los paquetes a las 13:00 (V5.6 \texttt{338ee14b}, +V5.7 \texttt{85baca51}; \texttt{HBOX\_v5\_Rev6\_PROD.zip} \texttt{01e1a39d}, \texttt{Rev7} \texttt{7d2fe248}; +BOM y CPL con el mismo SHA-256 que en la mañana). Se repitió el método A sobre copias nuevas +(\texttt{\_to\_delete/audit-20261022b/}, script \texttt{verify.sh} + \texttt{gcmp\_b.py}): + +\hwtab{\begin{tabular}{@{}L{7.4cm}L{2.1cm}L{2.1cm}L{4.1cm}@{}} +\toprule +\cab{\cw{Comparación (F.Cu, In1, In2, B.Cu a 20 $\mu$m)} & \cw{V5.6} & \cw{V5.7} & \cw{Lectura}}\\ +\midrule +A $\cdot$ relleno guardado en el \texttt{.kicad\_pcb} vs relleno fresco con el proyecto cargado & 0.000 mm$^2$ & 0.000 mm$^2$ & \textbf{P-1 cerrado}: el archivo en disco ya es lo que se fabrica\\ +\rowcolor{HelgenMist} B $\cdot$ paquete de las 13:00 vs archivo guardado (sin rellenar) & idéntico & idéntico & El Toolkit y el archivo coinciden\\ +C $\cdot$ cobre de las 13:00 vs cobre auditado en la mañana (pads, pistas, rellenos) & idéntico & idéntico & Nada más cambió: 2264 / 396 y 2253 / 403 pistas / vías\\ +\rowcolor{HelgenMist} D $\cdot$ paquete 13:00 vs paquete de la mañana: máscaras, pasta, serigrafía, contorno, taladros & idéntico & idéntico & Mismo paquete, con el relleno ya en el repo\\ +DRC con \texttt{.kicad\_dru}, relleno y paridad & 3 MOD1 $\cdot$ 0 $\cdot$ 13 PF & 3 MOD1 $\cdot$ 0 $\cdot$ 13 PF & Igual que en la mañana\\ +\rowcolor{HelgenMist} BOM y CPL & SHA iguales & SHA iguales & \refdes{D10} sigue como SMBJ33A: la condición 3 sigue viva\\ +\bottomrule +\end{tabular}} + +Lo único distinto dentro de los \texttt{.kicad\_pcb}, fuera de los rellenos, es la caché de glifos +(\texttt{render\_cache}) de los textos de serigrafía «EINARBoard 5.x» y «www.helgen.tech» en la fuente MADE Evolve +Sans: cosmético, porque la serigrafía exportada es idéntica región por región. \textbf{El veredicto de la mañana +no cambia.} Si la sesión paralela de \emph{quick wins} toca el BOM o el cobre, se vuelve a correr +\texttt{verify.sh} + \texttt{gcmp\_b.py} (5 min) antes de pagar. diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/sec4-electrica.tex b/03-Architecture-Hardware/Auditoria-Final-V56-V57/sec4-electrica.tex new file mode 100644 index 0000000..a6bffeb --- /dev/null +++ b/03-Architecture-Hardware/Auditoria-Final-V56-V57/sec4-electrica.tex @@ -0,0 +1,149 @@ +% ================================================================ ELÉCTRICA +\section{B $\cdot$ Revisión eléctrica por bloque}\label{sec:electrica} + +Los dos netlists se exportaron hoy de los esquemáticos auditados. \textbf{Los 64 pines del STM32F411 son +idénticos en V5.6 y V5.7} (apéndice \ref{sec:pinmap}): un solo firmware sirve para las dos. Lo que cambia entre +ellas no toca al MCU: la V5.7 trae la fuente \refdes{U25} y pierde \refdes{P2} (entrada de 5 V) y \refdes{U2} +(buck del ventilador, que pasa a colgar de \net{VEH5V} por \refdes{JP1}). + +\begin{figure}[H]\centering +\resizebox{\linewidth}{!}{\begin{tikzpicture}[node distance=5mm and 7mm, font=\small] + \node[cajaoscura, text width=24mm] (gx) {GX16 P1\\24 V $\cdot$ GND $\cdot$ IGN}; + \node[caja, right=of gx, text width=30mm] (in) {V5.6: Q10 + D10 $\to$ 24 V\\(solo ventilador U2)\\[2pt] V5.7: F2 3 A $\to$ D10 + Q10 $\to$\\\net{/24V} $\to$ \textbf{U25} TPS54360B\\9–32 V $\to$ 5.32 V}; + \node[caja, right=of in, text width=24mm] (veh) {\net{VEH5V}\\V5.6: P2 (SD-15B 5 V)\\V5.7: U25}; + \node[caja, right=of veh, text width=27mm] (ltc) {\textbf{U6 LTC4040}\\RS1 10 m$\Omega$ Kelvin $\to$ 2.5 A\\Q7 ideal diode\\PFI 4.40 V}; + \node[caja, right=of ltc, text width=22mm] (vsys) {\net{MAIN5V} (VSYS)\\C129 $\cdot$ C32/C33\\respaldo 4.79 V}; + \node[caja, below=of ltc, text width=27mm] (bat) {Paquete LFP 1S4P $\cdot$ P4\\L6 2.2 $\mu$H/8 A\\carga 1.40 A $\cdot$ flot. 3.50 V\\NTC R55 5.6k B3380}; + \node[caja, below=of vsys, text width=22mm] (sys) {P11 cutoff / JP6\\\net{SYS5V}}; + \node[caja, below=of sys, text width=22mm, xshift=-32mm] (ldo) {D12 $\to$ U17 TLV1117LV\\\net{3V3} MCU y lógica}; + \node[caja, below=of sys, text width=24mm] (u7) {\textbf{U7 AP64350} 3.33 V\\EN = PC3 (\net{MODEM\_EN})\\\net{3V3\_MODEM} $\cdot$ C43 220 $\mu$F}; + \node[caja, below=of sys, text width=22mm, xshift=32mm] (q1) {F1 PPTC $\to$ Q1 (PA1)\\\net{SW\_5V} $\to$ ArduSimple\\C3 220 $\mu$F}; + \node[caja, below=of ldo, text width=22mm] (eth) {U12 MP1584 $\to$ \net{3V3\_ETH}\\W5500 (sin enable)}; + \node[caja, below=of u7, text width=24mm] (xbee) {J7/J8 zócalo XBee\\4G NTRIP Master\\RST PC1 $\cdot$ LED PC2}; + \node[caja, below=of q1, text width=22mm] (k1) {K1 (PB5) Modo B\\NC: F9P TX2 $\to$ DIN}; + \draw[flecha] (gx) -- (in); \draw[flecha] (in) -- (veh); \draw[flecha] (veh) -- (ltc); \draw[flecha] (ltc) -- (vsys); + \draw[flecha] (ltc) -- (bat); \draw[flecha] (vsys) -- (sys); + \draw[flecha] (sys) -- (ldo); \draw[flecha] (sys) -- (u7); \draw[flecha] (sys) -- (q1); + \draw[flecha] (ldo) -- (eth); \draw[flecha] (u7) -- (xbee); \draw[flecha] (q1) -- (k1); +\end{tikzpicture}} +\caption{Árbol de potencia de V5.6 y V5.7 tal como sale del netlist. Lo nuevo contra V5.5: U25 (V5.7), AP64350 con +enable desde el MCU, C129/C130, RS1 de 10 m$\Omega$ con sensado Kelvin, paquete LFP.}\label{fig:arbol} +\end{figure} + +\subsection{Cargador y respaldo — U6 LTC4040}\label{sec:ltc} + +Todos los valores se recalcularon contra la hoja de datos (ADI, 4040fb) y coinciden con lo que el ECO V5.6 quiso: + +\hwtab{\begin{tabular}{@{}L{3.44cm}L{4.01cm}L{2.87cm}L{5.16cm}@{}} +\toprule +\cab{\cw{Función} & \cw{Piezas / red} & \cw{Valor que resulta} & \cw{Comentario}}\\ +\midrule +Umbral de respaldo (PFI) & R51 270 k / R52 100 k, $V_{PFI}=1.19$ V & \textbf{4.40 V} cae $\cdot$ 4.51 V sube & 30 mV de histéresis. 0.6 V bajo los 5.0 V de la SD-15B; 0.9 V bajo los 5.32 V de U25.\\ +\rowcolor{HelgenMist} Salida en respaldo (BSTFB) & R53 499 k / R54 100 k, ref. 0.8 V & \textbf{4.79 V} & Dentro del rango 3.5–5 V. El AP64350 arranca desde 3.8 V: ya no existe el caso V5.5 (MP1584 pedía 4.5 V).\\ +Límite de corriente de entrada & RS1 10 m$\Omega$, umbral 25 mV & \textbf{2.5 A} & Sensado Kelvin VIN (U6.6) y CLN (U6.7) verificado en el cobre (§\ref{sec:cobre}). Recorta solo la carga; el sistema nunca se limita.\\ +\rowcolor{HelgenMist} Corriente de carga & R50 1.43 k, $I=2000/R$ & \textbf{1.40 A} & C/10 del paquete 4 × 3.6 Ah LFP-HT.\\ +Flotación & JP2 2-3 (F2 = 0 LiFePO4) $\cdot$ JP3 F1 = 0 $\cdot$ JP4 F0 = 1 & \textbf{3.50 V} & Tabla de la hoja de datos (p.~11). Firmware: \texttt{BOARD\_VFLOAT\_V 3.50}.\\ +\rowcolor{HelgenMist} Ventana térmica de carga & R55 5.6 k desde \net{VEH5V}, NTC 10 k B3380 en P4.3 & $\approx$ \textbf{+10 … +60 °C} & Los umbrales son 34.9 \% y 76.5 \% de VIN (ratiométricos: el sesgo desde VIN es el correcto). El divisor R113/R114 a PC5 carga el nodo 4 \% (9.57 k en vez de 10 k): despreciable.\\ +Capacitor de VSYS & C129 10 $\mu$F 0603 junto a U6.1/24 + C32/C33 47 $\mu$F + C34 & 104 $\mu$F & El hallazgo crítico del 19-oct, cerrado (T31) y colocado (pasada 4).\\ +\rowcolor{HelgenMist} CHGOFF / BSTOFF & R56 100 k a GND en PA8 $\cdot$ BSTOFF a GND & carga ON por defecto $\cdot$ boost ON & Ninguno flota (la hoja de datos lo prohíbe). Con el MCU en reset, la carga queda en manos de la ventana NTC y del límite de 2.5 A: no se repite el bucle del 10-ago.\\ +OVSNS & unido a VIN & OVP no usada & Permitido por la hoja de datos (p.~12); el umbral de 6.4 V no se alcanza (VEH5V $\le$ 5.46 V).\\ +\rowcolor{HelgenMist} PFO & solo TP2 & no llega al MCU & El firmware detecta el respaldo por \net{5V\_SENSE} (PA4). Suficiente; una interrupción sería más elegante (v6).\\ +Corriente de respaldo & boost desde 3.2 V & hasta 2.5 A en VSYS & 12 W disponibles contra 8.7 W de pico (§\ref{sec:bateria}). NMOS 6.5 A; L6 8 A de saturación.\\ +\bottomrule +\end{tabular}} + +\subsection{Riel del módem — U7 AP64350}\label{sec:modem} + +\begin{itemize} +\item \textbf{Entrada} \net{SYS5V} con C101/C119/C120 (22 $\mu$F), C121 (10 $\mu$F/25 V) y \textbf{C130 100 nF} + pegado a U7.2 (T32, pasada 5). \textbf{Salida} 0.8 V × (1 + 100 k/31.6 k) = \textbf{3.33 V}; L7 4.7 $\mu$H/4 A + (rizo $\approx$ 0.44 A a 500 kHz); C43 220 $\mu$F polímero + C41 + C122. Frecuencia: RT 200 k $\to$ + \textbf{500 kHz} (450–550). Compensación Rcomp2 9.1 k / Ccomp2 10 nF / C123 68 pF. +\item \textbf{EN = PC3} a través de R105 10 k, con R106 100 k a GND: \textbf{apagado por defecto} (reset del MCU, + firmware viejo). Con PC3 en alto EN = 3.0 V ($>$ 1.25 V). Corriente de apagado 1 $\mu$A. Es lo que hace posible el + ciclo de 10 min: el módem se corta con un pin, sin tocar la etapa. +\item \textbf{RESET = PC1} a través de R107 1 k hacia J7.5, con \refdes{SW4G1} en paralelo a GND. Manejar como + colector abierto (salida en bajo o alta impedancia; nunca en alto). \textbf{LED = PC2} a través de R108 1 k desde + J8.8 (la misma señal que enciende \refdes{D4G1}). \textbf{Toma de RTCM = PC7} (USART6\_RX) a través de R111 1 k + desde \net{DOUT\_4G}: el MCU puede oír las correcciones que el módem manda al F9P. +\item \textbf{Zócalo}: VCC (J7.1) y VREF (J8.7) a \net{3V3\_MODEM}; ON/OFF (J8.1) a GND; USB del módem + (J7.7/J7.8) a \refdes{J9} con \refdes{D19} USBLC6; \net{MODEM\_ON\_SLEEP} (J8.3 $\to$ PC4) con R109 DNP: PC4 queda al + aire — configurar con pull-down. +\end{itemize} + +\subsection{V5.7 — la fuente a bordo y la entrada de 9 a 32 V}\label{sec:v57-fuente} + +Cadena: \refdes{P1.1} $\to$ \refdes{F2} (0452003.MRL, 3 A lento, 125 V) $\to$ \net{/VIN\_FUSED} $\to$ +\refdes{D10} SMBJ33A a GND y \refdes{Q10} IRFR5305 (P-FET: drenador a la entrada, fuente a \net{/24V}, compuerta a +GND por Rrp1 10 k y Zener DzG1 15 V entre fuente y compuerta) $\to$ \net{/24V} (C10 47 $\mu$F/50 V electrolítico, C22 +10 $\mu$F/50 V cerámico, C149/C150 2.2 $\mu$F/100 V, C11 100 nF) $\to$ \refdes{U25} TPS54360B. + +\hwtab{\begin{tabular}{@{}L{3.14cm}L{4.52cm}L{8.25cm}@{}} +\toprule +\cab{\cw{Parámetro} & \cw{Piezas} & \cw{Valor y comentario}}\\ +\midrule +Salida & R121 57.6 k / R122 10.2 k, ref. 0.8 V & \textbf{5.32 V} (5.21–5.43 con ±1 \% en R y ref.). Deja 0.9 V sobre el PFI y 0.2 V bajo el máximo de 5.5 V del LTC4040.\\ +\rowcolor{HelgenMist} Frecuencia & R120 162 k & \textbf{$\approx$ 600 kHz} (RT = 92417$\cdot$f$^{-0.991}$). Lejos del AP64350 (500 kHz) y del LTC4040 (2.25 / 1.125 MHz).\\ +Compensación & R123 13 k $\cdot$ C155 6.8 nF $\cdot$ C156 39 pF & Red tipo II; coincide con el diseño de referencia TI para 5 V / 3.5 A con L = 10 $\mu$H y 2 × 47 $\mu$F.\\ +\rowcolor{HelgenMist} Inductor y diodo & L22 SRP1265A 10 $\mu$H (15.5 A sat.) $\cdot$ D34 B560C (5 A, 60 V) & Rizo $\approx$ 0.7 A a 24 V. D34 disipa $\approx$ 1.2 W a 24 V y 2.8 A (conduce el 78 \% del periodo): se mide su temperatura en banco.\\ +Salida & C153/C154 47 $\mu$F/16 V 1210 + C78 220 $\mu$F polímero & C78 cuelga de una sola vía 0.8/0.3 (aceptado el 21-oct; opcional 2.\textsuperscript{a} vía).\\ +\rowcolor{HelgenMist} Enable / UVLO & R124 523 k y R125 84.5 k \textbf{DNP} & EN flotante = habilitado por la corriente interna; UVLO interno 4.3 V. Si algún día se quiere apagar a $<$ 9 V, se montan.\\ +Rango continuo & D10 (33 V de trabajo, conduce desde 36.7 V) $\cdot$ U25 (4.5–60 V) & \textbf{9–32 V DC}: 12 V y 24 V. Piso: a 2.8 A la regulación necesita $\approx$ 6.5 V.\\ +\rowcolor{HelgenMist} Polaridad invertida & Q10 bloquea; D10 unidireccional conduce & \alerta{F2 abre} (SMD, no se cambia en campo). Con SMBJ33CA no pasa nada: easy win P-4.\\ +Corriente de entrada & 15 W a plena carga & 0.7 A a 24 V $\cdot$ 1.9 A a 9 V. F2 de 3 A lento aguanta el arranque (C10 + C22 + C149/150).\\ +\rowcolor{HelgenMist} Térmico & U25 HSOP-8 con 6 vías en el EP $\cdot$ D34 SMC & $\approx$ 2.5 W en el bloque a 32 V y 2.8 A (U25 $\approx$ 1.0 W, D34 $\approx$ 1.2 W, L22 $\approx$ 0.1 W). A 45 °C en la caja el U25 ronda 100 °C de unión: lejos de los 176 °C de apagado, pero se mide.\\ +Lazo de entrada & C149/C150 a 1 mm de U25.2 & $\approx$ 56 mm$^2$ por centros de pad; In1 es GND sólido debajo (207 de 208 mm$^2$). Decisión D-21-2: se queda y se mide el timbre en SW/VIN (hallazgo E-9).\\ +\bottomrule +\end{tabular}} + +\begin{figure}[H]\centering +\includegraphics[width=0.78\linewidth]{fig/fig-v57-fuente.png} +\caption{V5.7: bloque de la fuente en F.Cu. Toda la corriente de entrada de U25 cruza una vía 0.8/0.3 en +(182.4, 68.1) (hallazgo E-10): a 24 V son 0.7 A y no pasa nada; a 9 V son 1.9 A y se mide con cámara térmica.} +\end{figure} + +\subsection{MCU, relojes, arranque y depuración} + +\refdes{U16} STM32F411RET6 con VBAT unido a \net{3V3} (no hay batería de RTC: no hace falta, el MCU sigue +alimentado en respaldo); HSE \refdes{Y3} 25 MHz HC49-SD con 15 pF (igual que V5.5, probado); \textbf{LSE +\refdes{Y4} Epson FC-135 (CL 12.5 pF, ESR 70 k$\Omega$) con C115/C116 de 12 pF}: la carga efectiva queda en +$\approx$ 8–9 pF, el oscilador corre unas decenas de ppm rápido (irrelevante para un temporizador de 10 min) y +arranca con margen; el firmware pone \texttt{LSEDRV} alto y, si no arranca en 2 s, usa LSI (hallazgo E-12). +BOOT0 con R98 10 k a GND y \refdes{SW2}; BOOT1 (PB2) con R99 10 k a GND; DFU por \refdes{J11} con +\refdes{D14/D15/D16} (ESD) y \refdes{Rdfu1} 22 k en PA10 para que el bootloader no se enganche con ruido en +USART1; NRST con C104, \refdes{SW1}, \refdes{P10} y TP5; SWD en TP3/TP4; VCAP1 4.7 $\mu$F; VDDA por R104 10 $\Omega$ ++ C109/C112. Pines al aire (PA7, PB1, PB10, PC6, PC8–PC12, PD2): el firmware los pone en pull-down para dormir. + +\refdes{PA15} (\net{ETH\_RST}) tiene pull-down de 4.7 k: tras el reset el pin es JTDI con pull-up interno +($\approx$ 40 k) y el nodo queda en $\approx$ 0.35 V — el W5500 arranca en reset, como quiere el ECO. +\refdes{PA5} (\net{IGN\_SENSE}): divisor 22 k arriba / 22 k $\parallel$ 3.3 k abajo (×0.1154) + BAT54 a 3V3: +24 V $\to$ 2.77 V, 13.8 V $\to$ 1.59 V, 12 V $\to$ 1.38 V — \textbf{en máquinas de 12 V \texttt{digitalRead} no es +confiable} (zona indefinida 0.99–2.31 V): ADC con umbrales 0.80 / 0.55 V (hallazgo E-7). + +\subsection{Etapa RTK, Modo B y telemetría} + +\net{PWR\_CTRL} (PA1) $\to$ R1 1 k $\to$ Q5 (MMBT3904) $\to$ \net{GATE\_LS} con R2 10 k a \net{SYS5V} $\to$ Q1 +AO3401A; fuente por F1 (PPTC) desde \net{SYS5V}, drenador a \net{SW\_5V} (C3 220 $\mu$F, C40) $\to$ MOD1.5. Con el MCU +en reset la etapa está apagada (invariante 1). USART2 (PA2/PA3) al UART1 del simpleRTK2B; USART1 RX (PA10) toma +TX2 (NMEA); USART1 TX (PA9) al contacto NO de \refdes{K1}; K1 (bobina en \net{SYS5V}, Q6 por PB5 con R41 pull-down, +D6 1N4148 de rueda libre) en reposo deja TX2 $\to$ \net{DIN\_4G} directo (invariante 2). Sin cambios contra V5.5 +salvo la toma de RTCM en PC7. + +\subsection{Puertos: Ethernet, RS-485, RS-232, USB y sensores}\label{sec:puertos} + +\hwtab{\begin{tabular}{@{}L{2.29cm}L{6.31cm}L{2.10cm}L{4.78cm}@{}} +\toprule +\cab{\cw{Puerto} & \cw{Qué hay (netlist)} & \cw{¿Usable?} & \cw{Reglas y hallazgos}}\\ +\midrule +Ethernet \refdes{J10} & W5500 en SPI2 (PB12–15), INT PC0, RST PA15 con pull-down; RSET 12.4 k; TOCAP 4.7 $\mu$F; 1V2O 10 nF; PMODE con pull-up (auto-negociación); TCT a \net{3V3\_ETH}; pares con 49.9 $\Omega$ a RCT; LED de enlace J10.9/10 & \estado{Sí} & J10.8 al aire (terminación Bob-Smith sin tierra: solo EMC); LED de actividad invertido (J10.11/12): cosmético. \net{3V3\_ETH} siempre encendido (U12 sin enable): en batería el firmware pone el PHY en power-down (13 mA) — hallazgo E-3.\\ +\rowcolor{HelgenMist} RS-485 \refdes{P15} & U14 SP3485EN a 3.3 V; RO $\to$ RXA, DI $\leftarrow$ TXA de U10; \textbf{DE y \nbar{RE} unidos a \nbar{RTSA}}; R82 120 $\Omega$ por JP5 (abierto) & \estado{Sí}, punto a punto & Tras el reset \nbar{RTSA} = 1 $\to$ transmisor encendido: \textbf{ocupa el bus hasta que el firmware escribe EFCR/MCR} ($\sim$1 s en el arranque; también durante DFU). Sin TVS ni polarización de reposo (el SP3485 no es a prueba de bus abierto): bytes basura con el cable suelto. Hallazgo E-4; THVD1410 para las 108 / 322.\\ +RS-232 \refdes{P16} & U15 MAX3232 a 3.3 V con C85–C88 100 nF; T1IN $\leftarrow$ TXB; R1OUT $\to$ RXB; canal 2 a tierra & \estado{Sí} & R1OUT y H4.3 comparten \net{SER\_RXB}: \textbf{H4 (TTL) y P16 nunca al mismo tiempo} (hallazgo E-5; v6 pone R147).\\ +\rowcolor{HelgenMist} TTL \refdes{H4} & 3V3 $\cdot$ TXB $\cdot$ RXB $\cdot$ GND & \estado{Sí} & Mismo canal B del SC16IS752 que el RS-232.\\ +USB-C \refdes{J11} & DFU del MCU (PA11/PA12), ESD, VBUS $\to$ D13 $\to$ LDO (alimenta el MCU sin 24 V) & \estado{Sí} & Igual que V5.5.\\ +\rowcolor{HelgenMist} USB-C \refdes{J9} & Paso directo al USB del módem (J7.7/J7.8) con D19 USBLC6 & \estado{Sí} & Para configurar el 4G NTRIP Master sin sacarlo.\\ +I$^2$C & SHT40 0x44 $\cdot$ TMP102 0x48 (U4, zona del cargador) $\cdot$ TMP102 0x49 (U18, zona del módem) $\cdot$ SC16IS752 0x4D $\cdot$ PCF8574 0x20 $\cdot$ SC7A20 0x18; pull-ups 4.7 k & \estado{Sí} & U4 se movió 54 mm (ahora mide el cargador, no el MCU); U18 es nuevo. El acelerómetro responde WHO\_AM\_I = 0x11; INT1 en PB9 (EXTI9, despertar desde STOP).\\ +\rowcolor{HelgenMist} Gauge y RGB & PCF8574 P0–P3 $\to$ DB1–4 (120 $\Omega$); P4–P6 $\to$ P14 RGB; P7 libre & \estado{Sí} & P7 ya no es el puente de MODEM\_RST de la V5.5.\\ +Ventilador \refdes{P6} & Q2 AO3400A por PA6 (Rgs1 100 k); V5.6 desde U2 (24 V), V5.7 desde \net{VEH5V} por JP1 & \estado{Sí} & \textbf{En respaldo no hay ventilador en ninguna de las dos} (ni U2 ni U25 tienen 24 V): el termostato de batería del firmware es inocuo.\\ +\rowcolor{HelgenMist} Pines de U10 al aire & \nbar{CTSA}, \nbar{CTSB}, GPIO0–7 & — & Entradas CMOS flotando: sin efecto con el control de flujo apagado; v6 las aterriza.\\ +\bottomrule +\end{tabular}} diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/sec5-bateria.tex b/03-Architecture-Hardware/Auditoria-Final-V56-V57/sec5-bateria.tex new file mode 100644 index 0000000..e698697 --- /dev/null +++ b/03-Architecture-Hardware/Auditoria-Final-V56-V57/sec5-bateria.tex @@ -0,0 +1,113 @@ +% ================================================================ BATERÍA +\section{C $\cdot$ Batería, apagón del módem y ciclo de 10 minutos}\label{sec:bateria} + +\subsection{Presupuesto de corriente en respaldo} + +En respaldo el LTC4040 eleva el paquete (3.2--3.5 V) a \textbf{4.79 V} en VSYS y puede entregar \textbf{2.5 A} +(12 W) con el paquete en 3.2 V. De ahí cuelga todo: + +\hwtab{\begin{tabular}{@{}L{3.87cm}L{2.52cm}L{2.52cm}L{6.58cm}@{}} +\toprule +\cab{\cw{Carga} & \cw{Promedio} & \cw{Pico} & \cw{Base del número}}\\ +\midrule +Etapa RTK (simpleRTK2B Pro + F9P) & 0.7 W (0.15 A) & 1.0 W & F9P $\approx$ 85 mA a 3.3 V + LDO + LEDs; medido 0.9 s a NMEA tras STACK ON.\\ +\rowcolor{HelgenMist} Módem 4G (vía U7, $\eta$ 0.9) & 1.5 W (0.31 A) & \textbf{7.3 W (1.5 A)} & 0.4 A promedio a 3.3 V; ráfagas LTE de 2 A a 3.3 V durante $\sim$1 ms (incidente PFI del 24-jul).\\ +MCU y lógica (\net{3V3} por U17) & 0.5 W (0.1 A) & 0.6 W & STM32 a 96 MHz, SC16IS752, MAX3232, SP3485, PCF8574, sensores, LEDs.\\ +\rowcolor{HelgenMist} W5500 (U12, \net{3V3\_ETH}) & 0.05 W en power-down $\cdot$ 0.3--0.5 W activo & — & 13 mA en PD; 65 mA sin enlace; 132 mA con enlace (hoja de datos p.~59).\\ +K1 (Modo B) & 0.15 W si está enganchado & — & Bobina G5V-1 5 V: 30 mA.\\ +\rowcolor{HelgenMist} Ventilador & \textbf{0} & 0 & Sin 24 V no hay 5V\_FAN en ninguna de las dos tarjetas.\\ +\textbf{Total ventana encendida} & \textbf{$\approx$ 2.9 W (0.6 A)} & \textbf{$\approx$ 8.7 W (1.8 A)} & Pico $<$ 2.5 A del boost: margen 0.7 A. Del paquete a 3.2 V: 1.0 A promedio, 3.0 A de pico (0.2 C del 1S4P).\\ +\bottomrule +\end{tabular}} + +\begin{helgennotice}[Por qué ya no hay apagón del módem (mandato 4)] +El caso que mató a la V5.5 fue estructural: su buck del módem (MP1584) necesitaba 4.5 V y el riel de respaldo +era 4.6--4.79 V; una ráfaga lo hundía bajo 4.5 V, el PMIC del módem abortaba y no reintentaba. En V5.6/V5.7 el +AP64350 regula desde \textbf{3.8 V} (1 V de margen bajo los 4.79 V), tiene 220 $\mu$F en su salida y el boost del +LTC4040 entrega 2.5 A contra 1.8 A de pico. El PFI quedó en 4.40 V, 0.2 V más abajo que en EinarBoard 1.0. +Lo que queda es \emph{secuencia}, y eso es firmware: nunca encender el módem al mismo tiempo que la etapa (el +inrush de C3 220 $\mu$F + C40 a través de Q1 es un escalón que el boost cubre en $\sim$100 $\mu$s, pero mejor sin el módem +colgado), y nunca encenderlo con el paquete bajo la rodilla de LFP (2.95 V). Si el firmware respeta eso, no hay +caso de brownout en el hardware de hoy. +\end{helgennotice} + +\subsection{Piso dormido: lo que consume la tarjeta con todo apagado} + +\hwtab{\begin{tabular}{@{}L{5.17cm}L{2.39cm}L{8.35cm}@{}} +\toprule +\cab{\cw{Componente (estado dormido)} & \cw{Potencia} & \cw{Comentario}}\\ +\midrule +W5500 en PHY power-down, vía U12 ($\eta$ 0.85) & \textbf{50 mW} & El rubro más grande; sin power-down serían 300--500 mW. No hay enable de \net{3V3\_ETH} (hallazgo E-3).\\ +\rowcolor{HelgenMist} MCU en STOP + RTC (LSE), reg. principal & 1.5 mW & 42 $\mu$A a 25 °C, $\sim$300 $\mu$A a 85 °C.\\ +MAX3232 (sin shutdown) $\cdot$ SP3485 (DE = \nbar{RE}: receptor o transmisor siempre uno encendido) & 1.5 + 2.5 mW & El SP3485 no puede entrar en shutdown con DE y \nbar{RE} unidos.\\ +\rowcolor{HelgenMist} LED D18 (PWR, siempre encendido) $\cdot$ Rdfu1 22 k hacia el F9P apagado & 4.3 + 0.5 mW & D18 no tiene control; 1.3 mA.\\ +U17 TLV1117LV (100 $\mu$A) $\cdot$ LTC4040 boost en Burst (40 $\mu$A) $\cdot$ U12 Iq $\cdot$ divisores & 1.5 mW & \\ +\rowcolor{HelgenMist} SC16IS752 (sleep) $\cdot$ TMP102 ×2 (shutdown) $\cdot$ SHT40 $\cdot$ SC7A20 (low power) $\cdot$ PCF8574 & 0.5 mW & \\ +U7 AP64350 apagado $\cdot$ etapa apagada $\cdot$ K1 suelto & 0 & Son los tres cortes que tiene el firmware.\\ +\rowcolor{HelgenMist} \textbf{Total estimado} & \textbf{$\approx$ 65--75 mW} & Se mide en el piloto con un PPK2 en BAT+ (gate G1 del plan del 9-sep: $<$ 50 mW era la meta; $<$ 100 mW vale para 10 min).\\ +\bottomrule +\end{tabular}} + +\begin{figure}[H]\centering +\includegraphics[width=0.8\linewidth]{fig/fig-autonomia.png} +\caption{Autonomía del paquete LFP 1S4P (37 Wh útiles) según la ventana encendida por ciclo, el periodo y el piso +dormido. Con 45 s de ventana cada 10 min y 75 mW de piso: $\approx$ 5 días; cada 20 min: $\approx$ 8.5 días. +Con el W5500 activo (450 mW) ninguna combinación llega a 7 días.}\label{fig:autonomia} +\end{figure} + +\subsection{La secuencia del ciclo (lo que 0.7.0 tiene que hacer)} + +\begin{figure}[H]\centering +\begin{tikzpicture}[node distance=3mm and 4mm, font=\scriptsize, + paso/.style={caja, text width=22mm, minimum height=11mm}, + pasoacento/.style={cajaoscura, text width=22mm, minimum height=11mm}] + \node[paso] (s1) {\textbf{1 $\cdot$ Detectar respaldo}\\\net{5V\_SENSE} $<$ 4.2 V (media 200 ms); evento \$PHEV BACKUP}; + \node[paso, right=of s1] (s2) {\textbf{2 $\cdot$ Última palabra}\\\$PHLG + posición guardada por el módem; esperar TX vacío}; + \node[paso, right=of s2] (s3) {\textbf{3 $\cdot$ Apagar}\\MODEM\_EN = 0 $\cdot$ PA1 = 0 $\cdot$ K1 suelto $\cdot$ UARTs en alta Z $\cdot$ W5500 PD $\cdot$ LEDs off}; + \node[pasoacento, right=of s3] (s4) {\textbf{4 $\cdot$ STOP}\\alarma RTC a 10 min (LSE; LSI si no arrancó) $\cdot$ EXTI9 (movimiento) $\cdot$ EXTI \net{5V\_SENSE}}; + \node[paso, below=of s4] (s5) {\textbf{5 $\cdot$ Despertar}\\restaurar relojes; medir vbat (media 200 ms): $<$ 2.95 V $\to$ dormir otra vez (sin módem)}; + \node[paso, left=of s5] (s6) {\textbf{6 $\cdot$ Etapa ON}\\PA1 = 1 (rampa 20 ms opcional); esperar NMEA ($\le$ 30 s)}; + \node[paso, left=of s6] (s7) {\textbf{7 $\cdot$ Módem ON}\\$\ge$ 2 s después: MODEM\_EN = 1; LED en PC2 o RTCM en PC7 en $\le$ 90 s, si no: pulso MODEM\_RST (PC1) 0.5 s, máx. 2}; + \node[paso, left=of s7] (s8) {\textbf{8 $\cdot$ Reportar}\\K1 enganchado; 2 × \$PHLG/\$PHCG (pwr = BATT) + GGA fresco si hay fix; \$PHEV con tiempos del ciclo}; + \node[pasoacento, below=of s8] (s9) {\textbf{9 $\cdot$ Dormir}\\paso 3 otra vez. Ventana meta $\le$ 60 s. Si vuelve el 24 V en cualquier punto: salir a RUN}; + \draw[flecha] (s1) -- (s2); \draw[flecha] (s2) -- (s3); \draw[flecha] (s3) -- (s4); \draw[flecha] (s4) -- (s5); + \draw[flecha] (s5) -- (s6); \draw[flecha] (s6) -- (s7); \draw[flecha] (s7) -- (s8); \draw[flecha] (s8) -- (s9); + \draw[flechaacento] (s9.west) -- ++(-5mm,0) |- (s4.west); +\end{tikzpicture} +\caption{Ciclo de respaldo de 0.7.0. Lo que lo hace posible en hardware: \net{MODEM\_EN} (PC3), \net{PWR\_CTRL} (PA1), +el MCU alimentado en respaldo, el LSE Y4 y la INT1 del SC7A20 en PB9.}\label{fig:ciclo} +\end{figure} + +Reglas que salen del hardware y entran al firmware: +\begin{itemize} +\item \textbf{Umbrales LFP, no Li-ion.} 0.6.3 corta la etapa a 3.40 V y rearma a 3.70 V (Li-ion). En LFP la meseta + está en 3.2--3.3 V: con 3.40 V la tarjeta se declararía vacía con el paquete a medio llenar. Corte en + \textbf{2.95 V} (media de 200 ms, nunca una muestra dentro de una ráfaga), rearme en \textbf{3.20 V}; SoC por + conteo de culombios, no por voltaje (hallazgo F-2 / riesgo R12). +\item \textbf{Nada de \texttt{loop()} a 96 MHz mientras «duerme».} Hoy el estado SLEEP corta \net{PWR\_CTRL} y sigue + girando a 96 MHz ($\approx$ 165 mW): eso solo ya duplica el piso. STOP con alarma RTC es el cambio sustantivo. +\item \textbf{W5500 en power-down, no en reset.} La corriente con RSTn en bajo no está especificada; en + power-down son 13 mA. Sacarlo del reset, escribir PHYCFGR (OPMD = 1, OPMDC = 110) y dejarlo. +\item \textbf{K1 suelto entre ventanas}: 150 mW de bobina serían 2× el piso. Se engancha solo durante los + reportes; la lógica de 0.5.1 (insertar en huecos de $\ge$ 8 ms, soltar antes de cortar) sigue valiendo. +\item \textbf{Módem «encendido pero muerto».} Rdfu1 (22 k en PA10) puede sostener a medias el riel del módem + apagado a través de K1 (NC) y su ESD: el pulso de \net{MODEM\_RST} después de cada \net{MODEM\_EN} es la + defensa, y ya está probado (SW4G1). +\item \textbf{Si el 24 V vuelve a mitad de ciclo}, se sale al modo normal sin reset (en V5.5 el reset era la única + forma de revivir el módem; aquí el riel se controla con un pin). Se conserva como opción + (\texttt{ENABLE\_WAKE\_RESET}). +\end{itemize} + +\subsection{Qué mide el piloto para cerrar esta sección} + +\hwtab{\begin{tabular}{@{}L{5.37cm}L{4.97cm}L{5.57cm}@{}} +\toprule +\cab{\cw{Medición} & \cw{Cómo} & \cw{Criterio de aceptación}}\\ +\midrule +Piso dormido & PPK2 o Joulescope en BAT+, 10 min & $<$ 100 mW (meta 75); histograma sin picos del W5500\\ +\rowcolor{HelgenMist} Arranque del módem en batería & Paquete al 20 \% (3.0 V/celda) y $\ge$ 45 °C; 20 ciclos de 10 min & LED/RTCM en $\le$ 90 s en los 20; \net{MAIN5V} $\ge$ 4.3 V en el osciloscopio durante el arranque\\ +Ráfaga LTE en respaldo & Osciloscopio en \net{SYS5V} y \net{3V3\_MODEM} durante el registro & \net{SYS5V} $>$ 4.3 V; \net{3V3\_MODEM} $>$ 3.1 V; sin reinicio del MCU\\ +\rowcolor{HelgenMist} Carga a 24 V con el sistema encendido & TP1 ÷ 32 contra V$_{RS1}$ (§4.5 de la auditoría del 16-oct) & razón 1.0--1.1 (Kelvin); carga 1.2--1.4 A con etapa + módem encendidos\\ +Transiciones 24 V $\leftrightarrow$ batería & 20 cortes de 10 s con módem registrado & sin reset del MCU; sin caída del módem; \$PHEV BACKUP\_START/END en el servidor\\ +\bottomrule +\end{tabular}} diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/sec6-cobre.tex b/03-Architecture-Hardware/Auditoria-Final-V56-V57/sec6-cobre.tex new file mode 100644 index 0000000..ba8c234 --- /dev/null +++ b/03-Architecture-Hardware/Auditoria-Final-V56-V57/sec6-cobre.tex @@ -0,0 +1,67 @@ +% ================================================================ COBRE +\section{D $\cdot$ El cobre final, sobre los archivos exactos de los Gerber}\label{sec:cobre} + +\subsection{DRC, paridad y ERC} + +\hwtab{\begin{tabular}{@{}L{4.0cm}L{5.6cm}L{5.6cm}@{}} +\toprule +\cab{\cw{Prueba (KiCad 10.0.4, copias)} & \cw{V5.6 \texttt{f07ad5b5}} & \cw{V5.7 \texttt{9373ebe8}}}\\ +\midrule +DRC con \texttt{.kicad\_dru}, relleno y paridad & \textbf{3 errores}, los 3 \texttt{npth\_inside\_courtyard} de MH7/MH9/MH10 contra MOD1 (por diseño, excluidos en el \texttt{.kicad\_pro}) & igual\\ +\rowcolor{HelgenMist} Sin conectar & \textbf{0} & \textbf{0}\\ +Paridad con el esquemático & 13 avisos: solo los PWR\_FLAG (PF1--PF14) & igual\\ +\rowcolor{HelgenMist} Avisos & 87 «no coincide con la biblioteca» (bibliotecas globales de la Mac y los courtyards de T38 en U7/U26), 2 de serigrafía en el borde (MOD1), 1 serigrafía sobre máscara (MH6) & 89 (+U25, L22) $\cdot$ 2 $\cdot$ 1\\ +ERC & 25 infracciones, 0 errores (las mismas que el 20-oct) & 27, 0 errores\\ +\bottomrule +\end{tabular}} + +\subsection{Sensado Kelvin de RS1 — comprobado otra vez} + +La prueba del 21-oct se repitió con un método independiente: se recorta el área del pad de RS1 del cobre y se +pregunta a dónde llega el hilo de sensado. \textbf{V5.6 y V5.7: U6.6 (VIN) solo llega a su propio pad y a nada +más; U6.7 (CLN) igual.} La corriente de entrada entra a RS1.1 por dos vías 0.6/0.3 ((150.7, 115.9) y +(150.9, 116.6), unidas en F.Cu y B.Cu) y sale de RS1.2 a Q7 sin pasar por los hilos de sensado. El límite de +entrada queda en 25 mV / 10 m$\Omega$ = 2.5 A, no en el $\approx$ 1 A de la V5.5. + +\begin{figure}[H]\centering +\includegraphics[width=\linewidth]{fig/fig-rs1-kelvin.png} +\caption{RS1 en F.Cu, V5.6 y V5.7: hilos de sensado de 0.25 mm (VIN y CLN) hacia su pad, entrada de potencia por +dos vías y salida directa a Q7.}\label{fig:kelvin} +\end{figure} + +\subsection{Vías únicas en las redes de potencia} + +Para cada red de potencia se buscaron las vías cuya ausencia parte la red (puntos de articulación). Lo que queda +coincide con lo aceptado el 19 y 21-oct, con dos observaciones nuevas: + +\hwtab{\begin{tabular}{@{}L{2.4cm}L{5.8cm}L{2.4cm}L{4.6cm}@{}} +\toprule +\cab{\cw{Red} & \cw{Vía única y lo que aísla} & \cw{Corriente} & \cw{Veredicto}}\\ +\midrule +\net{/VEH5V} & (160.155, 113.19) $\to$ U6.16 OVSNS (ambas); (136.1, 42.5) $\to$ JP1 ventilador (V5.6); (145.9, 57.6) $\to$ C78 + C30 + R55 + R7 (V5.7) & sensado $\cdot$ 0.2 A $\cdot$ bulk & Aceptadas. C78 cuelga de una vía: su efecto en alta frecuencia es menor, el de ms (ráfagas) se conserva.\\ +\rowcolor{HelgenMist} \net{/SYS5V} & (170.9, 47.1) / (165.4, 47.1) $\to$ R2 (pull-up); \textbf{V5.7 (146.37, 86.96) 0.6/0.3 $\to$ D12 + U12 + C101} & 0 $\cdot$ \textbf{$\approx$ 0.3 A} & \textbf{Nuevo, E-11:} por esa vía pasan el LDO del MCU (D12) y el buck del W5500. Eléctricamente sobra (una 0.3 mm aguanta $\sim$1 A); es un punto único de falla para el cerebro de la tarjeta. Siguiente revisión.\\ +\net{/BAT\_PLUS} & (155.5, 109.2), (172.0, 113.2), (169.8, 113.4) $\to$ U6.23 + C35; (153.4, 60.0) $\to$ R5 & sensado $\cdot$ sensado & El pin BAT del LTC4040 es de sensado; la corriente va de P4 a L6. Aceptadas.\\ +\rowcolor{HelgenMist} \net{/24V} V5.7 & \textbf{(182.4, 68.1) 0.8/0.3} y (184.0, 121.8) $\to$ toda la entrada de U25 & 0.7 A a 24 V $\cdot$ 1.9 A a 9 V & \textbf{E-10:} aceptada el 21-oct para 24 V. A 9 V se mide con cámara térmica. Segunda vía en la siguiente revisión.\\ +\net{/24V} V5.6 & 4 vías 0.6--0.8 hacia U2 (ventilador) & 0.1 A & Aceptadas.\\ +\rowcolor{HelgenMist} \net{/3V3\_ETH} & (86.6, 52.7) y (95.2, 57.2) $\to$ todo el W5500 & 0.13 A & Aceptadas (herencia V5.5).\\ +\net{/SW\_IN} & (195.1, 60.6) y (132.0 / 122.6, 44) $\to$ Q1; 86 / 95 mm en In2 a 1.0 mm & 0.2 A & Herencia V5.5; $\approx$ 80 m$\Omega$, 20 mV. Aceptada.\\ +\rowcolor{HelgenMist} \net{/ETH\_SW} $\cdot$ \net{/SW\_FAN} & nodos de conmutación de U12 y U2 por vías y capas internas (16--28 mm) & — & Herencia V5.5 (auditoría EMC del 22-ago): ruido, no falla. v6.\\ +\bottomrule +\end{tabular}} + +\subsection{Potencia por capas internas y lazos de los convertidores} + +\net{/SYS5V} tiene 20.2 mm (V5.6) / 14.7 mm (V5.7) en In2 a 1.5 mm: es la rama hacia R2 que se permitió el 19-oct. +\net{/BAT\_PLUS}, \net{/MAIN5V}, \net{/VEH5V}, \net{/3V3\_MODEM}, \net{/SW\_BAT} y \net{/SW3\_NODE}: 0 mm en capas +internas en las dos tarjetas. \net{/SW\_BAT} (nodo del boost del LTC4040, hasta 4 A de pico en respaldo) va en F.Cu +a 0.75--1.0 mm y $\approx$ 15 mm hasta L6: mejor que los 0.3 mm de la V5.5 que señaló la auditoría EMC, todavía +tibio a plena carga; se mide la temperatura de L6/U6 en el piloto. Lazos: U7 con C130 a 1.8 mm del pin VIN y L7 a +4.0 / 0.4 mm del pin SW; U25 (V5.7) con D34 a 2.3 mm de L22 y C149/C150 a 1 mm del pin VIN (lazo $\approx$ 56 mm$^2$ +sobre plano sólido, D-21-2); U12/L8 y U2/Dbk1 como en V5.5 (35 y 18 mm: ruido, no falla; v6). + +\subsection{Netclasses: una nota para la siguiente revisión} + +La clase \net{HV24} (holgura 0.5 mm) cubre \net{/24V\_IN}, \net{24V}, \net{IGN\_IN} y \net{Q10\_GATE}. En la V5.7 +las redes nuevas \net{/VIN\_FUSED} y \net{/SW\_PWRIN} quedaron en la clase por defecto (0.2 mm). A 32 V con +máscara eso sobra (IPC-2221 pide 0.13 mm), y el DRC salió limpio; es higiene de proyecto, no un hallazgo de +fábrica (E-15). diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/sec7-firmware.tex b/03-Architecture-Hardware/Auditoria-Final-V56-V57/sec7-firmware.tex new file mode 100644 index 0000000..0991af0 --- /dev/null +++ b/03-Architecture-Hardware/Auditoria-Final-V56-V57/sec7-firmware.tex @@ -0,0 +1,150 @@ +% ================================================================ FIRMWARE +\section{E $\cdot$ Firmware: dónde estamos y qué hace falta para que «todo funcione»}\label{sec:firmware} + +\subsection{0.6.3 contra el hardware de V5.6 / V5.7} + +El firmware de campo (\texttt{hbox\_v5\_bringup} 0.6.3, 2025 líneas) sirve a la V5.5 y a la V4. Sobre una V5.6 +compila y arranca, pero \textbf{no enciende el módem} y lee mal dos entradas: + +\hwtab{\begin{tabular}{@{}L{3.37cm}L{4.37cm}L{4.37cm}L{3.37cm}@{}} +\toprule +\cab{\cw{Función} & \cw{0.6.3 (V5.5)} & \cw{V5.6 / V5.7 (netlist)} & \cw{Efecto con 0.6.3}}\\ +\midrule +Riel del módem & siempre encendido (MP1584 desde el riel) & \net{MODEM\_EN} = PC3, apagado por defecto & \alerta{el módem nunca enciende}\\ +\rowcolor{HelgenMist} Reset del módem & PCF8574 P7 $\to$ puente a SW4G1 & PC1 directo (R107) & el pulso no hace nada\\ +LED del módem & no se lee & PC2 & sin señal de vida\\ +\rowcolor{HelgenMist} NTC & PB1, 3V3--10k--NTC--GND & PC5, nodo NTC del LTC4040 ×0.5455 & lectura basura\\ +Flotación & 4.00 V (Li-ion) & 3.50 V (LFP, JP2 2-3) & rearranques de carga mal juzgados (0.95 × flot.)\\ +\rowcolor{HelgenMist} Corte en batería & 3.40 / 3.70 V & LFP: 2.95 / 3.20 V & corta con el paquete a medio llenar\\ +Ignición & \texttt{digitalRead} PA5 & ADC (12 V $\to$ 1.38 V) & aleatoria en máquinas de 12 V\\ +\rowcolor{HelgenMist} Acelerómetro $\cdot$ RTCM & — & SC7A20 en 0x18 (INT1 PB9) $\cdot$ USART6 RX en PC7 & sin usar\\ +Ciclo en batería & \texttt{ENABLE\_DUTY 0}; con 1: espera activa a 96 MHz, 120--180 s por ventana & STOP + RTC posible (LSE Y4) & piso de 165 mW solo por el MCU\\ +\bottomrule +\end{tabular}} + +\textbf{Entregado hoy:} \texttt{04-Source-Code/firmware/hbox\_v5\_bringup/board\_v56.h}, el mapa de los 64 pines +derivado del netlist (idéntico para V5.6 y V5.7), con los umbrales del hardware como constantes y las notas de +cada pin nuevo. Extracto: + +\begin{lstlisting} +#define PIN_MODEM_EN PC3 // -> R105 10k -> EN del AP64350; R106 100k a GND: HIGH = 3V3_MODEM encendido +#define PIN_MODEM_RST PC1 // -> R107 1k -> J7.5 (RESET XBee, activo en BAJO; SW4G1 en paralelo). Colector abierto. +#define PIN_MODEM_LED PC2 // <- R108 1k <- J8.8 (LED del modem). Entrada. +#define PIN_RTCM_TAP PC7 // USART6_RX <- R111 1k <- DOUT_4G (RTCM3 hacia RX2 del F9P). Solo escucha. +#define PIN_ACC_INT1 PB9 // INT1 del SC7A20 (EXTI9): despertar por movimiento desde STOP +#define PIN_NTC_CELL PC5 // nodo NTC del LTC4040 x 120k/(100k+120k); solo con VEH5V presente +#define PIN_IGN_SENSE PA5 // ADC: x0.1154; umbral 0.80 V ON / 0.55 V OFF (12 V -> 1.38 V) +#define BOARD_PFI_FALL_V 4.40f // R51 270k / R52 100k +#define BOARD_VSYS_BACKUP_V 4.79f // R53 499k / R54 100k +#define BOARD_VFLOAT_V 3.50f // JP2 2-3 (LFP), F1 = 0, F0 = 1 +#define BOARD_ICHG_A 1.40f // R50 1.43k +#define BOARD_IIN_LIMIT_A 2.50f // RS1 10 mR Kelvin +\end{lstlisting} + +\subsection{Los algoritmos que ya existen (0.6.3) y que 0.7.0 hereda}\label{sec:algoritmos} + +\paragraph{1 $\cdot$ Gobernador de carga (\texttt{chargeService}).} El cargador no se enciende «porque sí»: se +enciende cuando el riel demuestra que puede con la carga y se corta antes de que el PFI lo haga. Nació del incidente +del 10-ago (carga + ráfaga LTE $\to$ PFI $\to$ bucle de reinicios). Con RS1 Kelvin el LTC4040 ya recorta solo a 2.5 A, +pero el gobernador sigue siendo la segunda línea. + +\begin{figure}[H]\centering +\begin{tikzpicture}[->, >=Stealth, node distance=17mm and 13mm, auto, font=\scriptsize, + every state/.style={draw=HelgenIndigo, fill=HelgenMist, text=HelgenIndigo, minimum size=11mm, inner sep=1pt}, + every edge/.style={draw=HelgenIndigo, thick}] + \node[state] (init) {INIT}; + \node[state, right=of init] (hold) {HOLDOFF}; + \node[state, right=of hold] (prov) {PROVING}; + \node[state, right=of prov] (on) {ON}; + \node[state, below=of on] (shed) {SHED}; + \node[state, left=of shed] (cool) {COOLDOWN}; + \node[state, left=of cool] (wait) {WAIT}; + \node[state, above=of prov, yshift=-6mm] (hot) {HOT}; + \path (init) edge node {arranque} (hold) + (hold) edge node {120 s} (prov) + (prov) edge node {riel $\ge$ 5.05 V 30 s} (on) + (on) edge node[right] {$<$ 4.70 V (muestra) o media $<$ 4.90 V 1 s} (shed) + (shed) edge node[above] {5 V sigue 3 s} (cool) + (shed) edge[bend left=25] node[below, pos=0.6] {5 V se fue} (wait) + (cool) edge node[above] {60 s $\cdot$ 2$^n$ $\cdot$ 30 min} (wait) + (wait) edge[bend left=15] node[left, pos=0.3] {riel OK} (prov) + (on) edge[bend right=20] node[above left] {celda $\ge$ 45 °C} (hot) + (hot) edge[bend right=20] node[above right] {$<$ 40 °C} (prov); +\end{tikzpicture} +\caption{Gobernador de carga (0.6.1--0.6.3). HOLDOFF también tras cada STACK ON (ventana de registro LTE). +Un corte cuenta y dobla el enfriamiento solo si el 5 V sigue ahí 3 s después. Pulso de rearranque de 500 ms del +LTC4040 bajo 0.95 × flotación; nunca con FAULT activo. En 0.7.0 cambian las constantes de flotación y de paquete +(LFP), no la máquina.} +\end{figure} + +\paragraph{2 $\cdot$ Recuperación de enlace.} Gracia de 90 s tras STACK ON; sin NMEA válido 60 s $\to$ ciclo de etapa +(máximo uno cada 5 min); RTK perdido 15 min después de haberlo tenido $\to$ ciclo (uno cada 30 min); tres ciclos +$\to$ \textbf{LIMP} (se queda encendida y lo reporta). Invariante 3: las correcciones viven en el módem, el ciclo +de etapa es el remedio, nunca un reset del GNSS. \textbf{0.7.0:} el ciclo de etapa incluye al módem en orden — +\net{MODEM\_EN} = 0, PA1 = 0, esperar 10 s a que los rieles lleguen a 0 V (PWR\_RETURN\_OFF\_MS), PA1 = 1, NMEA, +\net{MODEM\_EN} = 1 — para no cargar el boost con el módem registrándose mientras la etapa hace inrush (F-8). + +\paragraph{3 $\cdot$ Modo B y telemetría en banda.} K1 se engancha 10 s después del primer NMEA; el MCU retransmite +TX2 del F9P hacia el módem y \emph{inyecta} sus líneas solo cuando el anillo de transmisión lleva $\ge$ 8 ms vacío +(nunca parte una sentencia): \texttt{\$PHLG} (campos 1--24, $\le$ 100 caracteres: el 4G NTRIP Master tira líneas de +más de $\sim$108) cada 30 s, \texttt{\$PHCG} (energía y gobernador) en el hueco siguiente, \texttt{\$PHEV} por evento; +antes de cortar la etapa o reiniciar, se vacía la cola y se suelta K1. El servidor (\texttt{retranslator.py}, +\texttt{\_parse\_phlg} / \texttt{\_parse\_phcg}) no cambia. Fail-safe: con el MCU muerto, K1 suelto = F9P $\to$ +módem directo. + +\paragraph{4 $\cdot$ Vigilancia del módem.} Hoy es indirecta: la caída del riel en ventanas de 30 s (ráfagas LTE += vivo; plano 4 ventanas = oscuro, con histéresis 30/50 mV) y la edad del RTCM en los campos 13/14 del GGA. +\textbf{0.7.0} la vuelve directa con el hardware nuevo: \net{MODEM\_LED} (PC2) y la toma de RTCM3 (PC7, bytes 0xD3 +en los últimos 120 s). Pulso de \net{MODEM\_RST} (PC1, 500 ms) 5 s después de \net{MODEM\_EN} y si no hay vida en +90 s (máximo 2 por ventana). + +\paragraph{5 $\cdot$ Cortes térmicos y de batería.} Etapa fuera a 60 °C (TMP102 o NTC), rearme a 55; aviso a 50. +Batería: corte y rearme por media de 200 ms (0.6.3). \textbf{0.7.0:} umbrales LFP (2.95 / 3.20 V) y la +temperatura de la celda ya no viene de un NTC propio sino de U4 (cargador) y U18 (módem); \net{NTC\_CELL} se +reporta solo con 24 V presente. + +\paragraph{6 $\cdot$ Ventilador.} Política v3.0.3: con vehículo (5 V + ignición) 100 \% siempre; en batería termostato +48/45 °C — que en V5.6/V5.7 no tiene efecto porque sin 24 V no hay 5V\_FAN. Sin cambios. + +\paragraph{7 $\cdot$ Medición.} ADC calibrado con VREFINT de fábrica; muestras rápidas por lazo con mínimo de ventana +(detecta la ráfaga) y media de 200 ms (decide); la media del paquete, no una muestra, para cortar. + +\paragraph{8 $\cdot$ Supervisión propia.} IWDG de 16 s; razón de cada reset propio en los registros de respaldo del +RTC (sobrevive al reset) y en el \texttt{\$PHEV BOOT} siguiente; holdoff de carga ×2$^n$ tras un reset causado por +una carga; bandera MANUAL en EEPROM emulada (solo 0x5A = manual). + +\paragraph{9 $\cdot$ Ciclo de respaldo (nuevo).} La figura \ref{fig:ciclo}. Despertadores: alarma RTC (10 min; +adaptativo 15 $\to$ 30 $\to$ 60 min después de 24 h es una opción que el servidor puede pedir), INT1 del SC7A20 +(movimiento: la máquina se mueve, hay que reportar) y el regreso del 24 V. Posición: la última guardada con +\texttt{pwr=BATT} y bandera de antigüedad; un fix fresco solo si llega en la ventana. + +\subsection{Lo que falta para 0.7.0, con tamaño} + +\hwtab{\begin{tabular}{@{}L{0.78cm}L{6.27cm}L{1.96cm}L{6.47cm}@{}} +\toprule +\cab{\cw{} & \cw{Trabajo} & \cw{Tamaño} & \cw{Prueba que lo cierra}}\\ +\midrule +F-1 & \texttt{board\_v56.h} + \texttt{-DHBOX\_BOARD\_V56}; MODEM\_EN/RST/LED en setStack y en el arranque; NTC\_CELL; flotación y umbrales LFP; ignición por ADC & \textbf{1 día} (0.7.0-pre) & Tarjeta del piloto en banco: el módem enciende 2 s después del NMEA, registra, RTCM en PC7; \texttt{tntc} razonable a 24 V; ignición OK a 12 y 24 V\\ +\rowcolor{HelgenMist} F-2 & Ciclo de respaldo: STOP + alarma RTC (LSE con fallback LSI), apagado ordenado, W5500 PD, K1 suelto, reporte ×2, despertar por INT1 & 3--4 días & 20 ciclos con paquete al 20 \% a 45 °C; piso $<$ 100 mW; el servidor ve 2 líneas por ventana\\ +F-3 & SC16IS752: driver mínimo (baudios, FIFO, IRQ en PB8); \textbf{EFCR auto-RS-485 + RTS en bajo como primera escritura}; eco/lazo para las pruebas B3/B4 & 1 día & RS-485 y RS-232 en lazo a 115200 sin errores; bus libre $<$ 100 ms después del reset\\ +\rowcolor{HelgenMist} F-4 & Ethernet de campo: DHCP o IP fija configurables, servidor/puerto configurables, reconexión, PD en batería (parte del 0.6.0-eth ya existe) & 2 días & 24 h de espejo NMEA + \$PHLG a un servidor TCP sin bloquear el lazo\\ +F-5 & SC7A20: WHO\_AM\_I 0x11, 10 Hz low power, umbral de movimiento, INT1 enclavada & 0.5 día & Golpe en la mesa despierta del STOP\\ +\rowcolor{HelgenMist} F-6 & Vigilancia del módem por LED y RTCM; pulso de reset con límite & 0.5 día & Desconectar la antena LTE: la unidad lo reporta en $\le$ 2 min\\ +F-7 & Modo B con el módem apagado/encendido por software: no insertar hasta que el módem viva; soltar antes de MODEM\_EN = 0 & 0.5 día & Sin líneas truncadas en el historial crudo del servidor\\ +\rowcolor{HelgenMist} F-8 & Secuencia de recuperación con módem (arriba) & 0.5 día & 10 ciclos de recuperación forzados sin reset del MCU\\ +\bottomrule +\end{tabular}} + +Compilación como hasta ahora: arduino-cli + STM32duino 3.x, \path{GenF4:pnum=GENERIC_F411RETX,usb=CDCgen,xserial=generic,rtlib=nanofp} (sin \texttt{nanofp} el \texttt{\%f} sale vacío), \texttt{build\_opt.h} con anillos UART de +256, HSE 25 MHz por \texttt{SystemClock\_Config}. Binario con la tarjeta en el nombre: +\texttt{hbox-tarjetaV56\_0.7.0.bin} (sirve a V5.7). \textbf{Regla que no cambia: banco antes de campo.} + +\begin{helgennotice}[Dónde puede fallar el firmware aunque el hardware esté bien (riesgos F)] +(a) \textbf{STOP mal hecho}: un periférico con reloj encendido o un pin flotando duplican el piso; se mide, no +se supone. (b) \textbf{Rearranque del módem}: si \net{3V3\_MODEM} no llega a 0 V entre ventanas (C43 de 220 $\mu$F con +$\mu$A de carga tarda; Rdfu1 lo sostiene), el módem puede quedar «encendido pero muerto»: el pulso de reset es la +defensa y hay que verificar que SW4G1-por-PC1 revive al 4G NTRIP Master en ese estado. (c) \textbf{El 4G NTRIP +Master tarda}: registro + NTRIP $\approx$ 20--40 s; la ventana no puede ser de 10 s. (d) \textbf{RTC}: LSE que no +arranca sin fallback = unidad que no despierta. (e) \textbf{Líneas largas}: cualquier campo nuevo en \texttt{\$PHLG} +rompe el límite de $\sim$100 caracteres del módem; lo nuevo va en \texttt{\$PHCG}/\texttt{\$PHEV}. +\end{helgennotice} diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/sec8-hallazgos.tex b/03-Architecture-Hardware/Auditoria-Final-V56-V57/sec8-hallazgos.tex new file mode 100644 index 0000000..50b068b --- /dev/null +++ b/03-Architecture-Hardware/Auditoria-Final-V56-V57/sec8-hallazgos.tex @@ -0,0 +1,61 @@ +% ================================================================ HALLAZGOS +\section{Hallazgos: problema $\to$ arreglo}\label{sec:hallazgos} + +Clases: \sevA\ bloqueante $\cdot$ \sevB\ alto $\cdot$ \sevC\ medio $\cdot$ \sevD\ bajo / easy win. «Pedido» = se resuelve en el +formulario de JLC o en el BOM sin tocar cobre; «0.7.0» = firmware; «Piloto» = se mide en banco; «Rev. sig.» = +cambio de cobre para la siguiente revisión (no detiene el pedido). + +{\footnotesize +\begin{longtable}{@{}L{0.83cm}L{0.46cm}L{1.39cm}L{5.19cm}L{5.00cm}L{1.76cm}@{}} +\toprule +\cab{\cw{Id} & \cw{} & \cw{Tarjeta} & \cw{Problema (dónde)} & \cw{Arreglo} & \cw{Quién}}\\ +\midrule +\endfirsthead +\toprule +\cab{\cw{Id} & \cw{} & \cw{Tarjeta} & \cw{Problema (dónde)} & \cw{Arreglo} & \cw{Quién}}\\ +\midrule +\endhead +\multicolumn{6}{l}{\emph{Paquete y pedido}}\\ +P-1 & \ok & ambas & Los \texttt{.kicad\_pcb} del repo traían el relleno de zonas de la pasada 5; el relleno fresco solo existía en el Gerber del Toolkit (fig.~\ref{fig:relleno}). & \textbf{Cerrado a las 13:00} (§\ref{sec:reverif}): rellenado, guardado y paquetes regenerados; 0.000 mm$^2$. Falta el commit. Regla D-22-3. & Leo (commit)\\ +\rowcolor{HelgenMist} P-2 & \sevB & ambas & \refdes{U6} QFN-24 0.5 mm: 3 vías térmicas dentro de las ventanas de pasta (50 \%); \refdes{U7}/\refdes{U25} con pasta al 100 \% y vías en el pad. La causa de los puentes de V5.5/V4. & \textbf{Pedido: vías «Epoxy Filled \& Capped» + rayos X en U6}; lupa en U6 antes de energizar cada tarjeta. Rev. sig.: pasta 60 \% en U7/U25. & Leo (pedido) $\cdot$ Jesús (lupa)\\ +P-3 & \sevB & ambas & Rotación de \refdes{U7}, \refdes{U25}, \refdes{U26}, \refdes{L22} (easyeda2kicad, sin corrección del Toolkit) y polaridad de \refdes{D34} nunca fabricadas. & Confirmar en el visor de JLC (pin 1, cátodo, «+» de C3/C43/C78/C10/C103, D10, Q10). & Leo, al pedir\\ +\rowcolor{HelgenMist} P-4 & \sevD & V5.7 (V5.6) & \refdes{D10} SMBJ33A unidireccional: con el arnés al revés conduce y abre \refdes{F2} (SMD, no se cambia en campo); en V5.6 sin fusible quema D10. & BOM: SMBJ33CA (C8838 o C2688178, misma huella D\_SMB). Easy win. & Leo, antes de pedir\\ +P-5 & \sevD & ambas & \refdes{U14} SP3485 sin receptor a prueba de bus abierto ni ESD especificada; \refdes{U15} MAX3232 sin ESD. & Para las 108 / 322: THVD1410DR (C2671345) y TRS3232E, mismo pinout (pre-orden). El piloto va como está. & Adriana (pre-orden)\\ +\rowcolor{HelgenMist} P-6 & \sevD & ambas & 10 nF 0603 con dos códigos (C1589 básico, C57112 extendido); \refdes{C22} etiquetado 22 $\mu$F pero C138687 es 10 $\mu$F/50 V. & Unificar en C1589 (una línea menos); corregir la etiqueta de C22. & Leo, BOM\\ +P-7 & \sevC & V5.7 (V5.6) & JST del borde superior movidos 12--38 mm; en V5.7 \refdes{P14} (RGB) 68 mm y \refdes{DB1--DB4} al borde derecho. & Medir arneses con la primera tarjeta; tapa V5.7 si el gauge se ve por la tapa. & Jesús, piloto\\ +\rowcolor{HelgenMist} P-8 & \sevD & ambas & MH11 (abrazadera del disipador de V5.5) ya no existe: U6/L6 sin abrazadera. & Temperatura de U6 y L6 en banco a 1.4 A de carga y 45 °C; si hace falta, disipador adhesivo. & Jesús, piloto\\ +\multicolumn{6}{l}{\emph{Eléctrica}}\\ +E-1 & \ok & ambas & LTC4040: PFI 4.40/4.51 V, respaldo 4.79 V, 2.5 A Kelvin, 1.40 A, 3.50 V LFP, NTC +10…+60 °C, C129, CHGOFF/BSTOFF atados, OVSNS = VIN. & Nada. Verificado contra la hoja de datos. & —\\ +\rowcolor{HelgenMist} E-2 & \ok & ambas & Riel del módem: AP64350 3.33 V a 500 kHz desde \net{SYS5V}, EN apagado por defecto, C130, C43 220 $\mu$F, RST/LED/EN/RTCM al MCU. & Nada. El caso de brownout de V5.5 desapareció por diseño. & —\\ +E-3 & \sevB & ambas & \net{3V3\_ETH} (U12) no tiene enable: el W5500 cuelga siempre; en reset su corriente no está especificada, activo 65--132 mA. & 0.7.0: sacar del reset y poner el PHY en power-down (13 mA) antes de dormir. Rev. sig.: enable (como v6). & 0.7.0\\ +\rowcolor{HelgenMist} E-4 & \sevC & ambas & RS-485: DE y \nbar{RE} en \nbar{RTSA}: transmisor encendido desde el reset hasta que el firmware configura U10 (ocupa el bus $\sim$1 s; también en DFU). Sin TVS ni polarización. & 0.7.0: EFCR/MCR primero. Uso punto a punto. THVD1410 (P-5). Rev. sig.: inversor U32 + TVS D39 como v6. & 0.7.0 $\cdot$ BOM\\ +E-5 & \sevD & ambas & RS-232: R1OUT de U15 y H4.3 comparten \net{SER\_RXB}. & Regla de uso: H4 y P16 nunca juntos. Rev. sig.: R147 1 k. & Manual\\ +\rowcolor{HelgenMist} E-6 & \sevD & ambas & Ethernet: J10.8 al aire (Bob-Smith), LED de actividad invertido. & Cosmético. Rev. sig. & Rev. sig.\\ +E-7 & \sevB & V5.7 & Ignición a 12 V = 1.38 V en PA5: zona indefinida del STM32. & 0.7.0: ADC con histéresis 0.80 / 0.55 V. Con el gabinete a 24 V no aplica. & 0.7.0\\ +\rowcolor{HelgenMist} E-8 & \sevD & V5.7 & Entrada 9--32 V con F2 SMD: en campo el breaker del gabinete sigue siendo la protección. & Nada; documentar en el manual. & Manual\\ +E-9 & \sevC & V5.7 & U25: lazo de entrada $\approx$ 56 mm$^2$ (D-21-2) y $\approx$ 2.5 W en el bloque a 32 V / 2.8 A. & Banco: timbre en SW/VIN y temperatura de U25/D34 a 9/24/32 V. & Jesús, piloto\\ +\rowcolor{HelgenMist} E-10 & \sevD & V5.7 & Toda la entrada de U25 cruza dos vías 0.8/0.3 en serie ((184.0, 121.8), (182.4, 68.1)). & A 24 V (0.7 A) nada. A 9 V cámara térmica. Rev. sig.: 2.\textsuperscript{a} vía. & Jesús $\cdot$ Rev. sig.\\ +E-11 & \sevD & V5.7 & D12 (LDO del MCU) + U12 cuelgan de una sola vía 0.6/0.3 en (146.37, 86.96), $\approx$ 0.3 A. & Eléctricamente sobra; punto único de falla. Rev. sig.: 2.\textsuperscript{a} vía. & Rev. sig.\\ +\rowcolor{HelgenMist} E-12 & \sevD & ambas & LSE FC-135 (CL 12.5 pF) con 12 pF: corre rápido unas decenas de ppm. & 0.7.0: LSEDRV alto, timeout 2 s, fallback a LSI. & 0.7.0\\ +E-13 & \sevC & ambas & Rdfu1 22 k (PA10) sostiene a medias el riel del módem apagado por K1 (NC) $\to$ DIN. & 0.7.0: pulso de MODEM\_RST tras cada MODEM\_EN (probado con SW4G1). Rev. sig.: revisar Rdfu1. & 0.7.0\\ +\rowcolor{HelgenMist} E-14 & \sevD & ambas & \net{NTC\_CELL} (PC5) solo vale con \net{VEH5V} presente (sesgo desde VIN). & Firmware reporta n/c en batería; U4 y U18 cubren la temperatura. & 0.7.0\\ +E-15 & \sevD & V5.7 & \net{/VIN\_FUSED} y \net{/SW\_PWRIN} fuera de la clase HV24 (0.2 mm en vez de 0.5). & Rev. sig.: agregarlas al patrón. Sin efecto en fábrica. & Rev. sig.\\ +\rowcolor{HelgenMist} E-16 & \sevD & ambas & Inrush de C3 220 $\mu$F + C40 al encender la etapa con Q1. & 0.7.0: módem después de la etapa; rampa de 20 ms (\texttt{STACK\_SOFTSTART\_MS}) en batería. & 0.7.0\\ +\multicolumn{6}{l}{\emph{Firmware}}\\ +F-1 & \sevA{} piloto & ambas & 0.6.3 no enciende el módem de V5.6/V5.7 (PC3) y lee mal NTC, flotación e ignición. & \texttt{board\_v56.h} (hecho) + 0.7.0-pre: 1 día. Sin esto el piloto no se prueba. & Leo + Claude\\ +\rowcolor{HelgenMist} F-2 & \sevB & ambas & Ciclo de 10 min no existe (el actual es espera activa a 96 MHz); umbrales Li-ion. & STOP + RTC, apagado ordenado, umbrales LFP (§\ref{sec:bateria}). 3--4 días. & Leo + Claude\\ +F-3 & \sevC & ambas & SC16IS752 sin driver: RS-485/RS-232 0 \%. & Driver + EFCR primero (1 día). & Leo + Claude\\ +\rowcolor{HelgenMist} F-4 & \sevC & ambas & Ethernet solo en build de banco con IP fija. & Modo de campo configurable (2 días). & Leo + Claude\\ +F-5 & \sevD & ambas & SC7A20 sin driver. & 0.5 día; despertar por movimiento. & Leo + Claude\\ +\rowcolor{HelgenMist} F-6 & \sevD & ambas & Vigilancia del módem indirecta (caída del riel). & LED (PC2) + RTCM (PC7); reset con límite. 0.5 día. & Leo + Claude\\ +F-7 & \sevD & ambas & Modo B supone módem siempre encendido. & No insertar hasta que viva; soltar K1 antes de apagarlo. & Leo + Claude\\ +\rowcolor{HelgenMist} F-8 & \sevC & ambas & Ciclo de recuperación sin orden entre módem y etapa. & Módem OFF $\to$ etapa OFF/ON $\to$ NMEA $\to$ módem ON. & Leo + Claude\\ +\bottomrule +\end{longtable}} + +\begin{helgennotice}[Los seis easy wins, en orden de valor] +1 $\cdot$ Pedir con vías tapadas y rayos X en U6 (P-2) — quita el defecto más visto en V5.5/V4. 2 $\cdot$ D10 $\to$ SMBJ33CA +(P-4) — una línea de BOM, cero cobre. 3 $\cdot$ Commit con el relleno fresco (P-1) — cinco minutos, evita un lote +con cortos. 4 $\cdot$ Unificar los 10 nF y corregir la etiqueta de C22 (P-6). 5 $\cdot$ THVD1410 / TRS3232E en la pre-orden +de las 108 / 322 (P-5). 6 $\cdot$ ENIG como acabado (QFN de 0.5 mm). +\end{helgennotice} diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/sec9-riesgos.tex b/03-Architecture-Hardware/Auditoria-Final-V56-V57/sec9-riesgos.tex new file mode 100644 index 0000000..80a547b --- /dev/null +++ b/03-Architecture-Hardware/Auditoria-Final-V56-V57/sec9-riesgos.tex @@ -0,0 +1,58 @@ +% ================================================================ RIESGOS +\section{Evaluación de riesgos y decisión}\label{sec:riesgos} + +\subsection{Registro de riesgos} + +Probabilidad (P) e impacto (I) de 1 a 5; puntaje = P × I. «Antes» es hoy, con los archivos tal como están; +«después» es con las mitigaciones del plan (condiciones del pedido, 0.7.0 y el banco del piloto). + +{\footnotesize +\begin{longtable}{@{}L{0.63cm}L{4.50cm}L{1.35cm}L{1.44cm}L{1.44cm}L{3.69cm}L{1.17cm}@{}} +\toprule +\cab{\cw{Id} & \cw{Riesgo} & \cw{Tarjeta} & \cw{Antes} & \cw{Después} & \cw{Mitigación} & \cw{Clase}}\\ +\midrule +\endfirsthead +\toprule +\cab{\cw{Id} & \cw{Riesgo} & \cw{Tarjeta} & \cw{Antes} & \cw{Después} & \cw{Mitigación} & \cw{Clase}}\\ +\midrule +\endhead +\input{tab-riesgos.tex} +\end{longtable}} + +\begin{figure}[H]\centering +\includegraphics[width=\linewidth]{fig/fig-matriz-riesgo.png} +\caption{Matriz de riesgo 5 × 5 antes y después de las mitigaciones. Antes, tres riesgos en rojo (R1 soldadura de +U6, R2 rotaciones, R9 firmware); después, solo R9 queda en naranja porque el firmware es trabajo por hacer, no +una propiedad de la tarjeta.}\label{fig:matriz} +\end{figure} + +\subsection{Criterio y decisión} + +\hwtab{\begin{tabular}{@{}L{3.18cm}L{5.96cm}L{6.76cm}@{}} +\toprule +\cab{\cw{Veredicto} & \cw{Condición} & \cw{¿Se cumple hoy?}}\\ +\midrule +GO & Ningún bloqueante; los altos tienen mitigación escrita y prueba en el piloto & Bloqueantes de cobre: ninguno. Altos: P-1, P-2, P-3, E-3, E-7, F-2, todos con mitigación y prueba.\\ +\rowcolor{HelgenMist} GO con cambios de paquete & Los bloqueantes están en BOM, CPL u opciones del pedido & P-2 y P-3 son opciones del pedido; P-4 es BOM. \textbf{Este es el caso.}\\ +NO-GO & Un bloqueante en cobre (corto, red abierta, fuera de capacidad, daño) & DRC 0 / sin conectar 0 / paridad OK / Gerber = cobre: no hay.\\ +\bottomrule +\end{tabular}} + +\begin{helgennotice}[Decisión que se propone a Leo] +\textbf{V5.6: GO} — 5 tarjetas hoy con las condiciones 1--3. \textbf{V5.7: GO} — 5 prototipos hoy con las mismas +condiciones; la fuente U25 se valida en banco (9 / 24 / 32 V, polaridad, térmico) antes de las 322. +\textbf{Las 108 V5.6 y las 322 V5.7: después del banco del piloto con 0.7.0} (criterios en §\ref{sec:plan}). La +alternativa —pedir las 430 hoy— ahorra dos semanas y arriesga 430 tarjetas a un defecto de soldadura, de rotación +o de firmware que el piloto detecta por el precio de 10. +\end{helgennotice} + +\subsection{Lo que esta auditoría no puede cerrar desde el escritorio} + +\begin{itemize} +\item La \textbf{soldadura real} de U6 (QFN 0.5 mm): por eso rayos X y lupa. +\item La \textbf{rotación real} en JLC de las huellas easyeda2kicad: por eso el visor. +\item El \textbf{piso dormido real} (el W5500 en reset no tiene cifra en la hoja de datos; el MCU en STOP a 45 °C): por eso el PPK2. +\item El \textbf{módem «encendido pero muerto»} tras dormir: si el pulso de reset lo revive en ese estado se prueba en banco, no en papel. +\item El \textbf{timbre de U25} con el lazo de 56 mm$^2$: osciloscopio con punta de tierra corta. +\item Los \textbf{arneses y la tapa}: con la primera tarjeta en la mano. +\end{itemize} diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/tab-pinmap.tex b/03-Architecture-Hardware/Auditoria-Final-V56-V57/tab-pinmap.tex new file mode 100644 index 0000000..eca0a6e --- /dev/null +++ b/03-Architecture-Hardware/Auditoria-Final-V56-V57/tab-pinmap.tex @@ -0,0 +1,65 @@ +1 & \texttt{VBAT} & \texttt{/3V3} & alimentación\\ +2 & \texttt{PC13} & \texttt{/LED\_C13} & LED azul D17 (activo bajo)\\ +3 & \texttt{PC14} & \texttt{/LSE\_IN} & Y4 32.768 kHz\\ +4 & \texttt{PC15} & \texttt{/LSE\_OUT} & Y4\\ +5 & \texttt{PH0} & \texttt{/HSE\_IN} & Y3 25 MHz\\ +6 & \texttt{PH1} & \texttt{/HSE\_OUT} & Y3\\ +7 & \texttt{NRST} & \texttt{/NRST} & SW1 $\cdot$ P10 $\cdot$ TP5\\ +8 & \texttt{PC0} & \texttt{/ETH\_INT} & W5500 INT\\ +9 & \texttt{PC1} & \texttt{/MODEM\_RST\_MCU} & NUEVO $\cdot$ R107 $\to$ J7.5 (colector abierto)\\ +10 & \texttt{PC2} & \texttt{/MODEM\_LED\_MCU} & NUEVO $\cdot$ R108 $\leftarrow$ J8.8\\ +11 & \texttt{PC3} & \texttt{/MODEM\_EN} & NUEVO $\cdot$ R105 $\to$ EN AP64350 (R106 pull-down)\\ +12 & \texttt{VSSA} & \texttt{GND} & \\ +13 & \texttt{VDDA} & \texttt{/VDDA} & R104 + C109/C112\\ +14 & \texttt{PA0} & \texttt{/BAT\_SENSE} & ADC $\cdot$ paquete ÷2\\ +15 & \texttt{PA1} & \texttt{/PWR\_CTRL} & etapa RTK (Q5$\to$Q1), HIGH = ON\\ +16 & \texttt{PA2} & \texttt{/GNSS\_TX} & USART2 $\to$ F9P UART1\\ +17 & \texttt{PA3} & \texttt{/GNSS\_RX} & USART2 $\leftarrow$ F9P UART1\\ +18 & \texttt{VSS} & \texttt{GND} & \\ +19 & \texttt{VDD} & \texttt{/3V3} & alimentación\\ +20 & \texttt{PA4} & \texttt{/5V\_SENSE} & ADC $\cdot$ VEH5V ÷2\\ +21 & \texttt{PA5} & \texttt{/IGN\_SENSE} & ADC $\cdot$ ×0.1154 (12 V = 1.38 V)\\ +22 & \texttt{PA6} & \texttt{/FAN\_PWM} & Q2 ventilador, HIGH = ON\\ +23 & \texttt{PA7} & \texttt{— (al aire)} & poner en pull-down\\ +24 & \texttt{PC4} & \texttt{/MODEM\_ON\_SLEEP} & R109 DNP: al aire (pull-down)\\ +25 & \texttt{PC5} & \texttt{/NTC\_CELL} & NUEVO $\cdot$ ADC $\cdot$ nodo NTC ×0.5455 (solo con VEH5V)\\ +26 & \texttt{PB0} & \texttt{/EXT\_LED} & Q4 $\to$ LED del panel P8\\ +27 & \texttt{PB1} & \texttt{— (al aire)} & poner en pull-down\\ +28 & \texttt{PB2} & \texttt{/BOOT1\_STRAP} & R99 pull-down — no usar\\ +29 & \texttt{PB10} & \texttt{— (al aire)} & poner en pull-down\\ +30 & \texttt{VCAP1} & \texttt{/VCAP1} & C111 4.7 $\mu$F\\ +31 & \texttt{VSS} & \texttt{GND} & \\ +32 & \texttt{VDD} & \texttt{/3V3} & alimentación\\ +33 & \texttt{PB12} & \texttt{/ETH\_CS} & SPI2 W5500\\ +34 & \texttt{PB13} & \texttt{/ETH\_SCK} & SPI2\\ +35 & \texttt{PB14} & \texttt{/ETH\_MISO} & SPI2 (salida del W5500)\\ +36 & \texttt{PB15} & \texttt{/ETH\_MOSI} & SPI2\\ +37 & \texttt{PC6} & \texttt{— (al aire)} & poner en pull-down\\ +38 & \texttt{PC7} & \texttt{/RTCM\_TAP} & NUEVO $\cdot$ USART6 RX $\leftarrow$ R111 $\leftarrow$ DOUT\_4G\\ +39 & \texttt{PC8} & \texttt{— (al aire)} & poner en pull-down\\ +40 & \texttt{PC9} & \texttt{— (al aire)} & poner en pull-down\\ +41 & \texttt{PA8} & \texttt{/CHRG\_EN} & LTC4040 CHGOFF (R56 pull-down: carga ON por defecto)\\ +42 & \texttt{PA9} & \texttt{/USART1\_TX} & $\to$ K1 NO $\to$ DIN\_4G (Modo B)\\ +43 & \texttt{PA10} & \texttt{/USART1\_RX} & $\leftarrow$ TX2 del F9P (Rdfu1 22 k)\\ +44 & \texttt{PA11} & \texttt{/DFU\_DM} & USB J11\\ +45 & \texttt{PA12} & \texttt{/DFU\_DP} & USB J11\\ +46 & \texttt{PA13} & \texttt{/SWDIO} & TP3\\ +47 & \texttt{VSS} & \texttt{GND} & \\ +48 & \texttt{VDD} & \texttt{/3V3} & alimentación\\ +49 & \texttt{PA14} & \texttt{/SWCLK} & TP4\\ +50 & \texttt{PA15} & \texttt{/ETH\_RST} & R112 4.7 k pull-down: W5500 en reset por defecto\\ +51 & \texttt{PC10} & \texttt{— (al aire)} & poner en pull-down\\ +52 & \texttt{PC11} & \texttt{— (al aire)} & poner en pull-down\\ +53 & \texttt{PC12} & \texttt{— (al aire)} & poner en pull-down\\ +54 & \texttt{PD2} & \texttt{— (al aire)} & poner en pull-down\\ +55 & \texttt{PB3} & \texttt{/CHRG\_STAT} & LTC4040 CHRG (R57 pull-up)\\ +56 & \texttt{PB4} & \texttt{/CHRG\_FAULT} & LTC4040 FAULT (R58 pull-up)\\ +57 & \texttt{PB5} & \texttt{/BYP\_CTRL} & K1 por Q6 (R41 pull-down)\\ +58 & \texttt{PB6} & \texttt{/I2C\_SCL} & I2C1 4.7 k\\ +59 & \texttt{PB7} & \texttt{/I2C\_SDA} & I2C1 4.7 k\\ +60 & \texttt{BOOT0} & \texttt{/BOOT0} & R98 pull-down $\cdot$ SW2\\ +61 & \texttt{PB8} & \texttt{/SER\_IRQ} & SC16IS752 IRQ (R81)\\ +62 & \texttt{PB9} & \texttt{/ACC\_INT1} & NUEVO $\cdot$ SC7A20 INT1 (EXTI9)\\ +63 & \texttt{VSS} & \texttt{GND} & \\ +64 & \texttt{VDD} & \texttt{/3V3} & alimentación\\ +\bottomrule diff --git a/03-Architecture-Hardware/Auditoria-Final-V56-V57/tab-riesgos.tex b/03-Architecture-Hardware/Auditoria-Final-V56-V57/tab-riesgos.tex new file mode 100644 index 0000000..159bf4e --- /dev/null +++ b/03-Architecture-Hardware/Auditoria-Final-V56-V57/tab-riesgos.tex @@ -0,0 +1,17 @@ +R1 & Soldadura de U6 (QFN 0.5 mm, 3 vías en la pasta): puentes y bolas como en V5.5/V4 & V5.6 $\cdot$ V5.7 & 4$\cdot$4 = \textcolor{red!75!black}{$\blacksquare$}\,16 & 2$\cdot$3 = \textcolor{yellow!65!orange}{$\blacksquare$}\,6 & Pedir con «Epoxy Filled \& Capped» + rayos X en U6; lupa en cada tarjeta antes de energizar & Pedido\\ +R2 & Rotación de huellas easyeda2kicad (U7, U25, U26, L22) y polaridad de D34 en JLC & V5.6 $\cdot$ V5.7 & 2$\cdot$5 = \textcolor{orange!90!black}{$\blacksquare$}\,10 & 1$\cdot$5 = \textcolor{yellow!65!orange}{$\blacksquare$}\,5 & Confirmar pin 1 y polaridad en el visor de JLC antes de pagar & Pedido\\ +R3 & Apagón (brownout) del módem en batería al arrancar o en ráfaga LTE & V5.6 $\cdot$ V5.7 & 1$\cdot$4 = \textcolor{yellow!65!orange}{$\blacksquare$}\,4 & 1$\cdot$3 = \textcolor{green!60!black}{$\blacksquare$}\,3 & Hardware ya resuelto (AP64350 desde 3.8 V, 2.5 A de boost, C43 220 $\mu$F); 0.7.0 secuencia etapa $\to$ NMEA $\to$ MODEM\_EN & Diseño\\ +R4 & Piso de consumo dormido demasiado alto (W5500 65–132 mA sin enable) & V5.6 $\cdot$ V5.7 & 4$\cdot$3 = \textcolor{orange!90!black}{$\blacksquare$}\,12 & 2$\cdot$3 = \textcolor{yellow!65!orange}{$\blacksquare$}\,6 & 0.7.0: W5500 en power-down (13 mA) antes de dormir; medir el piso en el piloto (PPK2) & Firmware\\ +R5 & RS-485 toma el bus desde el encendido hasta que el firmware configura U10 & V5.6 $\cdot$ V5.7 & 3$\cdot$2 = \textcolor{yellow!65!orange}{$\blacksquare$}\,6 & 2$\cdot$2 = \textcolor{yellow!65!orange}{$\blacksquare$}\,4 & EFCR/MCR como primer paso del arranque; uso punto a punto; THVD1410 en BOM para 108/322 & Firmware\\ +R6 & Ignición mal leída en máquinas de 12 V (1.38 V en PA5, zona indefinida) & V5.7 & 4$\cdot$3 = \textcolor{orange!90!black}{$\blacksquare$}\,12 & 1$\cdot$3 = \textcolor{green!60!black}{$\blacksquare$}\,3 & 0.7.0: PA5 por ADC con histéresis 0.80/0.55 V & Firmware\\ +R7 & Arnés al revés: D10 SMBJ33A conduce y abre F2 (SMD) / quema D10 & V5.7 (V5.6) & 2$\cdot$3 = \textcolor{yellow!65!orange}{$\blacksquare$}\,6 & 2$\cdot$1 = \textcolor{green!60!black}{$\blacksquare$}\,2 & D10 $\to$ SMBJ33CA (misma huella); V5.6 sin fusible: el breaker del gabinete & BOM\\ +R8 & U25: timbre en SW/VIN (lazo 56 mm$^2$) o calor de U25/D34 a 32 V y 2.8 A & V5.7 & 2$\cdot$3 = \textcolor{yellow!65!orange}{$\blacksquare$}\,6 & 2$\cdot$2 = \textcolor{yellow!65!orange}{$\blacksquare$}\,4 & Banco: 9/24/32 V con 2.5 A, osciloscopio y cámara térmica; D-21-2 & Banco\\ +R9 & Firmware 0.7.0 no existe: el piloto no se puede probar (ni el módem enciende) & V5.6 $\cdot$ V5.7 & 5$\cdot$4 = \textcolor{red!75!black}{$\blacksquare$}\,20 & 3$\cdot$4 = \textcolor{orange!90!black}{$\blacksquare$}\,12 & board\_v56.h hoy; 0.7.0-pre (módem + ADC) antes de que lleguen las tarjetas & Firmware\\ +R10 & Arneses cortos / tapa: conectores JST movidos 12–68 mm; LEDs del gauge en otro borde (V5.7) & V5.7 (V5.6) & 3$\cdot$2 = \textcolor{yellow!65!orange}{$\blacksquare$}\,6 & 3$\cdot$1 = \textcolor{green!60!black}{$\blacksquare$}\,3 & Medir con la primera tarjeta; tapa V5.7 si el gauge se ve por la tapa & Mecánica\\ +R11 & Relleno de zonas viejo en los .kicad\_pcb del repo: una exportación sin rellenar manda cortos & V5.6 $\cdot$ V5.7 & 2$\cdot$4 = \textcolor{orange!90!black}{$\blacksquare$}\,8 & 1$\cdot$4 = \textcolor{yellow!65!orange}{$\blacksquare$}\,4 & Hoy: Gerber verificado = relleno fresco. Leo: abrir, B, guardar y commit & Proceso\\ +R12 & Umbrales de batería pensados para Li-ion (3.40/3.70 V) con paquete LFP (meseta 3.2–3.3 V) & V5.6 $\cdot$ V5.7 & 4$\cdot$3 = \textcolor{orange!90!black}{$\blacksquare$}\,12 & 1$\cdot$3 = \textcolor{green!60!black}{$\blacksquare$}\,3 & 0.7.0: corte 2.95 V / rearme 3.20 V con media de 200 ms; SoC por culombios & Firmware\\ +R13 & Lazos de convertidores heredados de V5.5 (U12/L8 35 mm, U2/Dbk1 18 mm): EMC / ruido & V5.6 $\cdot$ V5.7 & 2$\cdot$2 = \textcolor{yellow!65!orange}{$\blacksquare$}\,4 & 2$\cdot$2 = \textcolor{yellow!65!orange}{$\blacksquare$}\,4 & Se mide en el piloto; corregir en v6 & Diseño\\ +R14 & Vías únicas en el camino de 24 V (V5.7) a 9 V y 1.9 A: calentamiento & V5.7 & 1$\cdot$2 = \textcolor{green!60!black}{$\blacksquare$}\,2 & 1$\cdot$2 = \textcolor{green!60!black}{$\blacksquare$}\,2 & Instalaciones a 24 V (0.7 A); cámara térmica a 9 V; 2.\textsuperscript{a} vía en la siguiente revisión & Diseño\\ +R15 & Módem «encendido pero muerto» tras dormir (riel sostenido por Rdfu1 22k vía K1/DIN) & V5.6 $\cdot$ V5.7 & 2$\cdot$3 = \textcolor{yellow!65!orange}{$\blacksquare$}\,6 & 1$\cdot$3 = \textcolor{green!60!black}{$\blacksquare$}\,3 & Pulso de MODEM\_RST (PC1) tras cada MODEM\_EN (SW4G1 probado); revisar Rdfu1 en v6 & Firmware\\ +R16 & LSE no arranca (FC-135 CL 12.5 pF con 12 pF) y el ciclo de 10 min se queda sin reloj & V5.6 $\cdot$ V5.7 & 1$\cdot$3 = \textcolor{green!60!black}{$\blacksquare$}\,3 & 1$\cdot$1 = \textcolor{green!60!black}{$\blacksquare$}\,1 & LSEDRV alto + timeout $\to$ RTC con LSI (±5 \%) y evento; IWDG independiente & Firmware\\ +\bottomrule diff --git a/03-Architecture-Hardware/img/2026-10-22_Drogheda_Autonomia-Ciclo_v1.0.png b/03-Architecture-Hardware/img/2026-10-22_Drogheda_Autonomia-Ciclo_v1.0.png new file mode 100644 index 0000000..d5a01c4 Binary files /dev/null and b/03-Architecture-Hardware/img/2026-10-22_Drogheda_Autonomia-Ciclo_v1.0.png differ diff --git a/03-Architecture-Hardware/img/2026-10-22_Drogheda_Matriz-Riesgo_v1.0.png b/03-Architecture-Hardware/img/2026-10-22_Drogheda_Matriz-Riesgo_v1.0.png new file mode 100644 index 0000000..85382e5 Binary files /dev/null and b/03-Architecture-Hardware/img/2026-10-22_Drogheda_Matriz-Riesgo_v1.0.png differ diff --git a/03-Architecture-Hardware/img/2026-10-22_Drogheda_RS1-Kelvin-Final_v1.0.png b/03-Architecture-Hardware/img/2026-10-22_Drogheda_RS1-Kelvin-Final_v1.0.png new file mode 100644 index 0000000..866230a Binary files /dev/null and b/03-Architecture-Hardware/img/2026-10-22_Drogheda_RS1-Kelvin-Final_v1.0.png differ diff --git a/03-Architecture-Hardware/img/2026-10-22_Drogheda_Relleno-Viejo-vs-Gerber_v1.0.png b/03-Architecture-Hardware/img/2026-10-22_Drogheda_Relleno-Viejo-vs-Gerber_v1.0.png new file mode 100644 index 0000000..cdc3d28 Binary files /dev/null and b/03-Architecture-Hardware/img/2026-10-22_Drogheda_Relleno-Viejo-vs-Gerber_v1.0.png differ diff --git a/03-Architecture-Hardware/img/2026-10-22_Drogheda_U6-Pasta-Vias_v1.0.png b/03-Architecture-Hardware/img/2026-10-22_Drogheda_U6-Pasta-Vias_v1.0.png new file mode 100644 index 0000000..45b0320 Binary files /dev/null and b/03-Architecture-Hardware/img/2026-10-22_Drogheda_U6-Pasta-Vias_v1.0.png differ diff --git a/03-Architecture-Hardware/img/2026-10-22_Drogheda_V5.6-Cara-Superior_v1.0.png b/03-Architecture-Hardware/img/2026-10-22_Drogheda_V5.6-Cara-Superior_v1.0.png new file mode 100644 index 0000000..435a41f Binary files /dev/null and b/03-Architecture-Hardware/img/2026-10-22_Drogheda_V5.6-Cara-Superior_v1.0.png differ diff --git a/03-Architecture-Hardware/img/2026-10-22_Drogheda_V5.7-Cara-Superior_v1.0.png b/03-Architecture-Hardware/img/2026-10-22_Drogheda_V5.7-Cara-Superior_v1.0.png new file mode 100644 index 0000000..a798bd8 Binary files /dev/null and b/03-Architecture-Hardware/img/2026-10-22_Drogheda_V5.7-Cara-Superior_v1.0.png differ diff --git a/03-Architecture-Hardware/img/2026-10-22_Drogheda_V5.7-Fuente-U25_v1.0.png b/03-Architecture-Hardware/img/2026-10-22_Drogheda_V5.7-Fuente-U25_v1.0.png new file mode 100644 index 0000000..1762483 Binary files /dev/null and b/03-Architecture-Hardware/img/2026-10-22_Drogheda_V5.7-Fuente-U25_v1.0.png differ diff --git a/03-Architecture-Hardware/kicad b/03-Architecture-Hardware/kicad index 7883799..e13d074 160000 --- a/03-Architecture-Hardware/kicad +++ b/03-Architecture-Hardware/kicad @@ -1 +1 @@ -Subproject commit 7883799e36d67e5bfa0cdb1f370dfad0c120aa14 +Subproject commit e13d074571f11083d64e93f42f3a3e5182fc726b diff --git a/04-Source-Code/firmware b/04-Source-Code/firmware index 051a587..5619bbe 160000 --- a/04-Source-Code/firmware +++ b/04-Source-Code/firmware @@ -1 +1 @@ -Subproject commit 051a58752c5f194f4b2dac9f2c510cf78d12a105 +Subproject commit 5619bbe5ab77d0c31b4b2a9df1c21984958b7edf