Drogheda/03-Architecture-Hardware/watchdog-pcb-v3-design.md
Leopoldo Rodríguez 2c3dffa232 2026-07-02: PROD schematic complete (ERC 0) + carrier-board PCB + doc sweep to the Jul-2 ledger
Electrical/PCB:
- LTC4040 Block B sized to the 12 Ah 1S4P pack (RPROG 825R -> 2.42 A ~ C/5,
  RS 8 mR -> 3.1 A input limit, PFI 4.60 V, backup 4.79 V, charge 4.00 V Li-ion
  via VSYS-referenced straps) + Block E cutoff (P11) + Block F PA4->VEH5V re-tap
  + Block H fail-safe Modo-B bypass (K1 normally-closed relay) + Block I NTC->PB1.
- CARRIER-BOARD conversion: simpleRTK2B Pro on UNO-pattern female headers (MOD1;
  D0/D1=UART1, D2=RX2, D8=TX2, IOREF=3V3, 5V=SW_5V) + 4G NTRIP Master on on-board
  XBee socket (J7/J8; VCC=3V3_MODEM via new Block K MP1584 buck off SW_5V - the
  HP XBee socket is 3.3 V not 5 V). Board 120x100, placement + GND pour + DRC
  baselines. Custom symbols: LTC4040EUFD, AO4406A, SimpleRTK2B_Pro_Socket.
- Fixed duplicated U2, stale no-connects, A4->A3 sheet; ERC 0 errors.

Docs:
- Canonical electrical-design-state + production delta (Block B values table,
  5b/5c/5d/5e) + design/rationale/connections/BOM swept to the Jul-2 assumptions
  ledger (Conexiones-por-Bloque xlsx).
- Guia de Conexion Protoboard: LaTeX source now maintained in-repo -> v2.1 PDF.
- CircuiTikZ sheet + wiring Beamer: block 11 (NTC->PB1) + guinda ignition legend.
- Client decks: Avance v1.1 (overclaims fixed) + RCA v1.1 (2-jul addendum).

Repo hygiene:
- .gitignore: live rtk-config (SIM/APN/NTRIP creds) now ignored and REMOVED from
  tracking (NOTE: rotate those credentials - they exist in prior commits);
  KiCad .bak/snapshots/.history, LaTeX intermediates, Office locks ignored+purged.
- Removed rogue .history gitlinks that broke git status.
2026-07-02 22:18:56 -06:00

32 KiB
Raw Permalink Blame History

tags project author date status supersedes_section
project-drogheda
hardware
watchdog
pcb
thermal
fans
schematic
v3
Project Drogheda Helgen CTO 2026-06-21 Active — design for review; bench-validate before fab hardware-respec-and-pcb-brief.md §4 (watchdog carrier detail)

HBOX Watchdog Carrier PCB — v3.0 Design (Watchdog + Smart-Fan Thermal)

⚠️ Current electrical state (2026-06-24): see 03-Architecture-Hardware/watchdog-electrical-design-state (CANONICAL). Since this doc, the DFR1015 folded on-board (GX16 pin 3 = raw ignition), the battery was re-added (LTC4040 + NTC temp-qualified charging on the 1S4P pack), and reset + 4-LED gauge + power-cutoff were added. Where this doc disagrees with the canonical state, the canonical state wins. (Also: 1 fan, not "two" — see the 1-fan update.)

2026-07-02: LTC4040 sized to the 12 Ah pack — values in 03-Architecture-Hardware/watchdog-production-schematic-delta §4; capture + layout kickoff in progress.

The production PCB for the STM32F411 watchdog, expanded to drive two extraction fans and monitor internal temperature/humidity. This is the schematic-capture spec: every sub-circuit, every value, every part, the pin map, the firmware deltas, and the layout/fab path. Pairs with: 03-Architecture-Hardware/watchdog-pcb-v3-bom · 03-Architecture-Hardware/watchdog-pcb-v3-kicad-guide · 04-Source-Code/firmware/blackpillrtkcode_v2/blackpillrtkcode_v2 · 03-Architecture-Hardware/watchdog-schematic.

Decisions driving this revision (2026-06-21, Leo):

# Decision Consequence
1 Scope = watchdog + thermal carrier Blackpill plugs on via 2×20 headers (reuse v2.1 firmware, no MCU bring-up). Mean Well SD-15B-05 and the battery stay external modules. Lowest-risk first board.
2 5 V fan ×1 One extraction fan, low-side (MOSFET PWM) + tach. ⚠ Loads the same 5 V the modem bursts on — mitigated with a dedicated fan rail (§0a). Needs a passive filtered inlet to pull air through, and has no redundancy — a fan failure falls back to conduction + thermal derate (tach-fault flags it).
3 I²C temp + humidity SHT40 (board ambient + RH) + TMP102 probe (battery/modem hot spot) on one I²C bus.
4 JLCPCB with assembly Parts chosen from JLC/LCSC stock; we output Gerbers + BOM + CPL. Footprints biased to JLC-placeable + hand-reworkable.
5 Live telemetry ($PHLG): bench-test first, NOT built into v3 (2026-06-22) The 4G modem keeps its proven home on the F9P XBee socket = UART2; there is no spare UART to tap (see §2a). v3 ships health on the USB STREAM log (already works). PA9/PA10 header is reserved/DNP only. The forwarding question is settled by an isolated bench experiment (§7a), not by a board change.

0. Read this first — two engineering caveats

0a. 5 V fans must NOT share the RTK stack rail

The Mean Well SD-15B-05 gives 5 V @ 3 A. The RTK+4G stack already peaks ~2–2.5 A on LTE-TX bursts — the brownout the whole redesign is fixing. One 5 V fan adds ~0.15–0.25 A plus inrush. Coincident worst case ≈ 2.7 A still nears the supply limit, and fan inrush + a modem burst at the same instant is exactly the sag that drops the link. So the board gives the fan its own 5 V from a small 24→5 V buck tapped off the cabinet 24 V (which is already inside the HBOX). A 0 Ω jumper (JP1) lets you instead bridge the fan to the main 5 V — with a single ~0.2 A fan that's more defensible than with two, but the dedicated rail stays the safe default. Do not power the fan from the switched (load-switch) stack 5 V — it must run when hot even while the stack is power-cycling.

0b. Fans + IP67 is a real tradeoff — own it

Moving air in/out of the box breaks the IP67 seal. A fan only helps if it exchanges HBOX/cabinet air with outside air; that path is an opening. The honest position for the v3 mechanical:

  • Ventilation drops the rating from IP67 → ~IP54/IP55 at best, with filtered, hooded, downward-facing louvers. In a salty, humid, dusty port that is a maintenance item (filters clog/corrode).
  • Keep every electronic mitigation we already have: conformal-coat the PCB (acrylic/urethane), keep a Gore pressure-vent for condensation, and treat the fans as assist, not the whole thermal solution. Conduction to the metal plate (hardware brief §2b) still does the heavy lifting; fans buy the last few °C.
  • The firmware runs the fans only when temperature demands it (closed loop, §7), minimising the hours the vents are actively pulling dirty air.

If ICAVE can accept IP54 with filter maintenance, fans are fine. If they require IP67, the answer is conduction + sunshade, not fans. This board supports both — populate or depopulate the fan section. Confirm the rating target with ICAVE.


1. What the close look at the watchdog found

The as-built watchdog (watchdog-schematic.md) + v2.1 firmware is sound logic on fragile hardware. Keep the brains, fix the body.

Keep (proven):

  • The high-side power gate concept (PA1 → stack 5 V), fail-safe OFF at boot via the gate pull-up. This is the heart of 4G/NTRIP recovery — don't change its behaviour, only its build quality.
  • Three sense dividers (battery PA0, 5 V PA4, ignition PA5) and the v2.1 recovery state machine (backoff + LIMP + NMEA-silence + IWDG + MCU-thermal).
  • USART2 (PA2/PA3) to the F9P UART1 for NMEA read + UBX rate.

Fix (the liabilities):

Liability Root issue v3 board fix
2N3904 + IRF9540N + pull-up, hand-wired vibration intermittents; IRF9540N is not logic-level (marginal gate drive from a 5 V swing) SMD discrete high-side switch (AO3401A logic-level P-FET + MMBT3904) + PPTC overcurrent; optional eFuse upgrade
LED + dividers on Dupont mechanical all on-board, 0603, conformal-coatable
1.5 kΩ "????" mystery R undocumented resolved on this schematic (it was the LED series R; dividers are 10k/10k — see §6)
MCU temp only heat casualties are the 18650/modem, not the die external I²C sensors at the hot spot (§5)
No thermal actuation firmware can derate but can't cool 1 fan driver + closed-loop control (§4, §7)
No SWD/header bring-out can't debug a sealed unit USB + reserve-USART1 headers (§6). H1 SWD DROPPED 2026-06-25 (flash/log via USB-C; optional DNP 4-pad)

2. Expanded STM32F411 pin map (v2.1 pins kept; 6 added)

                       STM32F411 "Blackpill" (mounted on 2×20 headers)
  ── existing (firmware v2.1, unchanged) ───────────────────────────────────
  PA0  BAT_SENSE     ADC1_IN0   18650 ÷2 divider
  PA1  PWR_CTRL      GPIO out   → RTK-stack load switch enable (HIGH = ON)
  PA2  GNSS_TX       USART2_TX  → simpleRTK2B UART1 RX (UBX rate cmds)
  PA3  GNSS_RX       USART2_RX  ← simpleRTK2B UART1 TX (NMEA read)
  PA4  5V_SENSE      ADC1_IN4   stack 5 V ÷2 divider (vehicle-power present)
  PA5  IGN_SENSE     GPIO in    ignition via DFR1015 (INPUT_PULLDOWN)
  PB0  EXT_LED       GPIO out   external status LED (low-side MOSFET)
  PC13 LED           GPIO out   onboard LED (active-LOW)
  ── NEW for v3 (fan + temperature) ────────────────────────────────────────
  PA6  FAN_PWM       TIM3_CH1   25 kHz PWM → fan low-side gate
  PB10 FAN_TACH      EXTI       fan tach (open-collector, 10k pull-up to 3V3)
  PA7  (spare)       TIM3_CH2   reserved — 2nd fan PWM if ever needed
  PB12 (spare)       EXTI       reserved — 2nd fan tach if ever needed
  PB6  I2C1_SCL      I2C1       SHT40 + TMP102 (4.7k pull-ups to 3V3)
  PB7  I2C1_SDA      I2C1       SHT40 + TMP102
  ── NEW [2026-07-02] (PROD: battery backup + Modo-B bypass + hot-spot NTC) ──
  PB1  NTC_TEMP      ADC1_IN9   hot-spot NTC divider (3V3–10k 1%–NTC 10k–GND + 100 nF) — block 11
  PB3  CHRG_STAT     GPIO in    LTC4040 CHRG open-drain, 100k↑3V3 (LOW = charging)
  PB4  CHRG_FAULT    GPIO in    LTC4040 FAULT open-drain, 100k↑3V3 (LOW = NTC/bad-battery fault)
  PB5  BYP_CTRL      GPIO out   K1 bypass-relay driver via Q6 (HIGH = MCU in-line, §2c)
  ── reserved (do not populate now; future in-band $PHLG telemetry relay) ───
  PA9  USART1_TX     header     → future: inject $PHLG into modem uplink
  PA10 USART1_RX     header     ← future: F9P UART2 NMEA tap
  PA13 SWDIO / PA14 SWCLK       SWD debug header — H1 DROPPED 2026-06-25 (USB-C; opt. DNP 4-pad)
  PA11 USB_DM / PA12 USB_DP     Blackpill micro-USB = STREAM log capture

No conflicts: TIM3_CH1 (PA6) does fan PWM; PB0 (TIM3_CH3) stays plain-GPIO LED. The reserved USART1 pair (H3) future-proofs the board for the [[03-Architecture-Hardware/watchdog-health-telemetry|$PHLG health-in-server]] upgrade without a respin — but in v3 it is left unpopulated; no relay is wired (see §2a + the decision row above). PA10 caveat: PA10 is USART1-RX and a known Blackpill DFU-entry pin — a load/float here can block flash mode. Keep H3 unpopulated, or fit a ~22 kΩ pull-up on PA10 to 3V3, so this board never inherits the flaky-flashing gremlin.

2a. WeAct Black Pill header pinout — what lands on J1/J2

The module mounts on two 1×20 headers. From the WeAct MiniF4x1Cx V3.0 schematic (MiniF4x1Cx_V30 SchDoc.pdf, headers P1/P2), the physical pin order is (pin 1 = VBAT end):

Pin J1 = WeAct P1 carrier net J2 = WeAct P2 carrier net
1 VBAT — PB12 — (spare)
2 PC13 — (onboard LED) PB13 —
3 PC14 — PB14 —
4 PC15 — PB15 —
5 NRST — PA8 —
6 PA0 BAT_SENSE PA9 USART1_TX (reserve)
7 PA1 PWR_CTRL PA10 USART1_RX (reserve, +Rdfu 22k)
8 PA2 GNSS_TX PA11 — (USB)
9 PA3 GNSS_RX PA12 — (USB)
10 PA4 5V_SENSE PA15 —
11 PA5 IGN_SENSE PB3 CHRG_STAT [2026-07-02]
12 PA6 FAN_PWM PB4 CHRG_FAULT [2026-07-02]
13 PA7 — (spare) PB5 BYP_CTRL [2026-07-02]
14 PB0 EXT_LED PB6 I2C_SCL
15 PB1 NTC_TEMP [2026-07-02] PB7 I2C_SDA
16 PB2 — (BOOT1, pulled low on-module) PB8 —
17 PB10 FAN_TACH PB9 —
18 3V3 3V3 (LDO out) 5V MAIN5V (in)
19 GND GND GND GND
20 5V MAIN5V (in) 3V3 3V3 (LDO out)

Consequences (caught from the real pinout):

  • SWD (PA13/PA14) is NOT on the 2×20 — it's the module's separate 4-pin SWD header. → H1 dropped; flash/debug via the Blackpill USB-C.
  • 5V pin = power IN, 3V3 pin = LDO OUT. MAIN5V feeds the 5V pin; the module's 3V3 LDO output is the carrier 3V3 rail (sensors + I²C/tach pull-ups).
  • BOOT1 (PB2) is pulled low on the module — no carrier action needed.
  • USB (PA11/PA12) is on the header but unused (we flash via the USB-C connector).

2b. Why there is no spare UART (the telemetry reality)

The simpleRTK2B Pro breaks out both F9P UARTs, but only one is free:

F9P port Header pins Used by Free?
UART1 TX1 / RX1 watchdog (NMEA read + UBX rate) — PA2/PA3 taken
UART2 TX2 / RX2 and the XBee socket 4G NTRIP Master (server uplink) no — shared bus

TX2 = F9P-UART2-TX = the modem's DIN (the wire the modem reads and forwards to the server). The F9P already drives it, so the watchdog can't simply "connect a second wire" to send $PHLG — that's two transmitters on one line. Getting health to the server therefore needs a relay (interpose the MCU between F9P-UART2 and the modem), which is a deliberate architecture change deferred out of v3. To learn whether it's even possible, run the isolated bench experiment in §7a — it touches no PCB.

Two sub-circuits added on kicad/hbox-watchdog-v3-PROD.kicad_sch; full specs in 03-Architecture-Hardware/watchdog-production-schematic-delta §5b / §5c:

  • Block H — K1 normally-closed SPDT signal-relay bypass on the Modo-B uplink. The §2b relay is now real in Modo B: the watchdog sits in-line on the uplink (F9P TX2 → 4G DIN) to inject $PHLG; the RTCM3 downlink stays direct. K1's NC contacts route F9P TX2 → 4G DIN with the coil de-energized — the MCU must actively energize (PB5 BYP_CTRL → Q6) to insert itself. Chosen over an analog mux because a mux dies with the 3V3 rail; relay contacts keep F9P TX2 → 4G DIN even with the Blackpill physically absent (extends invariants #2/#3 to the diagnostic path).
  • Block I — NTC→PB1 hot-spot temperature divider (block 11). 3V3 – 10 k 1 % – NTC 10 k – GND into PB1 (ADC1_IN9) + 100 nF; NTC placed at the battery/modem hot spot. The proto's temperature path (no SHT40 in hand); the PCB keeps U3/U4 (I²C) and this channel.

3. Block diagram

 Cabinet 24 V  ──GX16-5(pin1/2)──►  P1 [24V_IN]
   │                                  ├─► reverse-pol P-FET (Q10) + TVS (D10, SMBJ33A) ─► 24V rail
   │                                  │        ├──────────────────────────────► FAN buck in
   │   (ignition 24V ─GX16 pin3─► DFR1015 ext module ─► P1[IGN] ─► PA5 divider)
   │
 Mean Well SD-15B-05  (EXTERNAL, 24→5 V 3 A)  ──►  P2 [5V_IN]  ─► MAIN 5V rail
      MAIN 5V ─► Blackpill 5V pin (onboard LDO → 3V3)
      MAIN 5V ─► high-side load switch (Q1 AO3401A / U1 eFuse opt) ─EN◄PA1─► SW_5V ─► P3 simpleRTK2B + 4G
      MAIN 5V ─► PA4 sense divider
 18650 / PowerBoost (EXTERNAL) ──► P4 [BAT+ , BAT_SENSE] ─► PA0 divider

 FAN rail:  24V ─► U2 buck (MP1584EN) ─► 5V_FAN (JP1: alt-bridge to MAIN 5V)
      5V_FAN ───► Fan (+)                          ┌─── Fan tach ─10k─► PB10
                  Fan (−) ─ Q2 (AO3400) ◄PWM PA6   ┘   (D2 SS34 flyback ∥ fan)

 I²C1 (PB6/7) ─┬─ SHT40  (U3, 0x44)  board ambient temp + RH
               └─ TMP102 (U4, 0x48)  on P5 pigtail → battery/modem hot spot

 PB0 ─► Q4 (AO3400) ─► status LED (D1)        USB/USART1 headers (H2/H3; H1 SWD DROPPED 2026-06-25)

4. Sub-circuit detail (capture this exactly)

4.1 24 V input protection (light — the cabinet does the heavy lifting)

The cabinet already has the Phoenix SPD + breaker, so the board needs only:

  • Q10 reverse-polarity P-MOSFET in the 24 V high side. ⚠ Corrected (review Finding 1): AO3401A (±12 V Vgs) and SI2305 (−20 V Vds) are NOT rated for a 24 V rail and would fail. Use Vds ≥ −40 V, Vgs ≥ ±20 V — e.g. IRFR5305 (−55 V/±20 V, DPAK; verify LCSC stock); the proto can use a TO-220 IRF9540 (−100 V/±20 V). Add a gate→source Zener clamp DzG ≈ 15 V (A→Q10.G, K→Q10.S) with Rrp 10 k gate→GND: the gate sits ~9 V, Vgs ≈ −15 V (in rating, fully on). Buck input current is ~0.2 A — the part is sized by rating, not current.
  • D10 TVS SMBJ33A (33 V standoff) 24 V→GND, plus C10 100 µF/50 V electrolytic + C11 100 nF bulk/decoupling.

4.2 Dedicated fan 5 V buck (U2) — see caveat §0a

  • U2 = MP1584EN (SOP-8, 4.5–28 V in, up to 3 A) set to 5.0 V out.
    • FB divider for 5 V: R20 = 100 kΩ top, R21 = 19.1 kΩ bottom (Vout = 0.8 V·(1+R20/R21) ≈ 5.0 V — verify against the MP1584 datasheet FB = 0.8 V).
    • L2 = 10 µH (≥1 A sat), C22 = 22 µF in, C23 = 22 µF out, freewheel Schottky per datasheet (SS34), EN tied to 24V-rail-derived enable.
  • JP1: 0 Ω / solder-jumper. Open = fans on U2 (recommended). Closed = fans bridged to MAIN 5 V (only if SD-15B-05 is upsized; never both).
  • Keep U2's switching node small; keep this buck away from the GNSS antenna feed (RF cleanliness — see §8).

Simpler alternative if you'd rather not lay out a buck on the first spin: drop U2, close JP1, and upsize the external 5 V supply to a 5 V/5 A unit so the rail has true headroom. The board supports it; it's a BOM/jumper choice, not a respin.

4.3 RTK-stack high-side load switch (Q1 trio — proven, SMD)

Keeps the as-built topology (so firmware PA1 logic is unchanged) but in solid, sourceable SMD, plus a resettable fuse for the missing current limit:

 MAIN 5V ──[F1 PPTC 3A]──┬───────────────[R2 10k]──┐
                          │                          │
            Q1 AO3401A  Source                      Gate ── Q5 MMBT3904 Collector
            (P-MOS)       │                          │
                        Drain ──► SW_5V ─► P3 stack   Q5 Emitter ── GND
                                                       │
                PA1 ──[R1 1k]── Q5 Base ───────────────┘
  • PA1 HIGH → MMBT3904 on → P-FET gate low → SW_5V ON. PA1 LOW → R2 holds gate high → OFF (fail-safe at boot). Identical to as-built.
  • AO3401A is logic-level and switches fully from the 5 V gate swing (the old IRF9540N was not — a real latent bug we're removing).
  • F1 PPTC (3 A hold / ~6 A trip, e.g., MF-MSMF300) gives overcurrent protection without a hard-to-source eFuse, and cannot permanently latch a healthy unit out (it self-resets) — satisfies the "never black-hole" invariant.
  • C3 = 47 µF bulk on SW_5V (modem-burst reservoir).
  • Optional upgrade footprint U1: pin-compatible-ish current-limit load switch / eFuse (e.g., AP2553W6-7 SOT-23-6, EN active-high, FLAGn). Lay the footprint and the discrete; populate one. Verify LCSC stock at order; default = discrete.

4.4 Fan driver ×1 (low-side PWM + tach) — Q2

Single extraction fan:

 5V_FAN ──► Fan(+)                         Fan tach ──[R_t 1k]──┬──► PB10 (EXTI)
            Fan(−) ──┬──► Q2 Drain                             │
   D2 SS34 ∥ fan     │     (AO3400A, N-MOS)              [R 10k pull-up → 3V3]
   (cathode→5V_FAN)  │     Source ── GND
                  PWM PAx ─[Rg 100Ω]─ Gate ──[Rgs 100k → GND]
  • Q2 = AO3400A logic-level N-MOSFET (SOT-23): full-on from 3.3 V PWM, 5.7 A / 30 V — vast margin over a <0.5 A fan.
  • D2 = SS34 Schottky flyback across the fan (motor is inductive — protects the FET at PWM turn-off). Cathode to 5V_FAN, anode to drain.
  • Rg 100 Ω gate series (tames edges/EMI), Rgs 100 kΩ gate→GND pull-down = fans OFF until the MCU drives PWM (fail-safe; consistent with the ethos — if the MCU is dead the stack is also unpowered, so there's nothing to cool).
  • Tach: 3-wire fan's open-collector tach → 10 kΩ pull-up to 3.3 V + 1 kΩ series into the EXTI pin. 2 pulses/rev → MCU computes RPM and flags a stalled/failed fan. Use 3-wire (or 4-wire) fans so tach exists. PWM is on the ground leg, so on a 3-wire fan the tach is valid only while PWM is high — firmware samples RPM during a brief 100 % window (§7). (4-wire fans avoid this entirely; if you can source 5 V 4-wire, drive their PWM pin from PAx via a 2N7002 open-drain and leave power always-on — cleaner tach. 5 V 4-wire fans are rarer, hence 3-wire default.)

4.5 Status LED (unchanged topology, SMD)

3V3 ─[R3 1k]─►|D1 LED|─► Q4 (AO3400) drain; source→GND; PB0 ─ gate, [10k → GND] pull-down. (Resolves the "1.5 kΩ ????" — it was this series resistor; 1 kΩ is the clean value for a 3.3 V drive.)

4.6 Sense conditioning (filtered; protect the ignition input)

Net Divider RC filter Protection
PA0 BAT (3.0–4.2 V) R5 10k / R6 10k (÷2) C5 100 nF —
PA4 5V (≈5 V) R7 10k / R8 10k (÷2) C7 100 nF —
PA5 IGN (from DFR1015) none — direct C9 100 nF Corrected (Finding 2): Rig 100 Ω series + D5 BAT54 clamp to 3V3, NO ÷2. PA5 is a digital input (INPUT_PULLDOWN); the DFR1015 logic level reaches PA5 undivided (a ÷2 would drop it below VIH). Internal pulldown = LOW when ignition off; clamp caps ≤3.3 V.
ADC stays ≤3.3 V with margin (verified in firmware-review). Firmware
DIVIDER_RATIO = 2.0 matches the 10k/10k legs.

5. Temperature + humidity sensing (I²C1)

Ref Part Addr Where Why
U3 SHT40-AD1B-R2 (DFN-4) 0x44 on-board, near an air-path edge board-ambient temp + RH (RH flags condensation risk — IP/coastal)
U4 TMP102AIDRLR (SOT-563) 0x48 (ADD0→GND) on P5 pigtail to the 18650/modem the actual heat casualty spot — the data the thermal RCA needs
  • One bus, 4.7 kΩ pull-ups (R30/R31) on SCL/SDA to 3.3 V. Both 3.3 V parts.
  • 100 nF decoupling each. SHT40 wants a small keep-out/slot so it reads air, not board.
  • Firmware reads all three temps (SHT40, TMP102, plus the existing MCU-internal) → triangulated thermal picture and the fan-control input (§7).

6. Connectors & headers (all keyed/locking)

Ref Connector Pins Net
P1 GX16-5 (HBOX↔cabinet, keep) 5 24V_IN, GND, IGN, (spare ×2)
P2 Molex Micro-Fit 3.0, 2-pos 2 5V_IN from SD-15B-05, GND
P3 JST-XH 4-pos 4 SW_5V, GND, GNSS_TX(PA2), GNSS_RX(PA3) → simpleRTK2B
P4 JST-XH 2-pos 2 BAT+ (to PA0 divider), GND (18650/PowerBoost)
P5 JST-XH 4-pos 4 3V3, GND, SDA, SCL → TMP102 probe pigtail
P6 JST-XH 4-pos 4 5V_FAN, Fan−(PWM), GND, Tach → fan
P8 JST-XH 2-pos 2 EXT_LED+, EXT_LED− (panel LED)
H1 1×4 0.1″ — DROPPED 2026-06-25 4 SWD: 3V3, SWDIO, SWCLK, GND — optional DNP 4-pad only (flash/debug via Blackpill USB-C)
H2 (Blackpill micro-USB) — STREAM log capture / flashing
H3 1×3 0.1″ DNP 3 reserve USART1: PA9, PA10, GND (future $PHLG)
— 2× 2×20 female headers 40 Blackpill seats here

Pin-1 / keying: silkscreen pin-1 arrows + the GX16 keyway; JST-XH is already keyed. Label every connector net on silk (DFM/serviceability requirement).


7. Firmware deltas (spec only — bench-test before any field flash)

The v2.1 .ino changes are small and additive (the ethos: bench first; the sandbox can't build STM32). New globals + functions, no state-machine surgery.

  1. Pins: add PIN_FAN_PWM PA6, PIN_FAN_TACH PB10 (PA7/PB12 stay spare); init TIM3 CH1 PWM at 25 kHz; attach an EXTI counter on the tach pin.
  2. I²C temps: Wire.begin() on PB6/PB7; read SHT40 (0x44, temp+RH) and TMP102 (0x48). Add tAirC, rhPct, tBatC to telemetry. Keep MCU-internal as cross-check.
  3. Closed-loop fan curve (input = max(tAirC, tBatC)):
    • < 45 °C → fans off (0 % — minimise vent hours / dust ingress).
    • 45–70 °C → linear 30 → 100 % PWM.
    • ≥ 70 °C → 100 %.
    • Hysteresis 3 °C on the off→on edge (no chatter). This replaces nothing — the existing THERM_WARN_C 75 derate-to-30 s still stands as the last resort.
  4. Tach fault: once/30 s, command a fan to 100 % for ~300 ms, count tach edges, compute RPM. 0 RPM while commanded > 0 → latch FAN_FAULT, log EVT, raise it in telemetry. A dead fan in a hot box must be visible, not silent.
  5. Telemetry (on-unit only in v3): extend the v2.1 TLM record with tair,rh,tbat,fan_rpm,fan_pwm,fan_fault, captured to the USB STREAM log. These are the same fields a future $PHLG-to-server sentence would carry — but v3 does NOT push them live to the server (no UART relay; see §2a + decision row 5). Live telemetry is gated on the bench experiment below.
  6. IWDG-safe: fan/tach/I²C work is non-blocking; keep petting the dog. I²C read uses a short timeout so a stuck sensor can't hang the loop.

Pin map and control law live here; implemented in v2.3 (blackpillrtkcode_v2.ino) — closed-loop fan + I²C SHT40/TMP102 + tach fault, with MCU-temp fallback. Bench-test before any field flash (the sandbox can't build STM32; the logic was host-verified).

7a. The one bench experiment that decides live telemetry (no PCB change)

✅ RESULT — 2026-06-22: PASS (no extra hardware needed). Enabled $PUBX (a u-blox proprietary $P… talker — same class + checksum format as $PHLG) on the F9P UART2 and watched the server udp/5010 capture: $PUBX,00,… arrives end-to-end, intact, alongside GGA/RMC. → The 4G NTRIP Master forwards proprietary $P… sentences, so $PHLG health-in-server is confirmed viable. No XBee-breakout test needed. Remaining work = the UART2 relay (interpose the watchdog to inject $PHLG) + backend parser — a deliberate later board, still out of v3 scope.

Incidental (flagged for GNSS follow-up): the same capture caught two live units — bench H0014 (Querétaro) at SPS (GGA quality 1), RSSI −93, and field H0017 (Veracruz/ICAVE) at DGPS (quality 2, RMC mode D, diff base id 0133), RSSI −51. Per Leo the bench is in a basement (poor sky + weak cellular) — which alone explains the bench SPS, since RTK fix needs open sky (carrier-phase) regardless of corrections/config. But note H0017 has good sky+signal and still only reaches DGPS, not RTK (4/5) → the corrections pipeline (free rtk2go caster + RAM-only F9P config) is a separate ceiling from antenna placement. One open-sky test with a proper caster + FLASH-saved config separates the two. (Reinforces the v2.1 SPS-thrash guard: a healthy basement/field unit may legitimately sit at SPS/DGPS — do not power-cycle it.)

Settles "does the 4G NTRIP Master forward a proprietary $P… sentence?" by isolating the modem — the F9P is not involved, so there's no bus collision:

  1. Remove the 4G NTRIP Master from the F9P XBee socket; mount it on a bench/XBee adapter with 3.3 V power, the SIM, and the LTE antenna.
  2. Wire Blackpill PA9 (USART1 TX) → modem DIN (the TX2/F9P-UART2-TX net in the socket) and modem DOUT → Blackpill PA10 (RX) or a USB-UART so a PC can watch it.
  3. Match the modem's UART baud (ArduSimple default 115200, 3.3 V). Let it register.
  4. Emit $PHLG,2.1,RUN,LIMP,1,12,34192,4.01,5.02,63,71,2,1,420,IWDG*CS\r\n and watch the server tcpdump.
    • Appears → modem forwards proprietary sentences → $PHLG is viable → then plan a relay-capable board.
    • Doesn't → modem whitelists talkers → fall back to a $GPTXT,HLT,… subtype (special-cased by field 1 so it never collides with the cell-id parse).

Either way, v3 ships unchanged — this experiment only informs a later decision.


8. Layout, stackup & DFM (for a relative beginner — the rules that matter)

  • Stackup: 2-layer is acceptable for this mostly-DC/low-speed board and is cheaper; 4-layer (GND + power inner planes) is better for the GNSS RF and the buck noise — recommended if budget allows. Either way: solid ground pour on a full layer.
  • Star-ground the power: fan return currents (PWM, pulsed) and the modem-burst return must not share a thin trace with the ADC/sensor grounds. Bring power grounds to the pour at one stitching region; keep sensor/MCU ground quiet.
  • Buck (U2) discipline: tiny switch-node copper, input cap right at the IC, ground the cap to the pour with vias. Keep U2 and the fan-PWM traces away from the GNSS antenna pigtail / P3 — switcher harmonics degrade the ZED-F9P front-end (= the watchdog's own "link health" signal).
  • Trace widths (1 oz Cu): 24 V_IN and 5 V rails ≥ 0.5 mm (fan + stack current); SW_5V to P3 ≥ 0.8 mm (modem bursts); signals 0.25 mm fine.
  • Thermal: copper pour + vias under Q1/Q10/U2 tabs. Mounting holes positioned to let the board bolt to the cabinet metal plate (conduction path, hardware brief §2b).
  • Creepage: nothing >24 V here, so standard clearances are ample; still keep the 24 V input section tidy.
  • Conformal coat after assembly (mask connectors/headers/SHT40 slot) — humidity + vibration joint stability.
  • JLC specifics: 0603 passives (hand-reworkable and machine-placeable), SOT-23 actives, 1.6 mm FR-4, HASL or ENIG. Add fiducials if you want tight placement. Put the JLC order number on silk (free, helps reorders).

9. Bring-up & test plan (prototype first)

  1. Bare-board power: 24 V in, confirm 5V_FAN = 5.0 V, reverse-polarity FET blocks a flipped input, TVS not hot.
  2. Load switch: toggle PA1 → SW_5V on/off; confirm OFF at reset; PPTC holds the measured stack current, trips on a deliberate short.
  3. Fan: ramp PA6 PWM 0→100 %, scope the gate + fan node, confirm flyback, read tach RPM vs PWM; pull the fan → confirm FAN_FAULT.
  4. Sensors: I²C scan finds 0x44 + 0x48; heat the TMP102 probe → fan ramps per curve.
  5. Power budget (the §0a check): with JP1 open, scope MAIN 5 V during an LTE burst and a fan ramp simultaneously — confirm the stack rail no longer sags. Repeat with JP1 closed to demonstrate the coupling you're avoiding.
  6. Full stack: mount Blackpill + F9P + 4G, run v2.1+fan firmware, watch the STREAM log for temps/RPM, confirm RTK recovery behaviour is unchanged.
  7. Only then: pilot 2–3 boards in real cabinets before the fleet (mirrors the August-30-unit ramp).

10. Open questions / decisions

  • IP rating target with ICAVE: IP67 (no vents → conduction only) vs IP54/55 (filtered louvers + fans). Determines whether the fan section is populated.
  • Fan choice (×1): 5 V 3-wire (tach), size (40/50/60 mm), + a filtered passive inlet so the single extraction fan can pull air through. Measured static-pressure need through the chosen duct/filter. Source 2–3 candidates.
  • U2 buck vs upsize supply (§4.2): lay the buck (default) or go 5 V/5 A external + JP1-closed. Recommend laying the buck for rail isolation.
  • Battery — RESOLVED (Finding 3): default = dropped (vehicle-powered only) — removes the worst thermal/safety liability and makes the connection list correct as-is (MAIN5V = SD-15B-05 powers the MCU; PA4 senses the vehicle-side 5 V; P4 = sense-only, battery DNP). If ICAVE needs parked tracking, fit LiFePO4/supercap on P4 and move the PA4 sense tap to the SD-15B-05/P2 (vehicle) node, not the battery-backed rail.
  • Confirm the DFR1015 stays external or folds on-board → RESOLVED 2026-06-24: folds ON-BOARD. GX16 pin 3 now carries raw machine ignition (12–24 V) into the on-board DFR1015 → Rig 100 Ω → D5 BAT54 clamp 3V3 → PA5 (digital, no divider).
  • Load switch: discrete (default, sourceable) vs eFuse U1 — verify AP2553 LCSC stock at order; otherwise ship discrete.